一个小程序,让你知道Qt一次能支持按下多少个键(二)
接上次的日志。
上次演示程序表明,Qt可以支持多个按键同时按下,这可以激起我们探索按键在游戏中的作用。知道吗?操作感是大多数游戏成功的因素之一,不谈那些网游,那些街机游戏更是将操作感视为其生命线。Qt要成为一款成功的游戏平台,这些因素肯定是不能忽略的。这会儿我将再次演示我们究竟是如何将Qt按键事件来适配我们需要的游戏按键效果的。
程序源代码下载地址:这里
上次我们使用了QList<int>来保存所有按下键的状态,其实啊,那么多按键,我们没有必要全部都利用,除非是那些网络游戏。目前,我觉得将键盘中的某些键定义为游戏中可以操作的键就行了。比如说可以使用键盘的“上、下、左、右”键或者“WSAD”来模拟上下左右键,让zxc键来表示CBA键。让QList<int>来保存少数几个按键的信息,实在是杀鸡用牛刀了,我们可以只使用一个unsignedlong的大小就可以保存32个按键的信息——你应该猜到了,0表示按键弹出,1表示按键按下。
想法倒是不错,但是如何实施呢?这里需要解决的问题有记录下按键的状态和读取按键状态的信息。怎样知道按键按下?使用按位与操作就可以了。怎么样?很简单吧,我们试试。
下面是Widget.h文件,注意其中的SaveKeyPressed()、SaveKeyReleased()和KeyPressed()函数。
#ifndef WIDGET_H #define WIDGET_H #include <QString> #include <QList> #include <QWidget> /*---------------------------------------------------------------------------*/ class Widget: public QWidget { Q_OBJECT public: Widget( void ); ~Widget( void ); protected: void paintEvent( QPaintEvent* event ); void keyPressEvent( QKeyEvent* event ); void keyReleaseEvent( QKeyEvent* event ); private: void SetShowText( void ); inline void SaveKeyPressed( int key ) { m_PressedKeys |= ( 1 << key ); } inline void SaveKeyReleased( int key ) { m_PressedKeys &= ~( 1 << key ); } inline bool KeyPressed( int key ) { return m_PressedKeys & ( 1 << key ); } enum Interested_Keys { Key_Up = 1, Key_Down, Key_Left, Key_Right }; QString m_Text; QString m_ShowText; quint32 m_PressedKeys; }; /*---------------------------------------------------------------------------*/ #endif // WIDGET_H
在上面我们定义了Interested_Keys枚举。其实枚举的好处还是很大的,它不产生编译单元,枚举的本质是整型数,可以和其它的数字进行加减乘除等等。最好的作用还在于可以让我们通过字面意思了解枚举常量的意思。
下面是Widget.cpp文件,我们捕获keyPressEvent()和keyReleaseEvent()函数来记录按键的变化情况。最后我们使用SetShowText()函数来告诉我们究竟是什么按键已经被按下了。
#include <QPoint> #include <QKeyEvent> #include <QPainter> #include "Widget.h" Widget::Widget( void ): QWidget( 0 ), m_PressedKeys( 0 ) { // 设置窗口的一些属性 setFixedSize( 640, 360 ); setWindowTitle( tr( "KeyTest" ) ); // 设置文字 m_Text = tr( "Try to press key.\n" ); } /*---------------------------------------------------------------------------*/ Widget::~Widget( void ) { } /*---------------------------------------------------------------------------*/ void Widget::paintEvent( QPaintEvent* event ) { Q_UNUSED( event ) QPainter painter( this ); painter.drawText( QPoint( 32, 32 ), m_Text ); painter.drawText( QPoint( 32, 64 ), m_ShowText ); } /*---------------------------------------------------------------------------*/ void Widget::keyPressEvent( QKeyEvent* event ) { switch ( event->key( ) ) { case Qt::Key_Up: SaveKeyPressed( Key_Up ); break; case Qt::Key_Down: SaveKeyPressed( Key_Down ); break; case Qt::Key_Left: SaveKeyPressed( Key_Left ); break; case Qt::Key_Right: SaveKeyPressed( Key_Right ); break; default: break; } SetShowText( ); update( ); } /*---------------------------------------------------------------------------*/ void Widget::keyReleaseEvent( QKeyEvent* event ) { switch ( event->key( ) ) { case Qt::Key_Up: SaveKeyReleased( Key_Up ); break; case Qt::Key_Down: SaveKeyReleased( Key_Down ); break; case Qt::Key_Left: SaveKeyReleased( Key_Left ); break; case Qt::Key_Right: SaveKeyReleased( Key_Right ); break; default: break; } SetShowText( ); update( ); } /*---------------------------------------------------------------------------*/ void Widget::SetShowText( void ) { m_ShowText = tr( "Pressed Keys: " ); if ( KeyPressed( Key_Up ) ) m_ShowText += tr( "Up " ); if ( KeyPressed( Key_Down ) ) m_ShowText += tr( "Down " ); if ( KeyPressed( Key_Left ) ) m_ShowText += tr( "Left " ); if ( KeyPressed( Key_Right ) ) m_ShowText += tr( "Right " ); }
main.cpp和以前的内容没有什么区别,就一笔带过吧。
#include <QApplication> #include <QTranslator> #include "Widget.h" int main( int argc, char** argv ) { QApplication app( argc, argv ); QTranslator trans; trans.load( ":/zh_CN.qm" ); app.installTranslator( &trans ); Widget w; w.show( ); return app.exec( ); }
好了,测试一下效果吧。
经过测试,似乎一起只能按下上下左右中的三个键。这个程序和上篇日志中的程序最大不同在于仅用了一个unsignedlong的空间就储存了我们感兴趣的按键的状态,并且借助位运算的威力,迅速准确地让我们判断按键所处的状态。