Qt 游戏开发(06) - 为游戏增加健康值和得分

来源:互联网 发布:无人机软件系统测试 编辑:程序博客网 时间:2024/06/05 20:22

  之前写的文章中,大多数属于贴代码的类型,经过一段时间后,自己对于代码的理解并没什么什么裨益,反而让自己觉得写代码就是贴代码,丧失很多兴趣,水平也得不到提高。在看过那么多大牛写的文章之后,也决心结合自己的长处开始写些比较好的文章。

  闲话少说,此文章是之前C++ Qt Game Tutorial的续集,只是把标题换成更中文一些。

1. 新建一个widget工程,工程名字为tutorial6,删除生成的代码,只剩下tutorial6.pro 和 main.cpp

#-------------------------------------------------## Project created by QtCreator 2017-01-23T11:32:10##-------------------------------------------------QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = tutorial6TEMPLATE = appSOURCES += main.cppHEADERS  +=

#include <QApplication>int main(int argc, char *argv[]){    QApplication a(argc, argv);    return a.exec();}

tutorial6.pro是工程文件,相当于makefile, QT += core gui 添加相关的模块,比如需要opengl编程可以 QT += opengl,一般常见的类都会在core gui widgets上。

TARGET TEMPLATE 在建立工程时已经自动生成,SOURCES HEADERS在增加源文件或者头文件时会自动生成相应的文件。

main.cpp是程序执行的入口,每个程序都会有,函数中第一句话,建立一个QApplication a的对象,使用argc, argv初始化。这个对象主要用于管理GUI程序的控制流和主要的设置。它包含一个事件住循环,来自系统的事件(比如鼠标点击,敲键盘)都会通过这个QApplication对象分发出去;它还包括程序的初始化,程序的清除回收,以及程序的管理,主要是处理系统或者程序级别的设置。这个类暂时不需要研究太深,a.exec(),使程序进入循环,防止退出。


2. 给游戏添加玩家

在前面的篇章中,玩家是继承QGraphicsRectItem类,用一个正方形实现。关于C++的多继承,理解起来有点费劲,Qt中的将父类的对象的指针传递给子类,是为了更好地管理子类的资源,子类销毁之后,父类自动回收资源。

#ifndef PLAYER_H#define PLAYER_H#include <QGraphicsRectItem>#include <QObject>#include <QGraphicsItem>class Player : public QObject, public QGraphicsRectItem {    Q_OBJECTpublic:    Player(QGraphicsItem *parent = 0);    void keyPressEvent(QKeyEvent *event);public slots:    void spawn();};#endif // PLAYER_H

Player对象定义了一个公共方法keyPressEvent,这个方法的作用是可以通过键盘的←→键控制玩家的左右移动,通过空格键发射子弹。

void Player::keyPressEvent(QKeyEvent *event){    // move the player left and right    if (event->key() == Qt::Key_Left) {        if (pos().x() > 0)            setPos(x() - 10, y());    } else if (event->key() == Qt::Key_Right) {        if (pos().x() + 100 < 800)            setPos(x() + 10, y());    } else if (event->key() == Qt::Key_Space) {        // shoot with the spacebar        // create a bullet        Bullet *bullet = new Bullet();        bullet->setPos(x(), y());        scene()->addItem(bullet);    }}

setPos是父类QGraphicsItem中的方法,表示玩家在窗口中的位置,玩家还有其它的方法,在构建的过程中,会调用如下的函数。

  player->setRect(0,0,100,100); // change the rect from 0x0 (default) to 100x100 pixels  player->setPos(400,500); // TODO generalize to always be in the middle bottom of screen  // make the player focusable and set it to be the current focus  player->setFlag(QGraphicsItem::ItemIsFocusable);  player->setFocus();


3. 创建子弹

子弹主要有一个move方法,通过QTimer,每个50ms移动10个像素,QTimer和Bullet是通过connect / slot机制完成通信的。另外在检测碰撞的过程中使用collidingItems()函数,具体的做法可以查看源码的注释,注释说得都比较清楚。

void Bullet::move() {    // get a list of all the items currently colliding with this bullet    QList<QGraphicsItem *> colliding_items = collidingItems();    // if one of the colliding items is an Enemy, destory both the bullet and the enemy    for (int i = 0, n = colliding_items.size(); i < n; ++i) {        if (typeid(*(colliding_items[i])) == typeid(Enemy)) {            // increase the score            game->score->increase();            // remove them from the scene(colliding_items[i]);            scene()->removeItem(colliding_items[i]);            scene()->removeItem(this);        }    }    // if there was no collision with an Enemy, move the bullet forward    setPos(x(), y() - 10);    // if the bullet is off the screen, destory it    if (pos().y() + rect().height() < 0) {        scene()->removeItem(this);        delete this;    }}


4. 创建敌人

敌人通过rand()函数在X坐标轴上随机产生,通过timer每隔50ms向下降落5个像素。它的产生在玩家的spawn()函数中,每次都要判断是否到达最底端,如果是则健康值减1.

可以直接阅读后面的代码。


5. 增加健康值和得分

可以直接阅读后面的代码。


6. 创建game布局

可以直接阅读后面的代码。

#-------------------------------------------------## Project created by QtCreator 2017-01-23T11:32:10##-------------------------------------------------QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = tutorial6TEMPLATE = appSOURCES += main.cpp \    player.cpp \    bullet.cpp \    enemy.cpp \    game.cpp \    health.cpp \    score.cppHEADERS  += \    player.h \    bullet.h \    enemy.h \    game.h \    health.h \    score.h

#ifndef BULLET_H#define BULLET_H#include <QGraphicsRectItem>#include <QGraphicsItem>#include <QObject>class Bullet : public QObject, public QGraphicsRectItem {    Q_OBJECTpublic:    Bullet(QGraphicsItem *parent = 0);public slots:    void move();};#endif // BULLET_H

#include "bullet.h"#include "enemy.h"#include <QTimer>#include <QGraphicsScene>#include <QList>#include <typeinfo>#include "game.h"// there is an external global object called gameextern Game *game;Bullet::Bullet(QGraphicsItem *parent) : QObject(), QGraphicsRectItem(parent){    // drew the bullet (a rectangle)    setRect(0, 0, 10, 50);    // make/connect a timer to move() the bullet every so often    QTimer *timer = new QTimer(this);    connect(timer, SIGNAL(timeout()), this, SLOT(move()));    // start the timer    timer->start(50);}void Bullet::move() {    // get a list of all the items currently colliding with this bullet    QList<QGraphicsItem *> colliding_items = collidingItems();    // if one of the colliding items is an Enemy, destory both the bullet and the enemy    for (int i = 0, n = colliding_items.size(); i < n; ++i) {        if (typeid(*(colliding_items[i])) == typeid(Enemy)) {            // increase the score            game->score->increase();            // remove them from the scene(colliding_items[i]);            scene()->removeItem(colliding_items[i]);            scene()->removeItem(this);            // delete them from the heap to save memory            delete colliding_items[i];            delete this;            // return (all code below refers to a non exist int bullet            return ;        }    }    // if there was no collision with an Enemy, move the bullet forward    setPos(x(), y() - 10);    // if the bullet is off the screen, destory it    if (pos().y() + rect().height() < 0) {        scene()->removeItem(this);        delete this;    }}

#ifndef ENEMY_H#define ENEMY_H#include <QGraphicsRectItem>#include <QObject>#include <QGraphicsItem>class Enemy : public QObject, public QGraphicsRectItem {    Q_OBJECTpublic:    Enemy(QGraphicsItem *parent = 0);public slots:    void move();};#endif // ENEMY_H

#include "enemy.h"#include <QTimer>#include <QGraphicsScene>#include <QList>#include <stdlib.h> // rand() -> really large int#include "game.h"extern Game *game;Enemy::Enemy(QGraphicsItem *parent){    // set random x position    int random_number = rand() % 700;    setPos(random_number, 0);    // draw the rect    setRect(0, 0, 100, 100);    // make/connect a timer to move() the enemy every so often    QTimer *timer = new QTimer(this);    connect(timer, SIGNAL(timeout()), this, SLOT(move()));    // start the timer    timer->start(50);}void Enemy::move(){    // move enemy down    setPos(x(), y() + 5);    // destroy enemy when it goes out of the screen    if (pos().y() > 600) {        // decrease the health        game->health->decrease();        scene()->removeItem(this);        delete this;    }}

#ifndef GAME_H#define GAME_H#include <QGraphicsView>#include <QWidget>#include <QGraphicsScene>#include "player.h"#include "score.h"#include "health.h"class Game : public QGraphicsView {public:    Game(QWidget *parent = 0);    QGraphicsScene *scene;    Player *player;    Score *score;    Health *health;};#endif // GAME_H

#include "game.h"#include <QTimer>#include <QGraphicsTextItem>#include <QFont>#include "enemy.h"#include "player.h"Game::Game(QWidget *parent) {    // create teh scene    scene = new QGraphicsScene();    // make the scene 800 * 600 instead of infinity by infinity (default)    // make the newly created scene the scene to visualize    // (since Game is a QGraphicsView widget, it can be used to visualize scenes)    setScene(scene);    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);    setFixedSize(800, 600);    // create the player    player = new Player();    // change the rect from 0x0 (default) to 100 * 100 pixels    player->setRect(0, 0, 100, 100);    // TODO generalize to always be in the middle botton of screen     player->setPos(400, 500);    // make the player focusable and set it to be the current focus    player->setFlag(QGraphicsItem::ItemIsFocusable);    player->setFocus();    // add the palyer to the scene    scene->addItem(player);    // create the score / health    score = new Score();    scene->addItem(score);    health = new Health();    health->setPos(health->x(), health->y() + 25);    scene->addItem(health);    // spawn enmeies    QTimer *timer = new QTimer();    QObject::connect(timer, SIGNAL(timeout()), player, SLOT(spawn()));    timer->start(2000);    show();}

#ifndef HEALTH_H#define HEALTH_H#include <QGraphicsTextItem>class Health : public QGraphicsTextItem {public:    Health(QGraphicsItem *parent = 0);    void decrease();    int getHealth();private:    int health;};#endif // HEALTH_H

#include <health.h>#include <QFont>Health::Health(QGraphicsItem *parent) : QGraphicsTextItem(parent){    health = 3;    // draw the text    setPlainText(QString("Health: ") + QString::number(health)); // health 3    setDefaultTextColor((Qt::red));    setFont(QFont("times", 16));}void Health::decrease(){    health--;    setPlainText(QString("Health: ") + QString::number(health));}int Health::getHealth(){    return health;}

#ifndef PLAYER_H#define PLAYER_H#include <QGraphicsRectItem>#include <QObject>#include <QGraphicsItem>class Player : public QObject, public QGraphicsRectItem {    Q_OBJECTpublic:    Player(QGraphicsItem *parent = 0);    void keyPressEvent(QKeyEvent *event);public slots:    void spawn();};#endif // PLAYER_H

#include "player.h"#include <QGraphicsScene>#include <QKeyEvent>#include "enemy.h"#include "bullet.h"Player::Player(QGraphicsItem *parent) : QGraphicsRectItem(parent){}void Player::keyPressEvent(QKeyEvent *event){    // move the player left and right    if (event->key() == Qt::Key_Left) {        if (pos().x() > 0)            setPos(x() - 10, y());    } else if (event->key() == Qt::Key_Right) {        if (pos().x() + 100 < 800)            setPos(x() + 10, y());    } else if (event->key() == Qt::Key_Space) {        // shoot with the spacebar        // create a bullet        Bullet *bullet = new Bullet();        bullet->setPos(x(), y());        scene()->addItem(bullet);    }}void Player::spawn(){    // create an enemy    Enemy *enemy = new Enemy();    scene()->addItem(enemy);}

#ifndef SCORE_H#define SCORE_H#include <QGraphicsTextItem>class Score : public QGraphicsTextItem {public:    Score(QGraphicsItem *parent = 0);    void increase();    int getScore();private:    int score;};#endif // SCORE_H

#include "score.h"#include <QFont>Score::Score(QGraphicsItem *parent){    //initialzie the score to 0    score = 0;    // draw the text    setPlainText(QString("Score: ") + QString::number(score));    setDefaultTextColor(Qt::blue);    setFont(QFont("times", 16));}void Score::increase() {    score++;    setPlainText(QString("Score: ") + QString::number(score));}int Score::getScore() {    return score;}

#include <QApplication>#include "game.h"Game *game;int main(int argc, char *argv[]){    QApplication a(argc, argv);    game = new Game();    game->show();    return a.exec();}

效果:



游戏还无法根据健康值提示结束,也没有办法升级,很简单,也很实用。


0 0
原创粉丝点击