Qt游戏编程——飞机大战

源码下载:http://download.csdn.net/detail/hao_zong_yin/9890778

效果图:


这篇文章记录了我用一周的时间从零Qt基础到制作出飞机大战的过程。

Qt相比MFC封装好了大量函数,而且非常有条理。飞机大战的实现主要用到了Qt的信号与槽机制、事件响应机制、计时器、随机数、QPainter绘图以及最关键的图形视图框架,在做飞机大战之前,建议掌握以下内容:

1.了解信号与槽机制,熟练使用connect函数

2.了解Qt时间响应机制,并学会响应鼠标、键盘事件

3.学会用QTimer控制时间

4.学会生成随机数(本文制作的游戏基本全部使用随机数控制,如果要制作高质量游戏的话建议结合计时器自己写各物体的行为)

5.学会使用QPainter绘图

6.最关键的一点,一定要熟练掌握图形视图框架,这是本文游戏编程的核心

7.多百度,多参考帮助文档

这里强力推荐Qt社区的快速入门教程,上面的内容在基础篇基本全部包含,而且Qt社区有大量的下载资源:

http://www.qter.org/portal.php?mod=view&aid=26

建议下载Qt5版本,并下载版本新一点的Qt creator,网上很多下载教程与下载资源,这里不再啰嗦


当完成了上面全部内容后,就可以正式开始了:

PS:游戏逻辑我会放在最后介绍,当然读者也可以跳到下面及时参考游戏逻辑的代码

根据面向对象的思想,我们应该有一个飞行物体的抽象类,为游戏中的所有飞行物体提供一个接口,飞行物体有飞机和子弹,而飞机有分为玩家飞机和敌机,子弹也分为玩家子弹和敌机子弹,所以还要建飞机抽象类和子弹抽象类继承飞行物体抽象类,对于飞机类,编写玩家飞机实体类和敌机实体类来继承实现飞机抽象类,对于子弹类,编写玩家子弹实体类和敌机子弹实体类继承实现子弹抽象类,现在,读者便可以编写各式各样的飞机子弹了,编写完成后只要继承相应的玩家飞机、敌机、玩家子弹、敌机子弹类就可以了。为了更好的实现各式各样的飞机子弹,我们创建飞机工厂和子弹工厂,在工厂中创造我们需要的物体。

大体思路说完以后,我们来说说这几个类的具体实现。

先看最核心的的类——飞行物体抽象类,所有飞行物体都应该有大小、速度、图片,以及动画函数、碰撞检测函数和摧毁函数,然后编写飞机抽象类,飞机都有血量,而且都会发射子弹,还要有一个函数负责给飞机减血,之后编写子弹抽象类,子弹是飞机大战中最终要的元素,除了各式各样的图片外,还应该朝不同方向发射,这就需要一个角度。

对于实体类,首先要实现基类中的纯虚函数。对于玩家飞机,我们应该为其添加键盘控制,并在实现发射子弹函数时通过子弹工厂装填玩家子弹,对于敌机,为了游戏性读者应该会添加各式各样的杂鱼、BOSS来继承敌机类,这就需要我们为每种类型的敌机都添加其属于自己的子弹、动画效果,为了实现各种移动我们应该为其添加一个角度,便于在飞机工厂中及时控制。建各式各样的飞机飞行效果。玩家子弹、敌机子弹同理编写各式各样的子类,配合子弹工厂实现各种效果。

这里绘图,动画,碰撞检测函数系统都封装好了,完成了准备工作的读者应该可以熟练掌握。

除此之外游戏还有好多其他元素,比如各种补充包,我们可以写一个supply类继承飞行物体类,然后编写子类实现各种补充包。玩家技能则可以看做特殊的子弹继承子弹类,在子弹工厂中创造出来。动态效果的话可以用一组图片通过不断变换来实现,还有更多丰富功能请读者自行添加......

对于游戏逻辑,其实应该读者自己编写,我这里只提供了一个关卡的模板space,space应该具有一个update函数不断刷屏,配合系统提供的advance函数实现移动,同时用step变量来判断隔多久生成敌人、补充包,并用level判断一次生成多少个敌人,然后就是一些开始游戏、暂停游戏、游戏结束之类的逻辑以及显示界面了(这里我没有实现得分显示之类的,本来我想用QGraohicsTextItem实现的,结果发现确实dll而runtime error!)

说了这么多,该上代码了:

全局变量:

#ifndef GLOBAL_H
#define GLOBAL_H

//此代码仅是一个模板,元素比较单一,但功能接口比较全,各种类型都可以通过在相应的工厂中改变参数实现,或是继承强大的基类实现
//游戏效果可以在全局变量中便捷的控制,添加新元素时注意添加相应的全局变量
//某些细节可能不条理,可以进行适当地调整
//代码中间很少加注释,参考度娘

#include <QtWidgets>

//Name
#define BLOODSUPPLYNAME 1
#define BOMBSUPPLYNAME 2
#define BULLETSUPPLYNAME 3
#define PLAYERPLANENAME 4
#define ENEMYPLANENAME 5
#define PLAYERBULLETNAME 6
#define ENEMYBULLETNAME 7
#define BOMBNAME 8

//Size
#define SCENEWIDTH  1000
#define SCENEHEIGHT  1000
#define BLOODSUPPLYSIZE 30
#define BOMBSUPPLYSIZE 30
#define BULLETSUPPLYSIZE 30
#define PLAYERPLANESIZE 40
#define FISHSIZE 100
#define BOSSSIZE 200
#define PLAYERBULLETSIZE 20
#define FISHBULLETSIZE1 20
#define FISHBULLETSIZE2 20
#define FISHBULLETSIZE3 20
#define BOSSBULLETSIZE1 80
#define BOSSBULLETWIDTH2 200
#define BOSSBULLETHEIGHT2 40
#define BOSSBULLETSIZE3 200
#define BOSSBULLETWIDTH4 200
#define BOSSBULLETHEIGHT4 200
#define BOMBSIZE 800

//Speed
#define BLOODSUPPLYSPEED 20
#define BOMBSUPPLYSPEED 20
#define BULLETSUPPLYSPEED 20
#define PLAYERPLANESPEED 10
#define FISHSPEED 10
#define BOSSSPEED 2
#define PLAYERBULLETSPEED 50
#define FISHBULLETSPEED1 20
#define FISHBULLETSPEED2 20
#define FISHBULLETSPEED3 20
#define BOSSBULLETSPEED1 5
#define BOSSBULLETSPEED2 20
#define BOSSBULLETSPEED3 20
#define BOSSBULLETSPEED4 5
#define BOMBSPEED 10

//UpdateTime, 因为包含一些内部逻辑, 直接改动可能会有错误, 改之前确保理解advance函数中step的意义
const int PLAYERSHOOTSTEP  = 5;
const int BOSSSHOOTSTEP = 20;
const int FISHSHOOTSTEP = 20;
const int BOMBPIXSTEP = 10;
const int BOSSPIXSTEP = 10;

//Score
#define FISHSCORE 10
#define BOSSSCORE 1000

//Hp
#define FISHHP 10
#define BOSSHP 1000

//UP(上限)
#define PLAYERPLANEBLOOD 3
#define PLAYERPLANEBOMB 3
#define PLAYERPLANEBULLET 3

//只实现了boss的动态、玩家的动态和炸弹动态,背景滚动和爆炸效果同理,这里懒得写了
//想要改变动态效果的话注意图片数量,然后自行在飞机、子弹工厂以及控制台中进行相应的改变
const QString background = ":/image/background/background.jpeg";
const QString bloodsupplypix = ":/image/bloodsupply/bloodsupply.png";
const QString bomb0 = ":image/bomb/bomb0.png";
const QString bomb1 = ":image/bomb/bomb1.png";
const QString bombsupplypix = ":/image/bombsupply/bombsupply.png";
const QString boss0 = ":/image/enemyplane/boss0.png";
const QString boss1 = ":/image/enemyplane/boss1.png";
const QString boss2 = ":/image/enemyplane/boss2.png";
const QString boss3 = ":/image/enemyplane/boss3.png";
const QString bossbullet0 = ":/image/enemybullet/bossbullet0.png";
const QString bossbullet1 = ":/image/enemybullet/bossbullet1.png";
const QString bossbullet2 = ":/image/enemybullet/bossbullet2.png";
const QString bossbullet3 = ":/image/enemybullet/bossbullet3.png";
const QString bulletsupplypix = ":/image/bulletsupply/bulletsupply.png";
const QString fish0 = ":/image/enemyplane/fish0.png";
const QString fish1 = ":/image/enemyplane/fish1.png";
const QString fish2 = ":/image/enemyplane/fish2.png";
const QString fishbullet0 = ":/image/enemybullet/fishbullet0.png";
const QString fishbullet1 = ":/image/enemybullet/fishbullet1.png";
const QString fishbullet2 = ":/image/enemybullet/fishbullet2.png";
const QString playerbullet0 = ":/image/playerbullet/playerbullet0.png";
const QString playerbullet1 = ":/image/playerbullet/playerbullet1.png";
const QString playerbullet2 = ":/image/playerbullet/playerbullet2.png";
const QString playerplane0 = ":/image/PlayerPlane/playerplane0.png";
const QString playerplane1 = ":/image/PlayerPlane/playerplane1.png";
const QString playerplane2 = ":/image/PlayerPlane/playerplane2.png";
const QString playerplane3 = ":/image/PlayerPlane/playerplane3.png";

#endif // GLOBAL_H


飞行物体抽象类

#ifndef FLYER_H
#define FLYER_H

#include <QtWidgets>
#include "global.h"

typedef enum {UP, DOWN, LEFT, RIGHT} CHECK_FLAG;
typedef QList<QPixmap> QPixmaps;

class Flyer : public QGraphicsObject
{
    Q_OBJECT
public:
    Flyer(qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0)
        : QGraphicsObject(parent), m_w(w), m_h(h), m_speed(speed), m_pixpos(0), m_step(0) {
        for (int i = 0; i < pixs.size(); i++) {
            QPixmap temp(pixs.at(i)), t;
            t = temp.scaled(m_w, m_h, Qt::KeepAspectRatioByExpanding);
            m_pixs.append(t);
        }
        scene->addItem(this);
    }
    virtual ~Flyer() {}
    virtual int name() const = 0;
    virtual void posLost() = 0;
    virtual void doCollide() = 0;
    virtual void fall() = 0;
    bool checkPos(CHECK_FLAG flag)
    {
        bool ok = false;
        switch (flag) {
        case UP:
            if (scenePos().ry() >= -m_h) ok = true;
            break;
        case DOWN:
            if (scenePos().ry() <= SCENEHEIGHT) ok = true;
            break;
        case LEFT:
            if (scenePos().rx() >= -m_w) ok = true;
            break;
        case RIGHT:
            if (scenePos().rx() <= SCENEWIDTH) ok = true;
            break;
        }
        return ok;
    }
protected:
    qreal m_w, m_h, m_speed, m_pixpos;//物体大小 & 速度 & 图片位置 & 动画控制
    uint m_step;//因为要取余所以必须是int
    QPixmaps m_pixs;
};

#endif // FLYER_H

飞机抽象类

#ifndef FLIGHTVEHICLE_H
#define FLIGHTVEHICLE_H

#include "flyer.h"
#include "unflyer.h"

class FlightVehicle : public Flyer
{
    Q_OBJECT
public:
    FlightVehicle(qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0)
        :Flyer(w, h, speed, pixs, scene, parent), m_blood(blood) {

    }
    virtual ~FlightVehicle() {}
    virtual void strike() = 0;
    virtual void shoot() = 0;
protected:
    qreal m_blood;//血量
signals:
    //向控制中心发送消息更改显示, 注释的那一块崩了
    void sig_score(int score);
    //void sig_blood(int blood);
    //void sig_bomb(int bomb);
    void sig_fall();
};

#endif // FLIGHTVEHICLE_H

子弹抽象类

#ifndef BULLET_H
#define BULLET_H

#include "flyer.h"
#include "unflyer.h"
#include <math.h>

#define ROTATE 57.26

class Bullet : public Flyer
{
public:
    Bullet(qreal angle,
           qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0)
        :Flyer(w, h, speed, pixs, scene, parent),
         m_angle(angle),
         xSpeed(::cos(m_angle / ROTATE) * m_speed),
         ySpeed(::sin(m_angle / ROTATE) * m_speed) {

    }
    virtual ~Bullet() {

    }
protected:
    qreal m_angle, xSpeed, ySpeed;
};

#endif // BULLET_H



玩家飞机

#ifndef PLAYERPLANE_H
#define PLAYERPLANE_H

#include "flightvehicle.h"
#include "bulletfactory.h"

class PlayerPlane : public FlightVehicle
{
public:
    PlayerPlane(qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0);
    ~PlayerPlane();
    QRectF boundingRect() const;
    QPainterPath shape() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    int name() const;
    void advance(int);
    void posLost();
    void doCollide();
    void fall();
    void strike();
    void shoot();
protected:
    void keyPressEvent(QKeyEvent *event);
    void keyReleaseEvent(QKeyEvent *event);
private:
    qreal m_bomb, m_bullet;//必杀技 & 子弹形态
    bool W, A, S, D, bomb;
};

#endif // PLAYERPLANE_H

#include "playerPlane.h"

PlayerPlane::PlayerPlane(qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent):
    FlightVehicle(blood, w, h, speed, pixs, scene, parent),
    m_bomb(3), m_bullet(0), W(false), A(false), S(false), D(false), bomb(false) {
    setPos((scene->width() - m_w)/2, scene->height() - m_h);
    setFlag(QGraphicsItem::ItemIsFocusable);
}

PlayerPlane::~PlayerPlane() {

}

QRectF PlayerPlane::boundingRect() const
{
    return m_pixs.at(0).rect();
}

QPainterPath PlayerPlane::shape() const
{
    QPainterPath path;
    path.addRect(boundingRect());
    return path;
}

void PlayerPlane::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->drawPixmap(0, 0, m_pixs.at(m_pixpos));
}

int PlayerPlane::name() const {
    return PLAYERPLANENAME;
}

void PlayerPlane::advance(int) {
    m_step++;
    if (m_step % PLAYERSHOOTSTEP == 0) {
        shoot();
    }
    if (m_step == PLAYERSHOOTSTEP * 10) m_step = 0;
    if (W && checkPos(UP)) {
        m_pixpos = 0;
        QPointF pos = scenePos();
        pos.ry() -= m_speed;
        setPos(pos);
    }
    if (S && checkPos(DOWN)) {
        m_pixpos = 1;
        QPointF pos = scenePos();
        pos.ry() += m_speed;
        setPos(pos);
    }
    if (A && checkPos(LEFT)) {
        m_pixpos = 2;
        QPointF pos = scenePos();
        pos.rx() -= m_speed;
        setPos(pos);
    }
    if (D && checkPos(RIGHT)) {
        m_pixpos = 3;
        QPointF pos = scenePos();
        pos.rx() += m_speed;
        setPos(pos);
    }
    if (!W && !S && !A && !D) m_pixpos = 0;
    doCollide();
}

void PlayerPlane::posLost() {

}

void PlayerPlane::doCollide()
{
    foreach (QGraphicsItem *t, collidingItems()) {
        if (t->type() != UnFlyer::TYPE) {
            Flyer *flyer = static_cast<Flyer*>(t);
            switch (flyer->name()) {
            case ENEMYPLANENAME:
                strike();
                if (m_blood == 0) {
                    m_bomb = 0;
                    m_bullet = 0;
                    fall();
                }
                break;
            case ENEMYBULLETNAME:
                flyer->fall();
                strike();
                if (m_blood == 0) {
                    m_bomb = 0;
                    m_bullet = 0;
                    fall();
                }
                break;
            case BLOODSUPPLYNAME:
                flyer->fall();
                if (m_blood < PLAYERPLANEBLOOD) {
                    m_blood++;
                    //emit sig_blood(m_blood);
                }
                break;
            case BOMBSUPPLYNAME:
                flyer->fall();
                if (m_bomb < PLAYERPLANEBOMB) {
                    m_bomb++;
                    //emit sig_bomb(m_bomb);
                }
                break;
            case BULLETSUPPLYNAME:
                flyer->fall();
                if (m_bullet < PLAYERPLANEBULLET) {
                    m_bullet++;
                }
                break;
            }
        }
    }
}

void PlayerPlane::fall()
{
    setFlag(QGraphicsItem::ItemIsMovable, false);
    setFlag(QGraphicsItem::ItemIsFocusScope, false);
    setVisible(false);
    deleteLater();
    emit sig_fall();
}

void PlayerPlane::strike() {
    //m_blood--;
    //emit sig_blood(m_blood);
}

void PlayerPlane::shoot()
{
    BulletFactory::PlayerBullets bullets = BulletFactory::pcreator(m_bullet, scene());
    QPointF pos = scenePos();
    pos.rx() += m_w / 2 - PLAYERBULLETSIZE / 2;
    foreach (PlayerBullet* bullet, bullets) {
        bullet->setPos(pos);
    }
    if (bomb && m_bomb > 0) {
        bomb = false;
        //m_bomb--;
        BulletFactory::Bombs bombs = BulletFactory::bcreator(1, scene());
        pos = scenePos();
        pos.rx() += m_w / 2 - BOMBSIZE / 2;
        pos.ry() -= BOMBSIZE / 2;
        foreach (Bomb* bomb, bombs) {
            bomb->setPos(SCENEWIDTH / 2 - BOMBSIZE / 2, SCENEHEIGHT - BOMBSIZE);
        }
    }
}

void PlayerPlane::keyPressEvent(QKeyEvent *event)
{
    switch (event->key()) {
    case Qt::Key_W:
        event->accept();
        W = true;
        break;
    case Qt::Key_S:
        event->accept();
        S = true;
        break;
    case Qt::Key_A:
        event->accept();
        A = true;
        break;
    case Qt::Key_D:
        event->accept();
        D = true;
        break;
    case Qt::Key_Space:
        event->accept();
        bomb = true;
        break;
    default:
        event->ignore();
        break;
    }
}

void PlayerPlane::keyReleaseEvent(QKeyEvent *event) {
    switch (event->key()) {
    case Qt::Key_W:
        event->accept();
        W = false;
        break;
    case Qt::Key_S:
        event->accept();
        S = false;
        break;
    case Qt::Key_A:
        event->accept();
        A = false;
        break;
    case Qt::Key_D:
        event->accept();
        D = false;
        break;
    case Qt::Key_Space:
        event->accept();
        bomb = false;
        break;
    default:
        event->ignore();
        break;
    }
}


敌机

#ifndef ENEMYPLANE_H
#define ENEMYPLANE_H

#include "flightvehicle.h"
#include "bulletfactory.h"

class EnemyPlane : public FlightVehicle
{
public:
    EnemyPlane(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0);
    ~EnemyPlane();
    QRectF boundingRect() const;
    QPainterPath shape() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    int name() const;
    void posLost();
    void strike();
protected:
    qreal m_angle, x_speed, y_speed;
};

#endif // ENEMYPLANE_H

#include "enemyplane.h"

EnemyPlane::EnemyPlane(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent):
    FlightVehicle(blood, w, h, speed, pixs, scene, parent), m_angle(angle),
    x_speed(::cos(m_angle / ROTATE) * m_speed),
    y_speed(::sin(m_angle / ROTATE) * m_speed) {

}

EnemyPlane::~EnemyPlane() {

}

QRectF EnemyPlane::boundingRect() const
{
    return m_pixs.at(0).rect();
}

QPainterPath EnemyPlane::shape() const
{
    QPainterPath path;
    path.addRect(boundingRect());
    return path;
}

void EnemyPlane::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->drawPixmap(0, 0, m_pixs.at(m_pixpos));
}

int EnemyPlane::name() const
{
    return ENEMYPLANENAME;
}

void EnemyPlane::posLost()
{
    setVisible(false);
    deleteLater();
}

void EnemyPlane::strike() {
    m_blood--;
}





敌机——杂鱼

#ifndef FISH_H
#define FISH_H

#include "enemyplane.h"
#include "randomizer.h"

class Fish : public EnemyPlane
{
public:
    Fish(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0);
    ~Fish();
    void advance(int);
    void doCollide();
    void fall();
    void shoot();
};

#endif // FISH_H

#include "fish.h"

Fish::Fish(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent):
    EnemyPlane(angle, blood, w, h, speed, pixs, scene, parent) {

}

Fish::~Fish() {

}

void Fish::advance(int)
{
    m_step++;
    if (m_step % FISHSHOOTSTEP == 0) {
        shoot();
    }
    if (m_step == FISHSHOOTSTEP * 10) m_step = 0;
    QPointF pos = scenePos();
    if (!checkPos(DOWN) || !checkPos(LEFT) || !checkPos(RIGHT)) {
        posLost();
        return;
    }
    if (!checkPos(UP)) {
        y_speed = -y_speed;
    }
    pos.ry() += y_speed;
    pos.rx() += x_speed;
    setPos(pos);
    doCollide();
}

void Fish::doCollide()
{
    foreach (QGraphicsItem *t, collidingItems()) {
        if (t->type() != UnFlyer::TYPE) {
            Flyer *flyer = static_cast<Flyer*>(t);
            if (flyer->name() == PLAYERBULLETNAME) {
                flyer->fall();
                strike();
                if (m_blood == 0) fall();
            }
            if (flyer->name() == BOMBNAME) {
                m_blood = 0;
                fall();
            }
        }
    }
}

void Fish::fall()
{
    setVisible(false);
    deleteLater();
    emit sig_score(FISHSCORE);
}

void Fish::shoot()
{
    int temp = Randomizer::creat(3);
    if (temp == 0) temp = 3;
    BulletFactory::EnemyBullets bullets = BulletFactory::ecreator(temp, scene());
    QPointF pos = scenePos();
    pos.rx() += m_w - FISHBULLETSIZE1;
    pos.ry() += m_h;
    foreach (EnemyBullet* bullet, bullets) {
        bullet->setPos(pos);
    }
}




敌机——BOSS

#ifndef BOSS_H
#define BOSS_H

#include "enemyplane.h"

class Boss : public EnemyPlane
{
public:
    Boss(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0);
    ~Boss();
    void advance(int);
    void doCollide();
    void fall();
    void shoot();
private:
    int flag;//特殊控制boss图片变换
};

#endif // BOSS_H

#include "boss.h"

Boss::Boss(qreal angle, qreal blood, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent):
    EnemyPlane(angle, blood, w, h, speed, pixs, scene, parent), flag(1) {

}

Boss::~Boss() {

}

void Boss::advance(int)
{
    m_step++;
    if (m_step % BOSSPIXSTEP == 0) {
        if (flag == 1 && m_pixpos == m_pixs.size() - 1) flag = -1;
        else if (flag == -1 && m_pixpos == 0) flag = 1;
        m_pixpos += flag;
        m_step = 0;
    }
    if (m_step % BOSSSHOOTSTEP == 0) {
        shoot();
    }
    if (m_step == BOSSSHOOTSTEP * 1000) m_step = 0;
    QPointF pos = scenePos();
    if (!checkPos(UP) || !checkPos(DOWN)) {
        y_speed = -y_speed;
    }
    if (!checkPos(LEFT) || !checkPos(RIGHT)) {
        x_speed = -x_speed;
    }
    pos.ry() += y_speed;
    pos.rx() += x_speed;
    setPos(pos);
    doCollide();
}

void Boss::doCollide()//Boss免疫大招
{
    foreach (QGraphicsItem *t, collidingItems()) {
        if (t->type() != UnFlyer::TYPE) {
            Flyer *flyer = static_cast<Flyer*>(t);
            if (flyer->name() == PLAYERBULLETNAME) {
                flyer->fall();
                strike();
                if (m_blood == 0) fall();
            }
        }
    }
}

void Boss::fall()
{
    setVisible(false);
    deleteLater();
    emit sig_score(BOSSSCORE);
}

void Boss::shoot()
{
    int temp;//这里temp的值应该在工厂中有宏定义,从而增强可读性,懒得写了
    if (1.0 * BOSSHP * 3 / 4 < m_blood && m_blood <= BOSSHP) temp = 4;
    else if (1.0 * BOSSHP * 2 / 4 < m_blood && m_blood <= 1.0 * BOSSHP * 3 / 4) temp = 5;
    else if (1.0 * BOSSHP * 1 / 4 < m_blood && m_blood <= 1.0 * BOSSHP * 2 / 4) temp = 6;
    else if (0 < m_blood && m_blood <= 1.0 * BOSSHP * 1 / 4) temp = 7;
    BulletFactory::EnemyBullets bullets = BulletFactory::ecreator(temp, scene());
    QPointF pos = scenePos();
    int bulletsize = BOSSBULLETSIZE1;
    if (temp == 5 || temp == 6 || temp == 7) bulletsize = BOSSSIZE / 2;
    pos.rx() += m_w / 2 - bulletsize / 2;
    pos.ry() += m_h / 2;
    foreach (EnemyBullet* bullet, bullets) {
        bullet->setPos(pos);
    }
}



玩家子弹

#ifndef PLAYERBULLET_H
#define PLAYERBULLET_H

#include "bullet.h"

class PlayerBullet : public Bullet
{
public:
    PlayerBullet(qreal angle, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0);
    ~PlayerBullet();
    QRectF boundingRect() const;
    QPainterPath shape() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    int name() const;
    void advance(int);
    void posLost();
    void doCollide();
    void fall();
};

#endif // PLAYERBULLET_H




#include "playerbullet.h"

PlayerBullet::PlayerBullet(qreal angle, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent)
    :Bullet(angle, w, h, speed, pixs, scene, parent) {

}

PlayerBullet::~PlayerBullet() {

}

QRectF PlayerBullet::boundingRect() const
{
    return m_pixs.at(0).rect();
}

QPainterPath PlayerBullet::shape() const
{
    QPainterPath path;
    path.addRect(boundingRect());
    return path;
}

void PlayerBullet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->drawPixmap(0, 0, m_pixs.at(0));
}

int PlayerBullet::name() const
{
    return PLAYERBULLETNAME;
}

void PlayerBullet::advance(int)
{
    if (!checkPos(UP) || !checkPos(DOWN) || !checkPos(LEFT) || !checkPos(RIGHT)) {
        posLost();
        return;
    }
    QPointF pos = scenePos();
    pos.rx() -= xSpeed;
    pos.ry() -= ySpeed;
    setPos(pos);
}

void PlayerBullet::posLost() {
    setVisible(false);
    deleteLater();
}

void PlayerBullet::doCollide() {

}

void PlayerBullet::fall() {
    setVisible(false);
    deleteLater();
}

敌机子弹

#ifndef ENEMYBULLET_H
#define ENEMYBULLET_H

#include "bullet.h"
#include <math.h>

#define ROTATE 57.26

class EnemyBullet : public Bullet
{
public:
    EnemyBullet(qreal angle, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent = 0);
    ~EnemyBullet();
    QRectF boundingRect() const;
    QPainterPath shape() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    int name() const;
    void posLost();
    void advance(int);
    void doCollide();
    void fall();
};

#endif // ENEMYBULLET_H
#include "enemybullet.h"

EnemyBullet::EnemyBullet(qreal angle, qreal w, qreal h, qreal speed, const QPixmaps &pixs, QGraphicsScene *scene, QGraphicsItem *parent)
    :Bullet(angle, w, h, speed, pixs, scene, parent){

}

EnemyBullet::~EnemyBullet() {

}

QRectF EnemyBullet::boundingRect() const
{
    return m_pixs.at(0).rect();
}

QPainterPath EnemyBullet::shape() const
{
    QPainterPath path;
    path.addRect(boundingRect());
    return path;
}

void EnemyBullet::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option);
    Q_UNUSED(widget);
    painter->drawPixmap(0, 0, m_pixs.at(0));
}

int EnemyBullet::name() const
{
    return ENEMYBULLETNAME;
}

void EnemyBullet::advance(int)
{
    if (!checkPos(UP) || !checkPos(DOWN) || !checkPos(LEFT) || !checkPos(RIGHT)) {
        posLost();
        return;
    }
    QPointF pos = scenePos();
    pos.rx() += xSpeed;
    pos.ry() += ySpeed;
    setPos(pos);
}

void EnemyBullet::posLost() {
    setVisible(false);
    deleteLater();
}

void EnemyBullet::doCollide() {

}

void EnemyBullet::fall() {
    setVisible(false);
    deleteLater();
}

飞机工厂:

#ifndef PLANEFACTORY_H
#define PLANEFACTORY_H

#include "boss.h"
#include "fish.h"
#include "randomizer.h"

class PlaneFactory
{
public:
    typedef QList<Boss*> BossPlanes;
    typedef QList<Fish*> FishPlanes;
    static BossPlanes bcreator(uint flag, QGraphicsScene *scene);
    static FishPlanes fcreator(uint flag, QGraphicsScene *scene);
};

#endif // PLANEFACTORY_H

#include "planefactory.h"

PlaneFactory::BossPlanes PlaneFactory::bcreator(uint flag, QGraphicsScene *scene)
{
    BossPlanes temp;
    switch (flag) {
    case 1:
        QPixmaps t;
        t.append(QPixmap(boss0));
        t.append(QPixmap(boss1));
        t.append(QPixmap(boss2));
        t.append(QPixmap(boss3));
        int angle = Randomizer::creat(180);
        temp.append(new Boss(angle, BOSSHP, BOSSSIZE, BOSSSIZE, BOSSSPEED, t, scene));
    }
    return temp;
}

PlaneFactory::FishPlanes PlaneFactory::fcreator(uint flag, QGraphicsScene *scene)
{
    FishPlanes temp;
    for (uint i = 0; i < flag; i++) {
        QPixmaps t;
        int x = Randomizer::creat(3);
        if (x == 1) t.append(QPixmap(fish0));
        else if (x == 2) t.append(QPixmap(fish1));
        else if (x == 0) t.append(QPixmap(fish2));
        int angle = Randomizer::creat(180);
        temp.append(new Fish(angle, FISHHP, FISHSIZE, FISHSIZE, FISHSPEED, t, scene));
    }
    return temp;
}
子弹工厂:

#ifndef BULLETFACTORY_H
#define BULLETFACTORY_H

#include "bomb.h"
#include "playerbullet.h"
#include "enemybullet.h"

class BulletFactory
{
public:
    typedef QList<Bomb*> Bombs;
    typedef QList<PlayerBullet*> PlayerBullets;
    typedef QList<EnemyBullet*> EnemyBullets;
    static Bombs bcreator(uint flag, QGraphicsScene *scene);
    static PlayerBullets pcreator(uint flag, QGraphicsScene *scene);
    static EnemyBullets ecreator(uint flag, QGraphicsScene *scene);
};

#endif // BULLETFACTORY_H

#include "bulletfactory.h"

BulletFactory::Bombs BulletFactory::bcreator(uint flag, QGraphicsScene *scene)
{
    Bombs temp;
    switch (flag) {
    case 0:
        break;
    case 1:
        QPixmaps t;
        t.append(QPixmap(bomb0));
        t.append(QPixmap(bomb1));
        temp.append(new Bomb(90, BOMBSIZE, BOMBSIZE, BOMBSPEED, t, scene));
        break;
    //可以继续添加,实现各种大招
    }
    return temp;
}

BulletFactory::PlayerBullets BulletFactory::pcreator(uint flag, QGraphicsScene *scene)
{
    PlayerBullets temp;
    if (flag == 0) {//作弊模式
        QPixmaps t;
        t.append(QPixmap(playerbullet0));
        for (int i = 0; i < 12; i++) {
            temp.append(new PlayerBullet(0 + 30 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene));
        }
    }
    if (flag >= 1) {
        QPixmaps t;
        t.append(QPixmap(playerbullet0));
        temp.append(new PlayerBullet(90, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene));
    }
    if (flag >= 2) {
        QPixmaps t;
        t.append(QPixmap(playerbullet1));
        for (int i = 0; i < 2; i++) {
            temp.append(new PlayerBullet(80 + 20 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene));
        }
    }
    if (flag >= 3) {
        QPixmaps t;
        t.append(QPixmap(playerbullet2));
        for (int i = 0; i < 2; i++) {
            temp.append(new PlayerBullet(40 + 20 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene));
        }
        for (int i = 0; i < 2; i++) {
            temp.append(new PlayerBullet(120 + 20 * i, PLAYERBULLETSIZE, PLAYERBULLETSIZE, PLAYERBULLETSPEED, t, scene));
        }
    }
    //可以继续添加,让玩家变得更变态
    return temp;
}

BulletFactory::EnemyBullets BulletFactory::ecreator(uint flag, QGraphicsScene *scene)
{
    EnemyBullets temp;
    QPixmaps t, t1, t2;
    switch (flag) {
    case 0:
        break;
    case 1:
        t.append(QPixmap(fishbullet0));
        temp.append(new EnemyBullet(90, FISHBULLETSIZE1, FISHBULLETSIZE1, FISHBULLETSPEED1, t, scene));
        break;
    case 2:
        t.append(QPixmap(fishbullet1));
        for (int i = 0; i < 3; i++) {
            temp.append(new EnemyBullet(80 + 10 * i, FISHBULLETSIZE2, FISHBULLETSIZE2, FISHBULLETSPEED2, t, scene));
        }
        break;
    case 3:
        t.append(QPixmap(fishbullet2));
        for (int i = 0; i < 4; i++) {
            temp.append(new EnemyBullet(0 + 90 * i, FISHBULLETSIZE3, FISHBULLETSIZE3, FISHBULLETSPEED3, t, scene));
        }
        break;
    case 4:
        t.append(QPixmap(bossbullet0));
        for (int i = 0; i < 8; i++) {
            temp.append(new EnemyBullet(0 + 45 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t, scene));
        }
        break;
    case 5:
        t1.append(QPixmap(bossbullet0));
        for (int i = 0; i < 12; i++) {
            temp.append(new EnemyBullet(0 + 30 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t1, scene));
        }
        t2.append(QPixmap(bossbullet1));
        temp.append(new EnemyBullet(90, BOSSBULLETWIDTH2, BOSSBULLETHEIGHT2, BOSSBULLETSPEED2, t2, scene));
        break;
    case 6:
        t1.append(QPixmap(bossbullet0));
        for (int i = 0; i < 12; i++) {
            temp.append(new EnemyBullet(0 + 30 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t1, scene));
        }
        t2.append(QPixmap(bossbullet2));
        temp.append(new EnemyBullet(90, BOSSBULLETSIZE3, BOSSBULLETSIZE3, BOSSBULLETSPEED3, t2, scene));
        break;
    case 7:
        t1.append(QPixmap(bossbullet0));
        for (int i = 0; i < 36; i++) {
            temp.append(new EnemyBullet(0 + 10 * i, BOSSBULLETSIZE1, BOSSBULLETSIZE1, BOSSBULLETSPEED1, t1, scene));
        }
        t2.append(QPixmap(bossbullet2));
        temp.append(new EnemyBullet(90, BOSSBULLETSIZE3, BOSSBULLETSIZE3, BOSSBULLETSPEED3, t2, scene));
        break;
    //推荐继续添加子弹,尤其是可以根据时间变化的子弹(用m_step控制)
    }
    return temp;
}


太长了。。。。。。附加功能和游戏逻辑另写一篇:

http://blog.csdn.net/hao_zong_yin/article/details/74560842

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值