【Qt OpenGL教程】21:线、反走样、正投影和简单的声音

这篇教程介绍了如何在Qt OpenGL环境下创建一个2D游戏,涉及线的绘制、反走样、正投影以及简单的音效。教程中通过实例展示了如何实现游戏逻辑,包括游戏对象的位置更新、碰撞检测、生命值管理等,最终构建了一个名为'GRID CRAZY'的游戏。此外,还讲解了反走样技术在光栅图形显示器上的应用,以消除锯齿状线段。

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

第21课:线、反走样、正投影和简单的声音 (参照NeHe)

这次教程中,我们将介绍线、反走样、正投影和简单的声音,这是第一个大教程,希望这一课的东西大家能够喜欢(NeHe原文中有介绍计时器,但是Qt已经为我们封装好了计时器,所以这次教程中我省略了这部分,有兴趣了解VC中设置计时器的请点击这里)。

在这一课里,我们将学会绘制直接,使用反走样,正投影,基本的音效和一个简单的游戏逻辑,希望这里的东西可以让你高兴,毕竟我们会完成一个游戏!在这一课的结尾,你将获得一个叫“GRID CRAZY”的游戏,你的任务是走完每一段直线。这个程序有了一个基本游戏的一切要素:关卡,生命值,声明和一个游戏道具。


程序运行时效果如下:



下面进入教程:


我们这次将在第01课代码的基础上修改代码,这次是个大程序,我们一一解释新的内容和游戏逻辑,希望大家能理解和喜欢这第一个openGL游戏(虽然只是2D游戏)。首先打开项目文件(.pro文件)和myglwidget.h文件,将两个文件内容更改如下:

TARGET = QtOpenGL21
TEMPLATE = app

HEADERS += \
    myglwidget.h

SOURCES += \
    myglwidget.cpp \
    main.cpp

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

QT       += opengl \
            multimedia

#ifndef MYGLWIDGET_H
#define MYGLWIDGET_H

#include <QWidget>
#include <QGLWidget>

class QSound;
class MyGLWidget : public QGLWidget
{
    Q_OBJECT
public:
    explicit MyGLWidget(QWidget *parent = 0);
    ~MyGLWidget();

protected:
    //对3个纯虚函数的重定义
    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

    void keyPressEvent(QKeyEvent *event);           //处理键盘按下事件

private:
    void resetObjects();                            //重置玩家和敌人信息
    void updateData();                              //更新下一帧数据
    void buildFont();                               //创建字体
    void killFont();                                //删除显示列表
    //输出字符串
    void glPrint(GLuint x, GLuint y, int set, const char *fmt, ...);

private:
    bool fullscreen;                                //是否全屏显示
    bool m_Vline[11][10];                           //保存垂直方向的11根线条中,每根线条中的10段是否被走过
    bool m_Hline[10][11];                           //保存水平方向的11根线条中,每根线条中的10段是否被走过
    bool m_Filled;                                  //网格是否被填满
    bool m_Gameover;                                //游戏是否结束
    bool m_Anti;                                    //是否反走样

    int m_Delay;                                    //敌人的暂停时间
    int m_Adjust;                                   //调整速度
    int m_Lives;                                    //玩家的生命
    int m_Level;                                    //内部的游戏难度等级
    int m_Level2;                                   //显示的游戏难度等级
    int m_Stage;                                    //游戏的关卡
    static const int s_Steps[6];                    //用来调节显示的速度

    struct object                                   //记录游戏中的对象
    {
        int fx, fy;                                 //使移动变得平滑
        int x, y;                                   //当前游戏者的位置
        float spin;                                 //旋转角度
    };
    object m_Player;                                //玩家信息
    object m_Enemy[9];                              //最多9个敌人
    object m_Hourglass;                             //宝物沙漏信息

    QString m_FileName[2];                          //图片的路径及文件名
    GLuint m_Texture[2];                            //储存两个纹理
    GLuint m_Base;                                  //字符显示列表的开始值
    QSound *m_Sound;                                //保存吃到宝物后的计时音乐
};

#endif // MYGLWIDGET_H

项目文件中,我们增加multimedia部分,这使得我们能够使用QSound等媒体播放对象。

myglwidget.h文件中,首先我们增加了2个布尔变量数组m_Vline和m_Hline,用于记录垂直方向和水平方向各110段线段是否走过。继续是3个布尔变量,当网格被填满时,m_Filled被设置为true而反之则为false;m_Gameover的作用易见,当它的值为true时,游戏结束;m_Anti指出抗锯齿功能是否打开,当设置为true时,该功能是打开着的。

接下来是5个整形变量和1个static const 整形数组,m_Delay用来减缓敌人的行动,其实就是当m_Delay小于某个值时,敌人不能移动(由于画面刷新很快,m_Delay变化也快,你是看不出敌人有很小一段时间没动的)。m_Adjust用来控制玩家和敌人移动的速度,其实就是控制玩家和敌人每一步能走多远,我们通过和下面的s_Steps[]数组配合一起完成这一控制目的。m_Lives保存了玩家的剩余生命值,m_Level保存了游戏内部的等级难度,m_Level2保存了显示出来的游戏难度,m_Stage保存了游戏的关卡(m_Level、m_Level2和m_Stage的区别后面大家会明白的,不用在这里纠结)。m_Steps[]保存了可供m_Adjust选择的数值。

然后我们定义了一个结构体来记录游戏中的对象。fx和fy记录每次在网格上移动我们的英雄和敌人的精确像素位置,x和y则记录着对象即将移动到网格交点是哪个。而最后一个变量spin用来使对象在z轴上选择。定义完后,我们就利用这个结构体创建我们的玩家对象,敌人对象(最多有9个所以是长度为9的数组)和宝物沙漏对象(m_Hourglass)。

还有我们需要载入两个纹理,所以有了m_FileName[2]和m_Texture[2。而m_Base储存字符显示列表的开始值,m_Sound用来指向一个QSound对象,该对象保存了吃到宝物后的计时音乐(注意声明QSound时需要在类前面加上class QSound声明)。最后是5个新的函数的声明,作用大家先看注释留个印象吧,后面会慢慢来介绍解释。


接下来,我们打开myglwidget.cpp,加上声明#include <QTimer>、#include <QSound>、#include <QTime>、#include <QCoreApplication>,在构造函数中对新增变量进行初始化并修改析构函数,具体代码如下:

const int MyGLWidget::s_Steps[] = {1, 2, 4, 5, 10, 20};

MyGLWidget::MyGLWidget(QWidget *parent) :
    QGLWidget(parent)
{
    fullscreen = false;
    setFixedSize(640, 480);                             //设置固定的窗口大小

    for (int i=0; i<11; i++)                            //初始化每个线段都没被走过
    {
        for (int j=0; j<11; j++)
        {
            if (i < 10)
            {
                m_Hline[i][j] = false;
            }
            if (j < 10)
            {
                m_Vline[i][j] = false;
            }
        }
    }
    m_Filled = false;
    m_Gameover = false;
    m_Anti = true;

    m_Delay = 0;
    m_Adjust = 3;
    m_Lives = 5;
    m_Level = 1;
    m_Level2 = m_Level;
    m_Stage = 1;

    resetObjects();                                     //初始化玩家和敌人信息
    m_Hourglass.fx = 0;                                 //初始化宝物沙漏信息
    m_Hourglass.fy = 0;
    m_FileName[0] = "D:/QtOpenGL/QtImage/Font.bmp";     //应根据实际存放图片的路径进行修改
    m_FileName[1] = "D:/QtOpenGL/QtImage/Image.bmp";
    m_Sound = new QSound("D:/QtOpenGL/QtImage/Freeze.wav");

    QTimer *timer = new QTimer(this);                   //创建一个定时器
    //将定时器的计时信号与updateGL()绑定
    connect(timer, SIGNAL(tim
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值