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();}
效果:
游戏还无法根据健康值提示结束,也没有办法升级,很简单,也很实用。
- Qt 游戏开发(06) - 为游戏增加健康值和得分
- Qt 游戏开发(07) - 为游戏增加音效
- 游戏得分
- Qt 游戏开发(08) - 为游戏设置图片
- jquery 游戏得分冒泡效果
- cocos2d-x游戏得分显示
- 51NOD-1390 游戏得分
- 51nod-1390 游戏得分
- 51nod 1390 游戏得分
- 51Nod-1390-游戏得分
- 51nod-1390-游戏得分
- 51nod 1390 游戏得分
- 使用FLEX 和 Actionscript开发FLASH 游戏—嵌入资源和增加游戏元素
- 使用Qt开发俄罗斯方块游戏
- 第一章 第十节 游戏回顾:玩家得分
- 51Nod-1390-游戏得分
- 51nod 1390 游戏得分(贪心)
- 杂谈:健康与游戏行业
- spark 输出结果压缩(gz)
- pentaho7.0安装配置 (三)
- 深度学习-如何调试基于spark的LSTM
- JAVA之猜数字游戏
- Linux的capability分析
- Qt 游戏开发(06) - 为游戏增加健康值和得分
- 输入框禁止输入特殊字符
- 简单的jsp页面实现登录
- 过年了
- Office 中的 Word 及常用操作
- Collections.unmodifiableCollection
- coordinatorLayout 和AppBarLayout的踩坑记
- T-SQL查询处理执行顺序(一)
- 九度 oj 题目1147:Jugs