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

本人正在尝试用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,以尽可能减小方向误差。实测效果尚可,但如果有人想出了更好的处理方案希望可以告诉我。)

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

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

  • 11
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,关于QT绘图系统,我可以为您提供一些基本的介绍和使用方法。 QT提供了一套强大的绘图系统,可以用来绘制各种图形、图表、文本、图像等等。QT的绘图系统主要由以下几个类组成: 1. QPainter:绘图类,用于绘制各种图形、图像、文本等。 2. QPen:画笔类,用于设置绘图的线条样式、颜色、粗细等。 3. QBrush:画刷类,用于设置绘图的填充样式、颜色等。 4. QFont:字体类,用于设置绘图的字体、大小、样式等。 5. QRect和QRectF:矩形类,用于表示矩形区域的位置和大小。 6. QImage:图像类,用于表示位图图像。 使用QT绘图系统进行绘图主要有两种方式,一种是在QWidget或QGraphicsView等控件的paintEvent事件中进行绘制,另一种是创建QPixmap或QImage等图像对象,然后使用QPainter在图像上进行绘制。 下面是一个简单的示例代码,演示了如何在QWidget中使用QT绘图系统进行绘制: ```cpp void MyWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); // 设置画笔和画刷 QPen pen(Qt::red, 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); QBrush brush(Qt::yellow, Qt::SolidPattern); painter.setPen(pen); painter.setBrush(brush); // 绘制矩形和椭圆 QRect rect(100, 100, 200, 100); painter.drawRect(rect); painter.drawEllipse(rect); // 绘制文本 QFont font("Arial", 20); painter.setFont(font); painter.drawText(rect, Qt::AlignCenter, "Hello, QT!"); } ``` 在这个示例代码中,我们在QWidget的paintEvent事件中创建了一个QPainter对象,然后设置了画笔和画刷,接着使用QRect定义了一个矩形区域,并使用drawRect和drawEllipse方法在该区域上绘制了矩形和椭圆。最后,使用setFont和drawText方法在矩形区域中央绘制了一段文本。 当然,QT绘图系统的功能远不止于此,您可以根据需要使用更多的API进行绘制。希望这个简单的介绍可以帮助您更好地了解和使用QT的绘图系统。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值