Qt 在UI界面通过键盘控制飞机上下左右移动

本项目资源文件借鉴了此篇文章内容,https://blog.youkuaiyun.com/weixin_42756970/article/details/108975622python版本的雷电小游戏。


前言

通过Qt做一个UI界面控制飞机上下左右移动的小实验,通过按下WSAD四个键盘按键,实现飞机的移动,并且在飞机向上移动的状态时,添加飞机尾焰的视觉效果。
本实验的主要思路是通过在GUI界面类Widget类中,重写keyPressEvent、keyReleaseEvent进行相关的判断操作,并且重写paintEvent,设定一个定时器,到设定的时间时,不断地调用update()函数进行图形界面的重绘。


效果

实验效果如下图所示,通过键盘WSAD来控制红色小飞机的移动。
通过Qt做一个UI界面控制飞机上下左右移动的小实验,通过按下WSAD四个键盘按键,实现飞机的移动,并且在飞机向上移动的状态时,添加飞机尾焰的视觉效果。


资源下载

本次实验全部代码请至https://download.youkuaiyun.com/download/wang_chao118/86427796下载。


核心代码

分开定义飞机类heroPlane以及GUI界面类Widget。

heroplane.h

#ifndef HEROPLANE_H
#define HEROPLANE_H

#include <QPixmap>

class heroPlane
{
public:
    heroPlane();
	//飞机原始图片
    QPixmap plane_pic;
    //向左移动时的飞机图片
    QPixmap plane_pic_moveleft;
    //向右移动时的飞机图片
    QPixmap plane_pic_moveright;
    //尾焰图片
    QPixmap air;
	//飞机当前坐标
    int m_X;
    int m_Y;
};

#endif // HEROPLANE_H

heroplane.cpp

#include "heroplane.h"
#include "config.h"

heroPlane::heroPlane()
{	
	//加载飞机图片
    plane_pic.load(":/hero.png");
    plane_pic_moveleft = plane_pic.copy(198,0,318-255,87);
    plane_pic_moveright = plane_pic.copy(53,0,318-255,87);
    plane_pic = plane_pic.copy(120, 0, 318 - 242, 87);

    air.load(":/air.png");
    air = air.copy(80, 0, 55, 65);

    //初始化坐标
    m_X = GAME_WIDTH * 0.5 - plane_pic.width() *0.5;
    m_Y = GAME_HEIGHT - plane_pic.height();
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QKeyEvent>
#include <QDebug>
#include <QPainter>
#include <QTimer>
#include "heroplane.h"
#include "config.h"

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    void keyPressEvent(QKeyEvent * event);
    void keyReleaseEvent(QKeyEvent *event);
    void paintEvent(QPaintEvent *event);
    void judgekey();

private:
    Ui::Widget *ui;
    heroPlane *hero;
    QTimer *timer;
	//按键标志位,用于判断是否有按键按下
    bool keypressflag;
    //按键种类标志,用于判断是WSAD中的哪个
    int keyflag;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setFixedSize(GAME_WIDTH, GAME_HEIGHT);
    keypressflag = false;
    //实例化一个飞机对象
    hero = new heroPlane;
	//设置重绘速率,此处为每5ms重绘一次界面
    timer = new QTimer(this);
    //每次到时间就调用update()函数,update()函数将调用paintEvent()
    connect(timer,SIGNAL(timeout()),this,SLOT(update()));
    timer->start(5);

}

Widget::~Widget()
{
    delete ui;
}

void Widget::keyPressEvent(QKeyEvent *event)
{
    qDebug()<<event->key();
	//判断按键种类
    switch(event->key())
    {

    case Qt::Key_W:
    	//有按键按下即将按键标志位置1
        keypressflag = true;
        //设置按键种类标志位
        keyflag = 1;
        return;

    case Qt::Key_S:
        keypressflag = true;
        keyflag = 2;
        return;

    case Qt::Key_A:
        keypressflag = true;
        keyflag = 3;
        return;

    case Qt::Key_D:
        keypressflag = true;
        keyflag = 4;
        return;
    }
}

void Widget::keyReleaseEvent(QKeyEvent *event)
{
    switch(event->key())
    {
    //有按键松开时即将按键标志位置0
    case Qt::Key_W:
        keypressflag = false;
        return;

    case Qt::Key_S:
        keypressflag = false;
        return;

    case Qt::Key_A:
        keypressflag = false;
        return;

    case Qt::Key_D:
        keypressflag = false;
        return;
    }
}

//界面绘制事件
void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    if(keypressflag)
    {	
    //判断是哪个键按下了,绘制对应的图片
        judgekey();
    }
    else
    {
        QPainter painter(this);
        painter.drawPixmap(hero->m_X,hero->m_Y,hero->plane_pic);
    }
//    qDebug()<<"keypressflag: "<<keypressflag;
}

void Widget::judgekey()
{
    QPainter painter(this);
    switch(keyflag)
    {
    case 1:
    //设置飞机的坐标值,绘制向上移动的飞机
        hero->m_Y = (hero->m_Y - 1 < 0) ? hero->m_Y : hero->m_Y - 1;
        painter.drawPixmap(hero->m_X,hero->m_Y,hero->plane_pic);
        //绘制尾焰图形
        painter.drawPixmap(hero->m_X+8,hero->m_Y + 80,hero->air);
        return;

    case 2:
        hero->m_Y = (hero->m_Y + 1 + hero->plane_pic.height() > GAME_HEIGHT) ? hero->m_Y : hero->m_Y + 1;
        painter.drawPixmap(hero->m_X,hero->m_Y,hero->plane_pic);
        return;

    case 3:
        hero->m_X = (hero->m_X - 1 < 0) ? hero->m_X : hero->m_X - 1;
        painter.drawPixmap(hero->m_X,hero->m_Y,hero->plane_pic_moveleft);
        return;

    case 4:
        hero->m_X = (hero->m_X + 1 + hero->plane_pic.width() > GAME_WIDTH) ? hero->m_X : hero->m_X + 1;
        painter.drawPixmap(hero->m_X,hero->m_Y,hero->plane_pic_moveright);
        return;
    }
}

资源下载

本次实验全部代码请至https://download.youkuaiyun.com/download/wang_chao118/86427796下载。

遗留问题

Qt按键事件中的相应问题:
(1)Qt按键在长按状态下会反复调用keyPressEvent以及keyReleaseEvent,且如果一直在长按状态下时,第一次的keyPressEvent与第二次的keyPressEvent之间有一定间隔时间,导致的现象就是,如果直接在keyPressEvent函数中直接设定飞机的位置的话,将会产生一种“停顿”的现象,为了避免这种现象,本案例在Widget类中引入了一个keypressflag来判断按键是否按下,只要有按键按下就开始重绘界面,直到有keyReleaseEvent后停止重绘界面,解决了“停顿”现象。
(2)本案例稍有缺陷,如果同时按下多个按键,即同时按下W及A按键、按下多个按键,然后再松开某个按键时,飞机的运行状态不明确,或产生不运动的现象。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_chao118

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值