Qt编程游戏开发实践笔记——实现多方向键共同控制移动

本文介绍了如何在QT环境下开发一个STG游戏时,通过使用键盘控制物体在2D平面上自由移动。作者提出了一种解决方案,通过创建MoveVector类来管理移动向量,结合按键事件处理,实现了包括斜方向在内的多方向移动。在更新位置时,通过单位向量和速度调整确保了物体的自由移动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本人正在尝试用QT开发一个STG游戏,遇到了一个难题:如何才能使用键盘控制物体在2D平面上自由移动?遍查网上的文档和博客,大多只能实现物体上下左右移动,达不到我需要的标准(比如斜方向移动)。最近终于想出了一个解决方案。(最终效果在文章最后)

假如我声明定义了一个自机(可操作角色)如下,并创建了一个对象作为主界面类的子对象:

//自机类
//声明
#include <QPixmap>
#include <QRect>

class Hero
{
public:
    Hero();
    void setPosition(int x,int y);//设置自机的位置
    QPixmap Plane;
    int X;
    int Y;
    QRect PlaneRect;
};

//定义略

如果需要键盘控制,需要重写游戏主界面类(我这里叫Widget)的keypressevent事件。显然,在事件中使用if...else if...else...这样的结构是绝对达不到我的标准的(因为这样只能一次识别一个键)。

为了解决问题,我增加了一个“移动向量”,声明定义了一个MoveVector类:

//声明
#include <QtMath>
#include <QString>

class MoveVector
{
public:
    MoveVector();
    void toZeroVector();
    void GenerateVector();
    void AddVx(qreal deltax);
    void AddVy(qreal deltay);
    QString StateofMoveKeys[5];//记录键盘相关键的状态
    qreal Vx;
    qreal Vy;
};
//定义
#include "movevector.h"

MoveVector::MoveVector()
{
    for(int i=0;i<5;i++)
    {
        this->StateofMoveKeys[i]=QString("unpressed");
    }
    this->toZeroVector();
}

void MoveVector::toZeroVector()//归零向量
{
    this->Vx=0;
    this->Vy=0;
}

void MoveVector::GenerateVector()//根据按键状态生成单位向量
{
    this->toZeroVector();
    if(this->StateofMoveKeys[0]==QString("pressed"))//左
    {
        this->AddVx(-1.0);
    }
    if(this->StateofMoveKeys[1]==QString("pressed"))//上
    {
        this->AddVy(-1.0);
    }
    if(this->StateofMoveKeys[2]==QString("pressed"))//下
    {
        this->AddVy(1.0);
    }
    if(this->StateofMoveKeys[3]==QString("pressed"))//右
    {
        this->AddVx(1.0);
    }
    qreal length=qSqrt(this->Vx*this->Vx+this->Vy*this->Vy);
    if(length!=qreal(0.0))//向量归一化
    {
        this->Vx=this->Vx/length;
        this->Vy=this->Vy/length;
    }
}

void MoveVector::AddVx(qreal deltax)
{
    this->Vx+=deltax;
}

void MoveVector::AddVy(qreal deltay)
{
    this->Vy+=deltay;
}

随后在主界面类Widget里添加MoveVector类子对象,最终声明如下:

//声明,include部分略去
class Widget : public QWidget
{
    Q_OBJECT

public:    
    //无关函数略去
    void updateAllPosition();//更新各元素位置
    void paintEvent(QPaintEvent*event);//重绘场景各元素,Update()时调用
    void keyPressEvent(QKeyEvent *event);//按键事件
    void keyReleaseEvent(QKeyEvent *event);//松键事件
    QTimer my_Timer;//计时器,用于游戏每10ms进行一次数据的更新处理与重新绘图
    Map my_map;//背景场景,本文未用到
    Hero my_hero;//自机
    MoveVector my_vector;//自机移动向量
};

再将按键事件与松键事件重写如下:

//按键事件
void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->key()==Qt::Key_Left)
    {
        this->my_vector.StateofMoveKeys[0]=QString("pressed");
    }
    if(event->key()==Qt::Key_Right)
    {
        this->my_vector.StateofMoveKeys[3]=QString("pressed");
    }
    if(event->key()==Qt::Key_Up)
    {
        this->my_vector.StateofMoveKeys[1]=QString("pressed");
    }
    if(event->key()==Qt::Key_Down)
    {
        this->my_vector.StateofMoveKeys[2]=QString("pressed");
    }
    if(event->key()==Qt::Key_Shift)//低速移动键,参照東方project机制
    {
        this->my_vector.StateofMoveKeys[4]=QString("pressed");
    }
}

//松键事件
void Widget::keyReleaseEvent(QKeyEvent *event)
{
    if(event->key()==Qt::Key_Left)
    {
        this->my_vector.StateofMoveKeys[0]=QString("unpressed");
    }
    if(event->key()==Qt::Key_Right)
    {
        this->my_vector.StateofMoveKeys[3]=QString("unpressed");
    }
    if(event->key()==Qt::Key_Up)
    {
        this->my_vector.StateofMoveKeys[1]=QString("unpressed");
    }
    if(event->key()==Qt::Key_Down)
    {
        this->my_vector.StateofMoveKeys[2]=QString("unpressed");
    }
    if(event->key()==Qt::Key_Shift)//低速移动键,参照東方project机制
    {
        this->my_vector.StateofMoveKeys[4]=QString("unpressed");
    }
}

在updateAllPosition()方法中进行自机位置的更新:

void Widget::updateAllPosition()
{
    //已略去与自机位置更新无关的部分

    this->my_vector.GenerateVector();
    int isShiftPressed=this->my_vector.StateofMoveKeys[4]==QString("pressed")?1:0;
    int deltax=qFloor(this->my_vector.Vx*100000.0)/(10000+isShiftPressed*30000);
    int deltay=qFloor(this->my_vector.Vy()*100000.0)/(10000+isShiftPressed*30000);
    this->my_hero.setPosition(this->my_hero.X+deltax,this->my_hero.Y+deltay);
}

(注:此处由于设置位置时只能使用int,故我把单位向量放大了100000倍再转换为int,以尽可能减小方向误差。实测效果尚可,但如果有人想出了更好的处理方案希望可以告诉我。)

至此就可以实现使用多方向键控制物体自由移动了。效果如下:

(背景的移动是之前就已实现的,与本文内容无关)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值