# 植物大战僵尸Qt版
## 一、初步设计
### 1. 框架
本程序分为两个部分:菜单界面采用`QWidget`实现,有一个父窗口,通过信号槽机制调用各种子窗口;游戏界面使用`QGraphicsScene`框架实现,里面包含`view`和各种图形项`item`。
本程序采用面向对象程序设计思路,创建基类植物`Plant`、僵尸`Zombie`、卡牌`Cards`,在这基础上派生出不同的类,如豌豆射手、路障僵尸等。创建一个`Map`类,用以记录植物的位置,以及是否可以种植。
### 2. 界面
首先,整个窗口界面是`900X600`的大小,并且大小不可调。
菜单界面依然是植物大战僵尸的那个味道,放置熟悉的菜单背景,在右侧放置游戏开始按钮,玩家点击后程序会展示僵尸的一封信,再次点击即可进入游戏界面。
游戏界面也依然是植物大战僵尸的那个味道,几乎差不多。最上方是卡牌选择框,在选择框左侧显示阳光点数。左上角是返回菜单和游戏暂停按钮,在左侧摆放割草机,右侧出僵尸,正中一大片区域放植物,最下方展示游戏目标。
游戏开始,依然是植物大战僵尸的味道。玩家选择卡牌,在地图中央点击放置植物;若想铲除植物,则需点击右上方的铲子进行铲除操作。
### 3. 图形项Item
基于`QGraphicsItem`的`Plant`和`Zombie`包含以下函数,注意,前两个是必须要实现的:
```
boundingRect() // Item的绘制边界
paint() // Item的绘制
collidesWithItem() //Item的碰撞判定
advance() // Item的动作状态
```
因为每种植物和僵尸的动作特点不同,实际编写程序的时候,是需要重写这四个函数的。
可点击的图形项:例如基于`QGraphicsItem`的`Cards`和`Sun`(阳光点数)包含以下函数:
```
boundingRect() // Item的绘制边界
paint() // Item的绘制
collidesWithItem() //Item的碰撞判定
advance() // Item的动作状态
mousePressEvent() // 鼠标动作
```
想实现各种`Item`的动画效果,就要将定时器`Timer`绑定到`QGraphicsScene`的`advance`函数。同时,游戏生成僵尸的函数也需要绑定到`advance`函数。
## 二、详细设计
### 1. 地图Map
`Map`类是整个程序的核心部位,是重中之重,`Map`主要完成了以下几件事情:
- 界定地图边界
- 计算并存储植物的位置
- 接收玩家的点击事件(尤其是卡牌被点击后)
- 生成太阳
我们来看看Map的变量:
```cpp
static Cards *PreparedPlant; //记录玩家点击了哪张卡牌
static Plant *PlantMap[9][5]; //记录植物的位置,类型是Plant,一般情况下为nullptr
```
地图是如何响应玩家的点击事件的呢?正常情况下,玩家点击地图是没有反应的;但是如果玩家先前点击卡牌购买植物,再点击地图,那么就必须做出反应了:
```cpp
if(PreparedPlant && event->button()==Qt::LeftButton)
{
Shovel::isMovePlant = 0;
int i = ((int)event->scenePos().x() - 250) / 80;
int j = ((int)event->scenePos().y() - 100) / 90;
if(i == 9) --i; if(j == 5) --j;
qDebug()<< i << j; //以上都是计算准备种植的位置
if(!PlantMap[i][j]) // 如果这个位置没被其他植物占用
{
QPointF plantPos(290+80*i, 145+90*j);
switch(PreparedPlant->No)//根据卡牌序号,生成新的植物对象
{
case 0: PlantMap[i][j] = new Sunflower(plantPos); break;
case 1: PlantMap[i][j] = new Peashooter(plantPos); break;
........................
default: break;
}
PlantMap[i][j]->setZValue(j);
scene()->addItem(PlantMap[i][j]);
PreparedPlant->isPlanted = 1; //告诉卡牌我已经被种植了,意味着可以开始你的冷却动画了
PreparedPlant->counter = 0; //开始进行冷却等待
PreparedPlant->StartMode = 0;
PreparedPlant->sunTotal -= PreparedPlant->sunNeed;
PreparedPlant = nullptr; //记录准备植物的变量清空,等待下一次卡牌被点击时被赋予新的值
QApplication::restoreOverrideCursor(); //光标出栈,恢复光标形状
}
}
```
其实铲子的功能也是同样的原理,这里不说了。
### 2. 卡牌Cards
`Cards`主要完成的任务有:
- 显示卡牌的各种状态
- 判断并接收玩家的点击事件,并改变光标形状
- 存储玩家的阳光点数
基类`Cards`包含以下变量:
```
int No, sunNeed;// 植物编号;植物所需的阳光点数
int counter; // 计时器,
int coolTime; // 冷却时间
QString name; // 植物名字
bool isPlanted, StartMode; // 记录是否被种植;记录是否是游戏开始,这个是干嘛的后面再说
static int sunTotal; // 玩家现有的阳光点数,静态成员变量
```
paint函数实现了卡牌绘制和冷却效果:
```cpp
void Cards::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option);
Q_UNUSED(widget);
QImage image(":/graphics/Cards/card_" + name.toLower() + ".png");
painter->drawImage(boundingRect(), image); //画出卡牌
if(sunTotal < sunNeed) //情况一:当阳光点数不足以购买植物时,画禁止点击的矩形
{
painter->setBrush(QColor(128, 128, 0, 200));
painter->drawRect(boundingRect());
}
if(counter < coolTime && !StartMode && isPlanted) //情况二:未到冷却时间,画冷却效果
// 注意,游戏开始时不需要冷却效果,如果没有StartMode来判断游戏是否开始,那游戏一开始就会跑冷却效果,就没法购买植物了;同时,要真的种了植物才能跑冷却,如果没有种不需要冷却效果
{
painter->setBrush(QColor(0, 0, 0, 200));
painter->drawRect(QRectF(425+60*No, 10, 50, 70*(1-qreal(counter)/coolTime)));
}
}
```
这个函数实现了鼠标点击事件:
```cpp
void Cards::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(event->button()==Qt::LeftButton) //如果卡牌被点击
{ //如果阳光足够,且已达到冷却时间
if(sunTotal >= sunNeed && (counter == coolTime || StartMode)){
QCursor cursor(QPixmap(":/graphics/Plants/" + name + "/0.gif"));//改变鼠标光标为对应植物光标
QApplication::setOverrideCursor(cursor);
Map::PreparedPlant = this;//告诉地图,我接下来可能要种植这株植物了
}
}
}
```
最后,派生类继承了这些函数,并初始化自己的变量,例如:
```cpp
sunflower::sunflower()
{
name = "SunFlower"; coolTime = 227; No = 0;
sunNeed = 50; tip = "向日葵(50)";
}
```
### 3. 植物Plant
基类`Plant`包含以下变量:
```
enum { Type = UserType + 1}; //植物类型记作1
int HP; //血量
int ATK; //攻击力
int posX, posY; //位置
QString name; //植物名字
QMovie *movie; //动画
```
基类`Plant`包含以下函数(前三个之前说过,不说了):
```
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
void advance(int phase);
int type() const; // 返回类型,这个作用就是,
// 是植物的就返回植物类型(记作1),是僵尸的就返回僵尸类型(记作2),以此类推
```
为什么没有`collidesWithItem()`?因为大部分植物的确不需要碰撞检测,一般碰撞发出者是僵尸。比如向日葵、豌豆射手是不需要碰撞检测的,但是樱桃炸弹、土豆地雷这些是需要的,因为它是碰撞发出者。
以下两个成员函数位于基类,凡是植物,没有特殊要求的,都默认执行这两个函数:
```
QRectF Plant::boundingRect() const
{
return QRectF(180, 0, 64, 70);
}
void Plant::paint(QPainter *painter, const QStyleOptionGraphicsItem
没有合适的资源?快使用搜索试试~ 我知道了~
基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip
共198个文件
gif:85个
png:42个
cpp:30个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 95 浏览量
2023-08-26
16:19:34
上传
评论
收藏 3.99MB ZIP 举报
温馨提示
基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。 基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip 该项目是个人大作业项目源码,评审分达到95分以上,都经过严格调试,确保可以运行!放心下载使用。基于QT开
资源推荐
资源详情
资源评论
收起资源包目录
基于QT开发的植物大战僵尸游戏源码(高分C++期末大作业).zip (198个子文件)
maingame.cpp 4KB
paperzombie.cpp 4KB
conezombie.cpp 4KB
footballzombie.cpp 4KB
commonzombie.cpp 3KB
screenzombie.cpp 3KB
map.cpp 3KB
cards.cpp 2KB
potatomine.cpp 2KB
cherrybomb.cpp 2KB
sun.cpp 2KB
zombie.cpp 1KB
pea.cpp 1KB
menu.cpp 1KB
wallnut.cpp 1KB
car.cpp 1KB
quit.cpp 1KB
selectbox.cpp 961B
repeater.cpp 876B
startbutton.cpp 867B
pause.cpp 845B
finishtip.cpp 810B
peashooter.cpp 761B
sunflower.cpp 759B
snowpea.cpp 745B
shovel.cpp 739B
widgettest.cpp 723B
battletip.cpp 610B
plant.cpp 541B
main.cpp 312B
LostHeadWalk1.gif 140KB
ScreenDoorZombie.gif 98KB
HeadWalk1.gif 98KB
HeadWalk1.gif 94KB
1.gif 93KB
SunFlower.gif 82KB
Zombie2(有问题).gif 78KB
ConeheadZombie.gif 72KB
LostHeadWalk1.gif 72KB
1.gif 71KB
Zombie1.gif 65KB
2.gif 65KB
HeadWalk0.gif 61KB
LostHeadAttack1.gif 60KB
ZombieAttack.gif 58KB
Zombie3.gif 56KB
HeadAttack1.gif 53KB
ScreenDoorZombieAttack.gif 53KB
Boom.gif 53KB
1.gif 52KB
LostNewspaper.gif 51KB
FootballZombie.gif 51KB
BucketheadZombie.gif 50KB
FootballZombieOrnLost.gif 47KB
OrnLost.gif 47KB
HugeWallNutRoll.gif 46KB
FootballZombieAttack.gif 46KB
Attack.gif 46KB
OrnLostAttack.gif 46KB
FootballZombieOrnLostAttack.gif 46KB
BucketheadZombieAttack.gif 45KB
1.gif 43KB
Sun.gif 42KB
3.gif 42KB
LostHeadWalk0.gif 42KB
ZombieLostHead.gif 41KB
ConeheadZombieAttack.gif 40KB
1.gif 40KB
SunFlower2.gif 39KB
HeadAttack1.gif 38KB
LostHead.gif 37KB
LostHeadAttack.gif 37KB
1.gif 36KB
Die.gif 34KB
HeadAttack0.gif 30KB
LostHeadAttack1.gif 29KB
ZombieLostHeadAttack.gif 28KB
1.gif 28KB
1.gif 27KB
Wallnut_cracked2.gif 27KB
1.gif 25KB
Die.gif 24KB
1.gif 21KB
ZombieDie.gif 21KB
1.gif 20KB
BoomDie.gif 20KB
LostHeadAttack0.gif 20KB
BoomDie.gif 20KB
BoomDie.gif 19KB
Head.gif 17KB
1.gif 16KB
ZombieHead.gif 15KB
Wallnut_cracked1.gif 14KB
WallNutRoll.gif 14KB
PotatoMine.gif 12KB
BoomWallNutRoll.gif 12KB
0.gif 7KB
2.gif 7KB
0.gif 5KB
0.gif 5KB
共 198 条
- 1
- 2
资源评论
盈梓的博客
- 粉丝: 6842
- 资源: 1247
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功