
前言
创建cmake 俩条指令
cocos new PlantsVsZombies -l cpp -p com.test.games // 在空文件下输入cmd
cmake .. -G "Visual Studio 17 2022" -AWin32 // 在proj.win32 目录下输入cmd
环境
实现需要的前置知识
- C++语法: 面向对象 、 stl的vector 和 string 、 auto、指针 , 需要有一定的c++语言基础
- cocos2d:类的继承、节点和精灵 场景这些继承关系、调度函数、回调函数、一些基本操作,plist 文件的使用。
实现思路
把cocos2d 的部分 和 代码逻辑分开 ,采用面向对象的模式
文件架构
场景类
场景类:登录、注册、加载、主菜单、帮助、声音设置、游戏选择植物、游戏、胜利、失败、 鼠标层
界面这里放游戏界面的 , 比较有难度
GameScene.h
#ifndef __GAME_SCENE_H__
#define __GAME_SCENE_H__
#include "Other//PlantsVsZombies.h"
#include "cocos2d.h"
using namespace cocos2d;
#include "ui/CocosGUI.h"
using namespace ui;
class GameScene : public cocos2d::Scene {
public:
//PlantVsZombies* plants_vs_zombies;
static cocos2d::Scene* createScene();
virtual void update(float update_time);
virtual bool init();
void init_data();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
bool onTouchBegan(Touch* touch, Event* unused_event);
void onTouchMoved(Touch* touch, Event* unused_event);
void onTouchEnded(Touch* touch, Event* unused_event);
int row_plant_cnt(int row_); // 获取这一路的植物数量。
void plant_down(int row_, int col_, PlantType plant_type);
void plant(int row_, int col_, PlantType plant_type);
Sprite* mouse_sprite;
PlantType selete_plant_type;
// implement the "static create()" method manually
CREATE_FUNC(GameScene);
Label* sun_label;
};
#endif // __HELLOWORLD_SCENE_H__
GameScene.cpp
#include "Scene/GameScene.h"
#include "AudioEngine.h"
#include "Other/Data.h"
#include "Scene/GameOverScene.h"
#include "Scene/GameVictorScene.h"
USING_NS_CC;
PlantVsZombies* plants_vs_zombies = new PlantVsZombies;
static int numofsum = 0; //存储阳光数量
Scene* GameScene::createScene() {
return GameScene::create();
}
// on "init" you need to initialize your instance
bool GameScene::init() {
if (!Scene::init()) {
return false;
}
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
AudioEngine::stopAll();
//音乐播放
AudioEngine::preload("Music/game.mp3");
auto game_BGM = AudioEngine::play2d("Music/game.mp3", true);
this->init_data();
//鼠标 监听事件
auto listener = EventListenerTouchOneByOne::create();
listener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(GameScene::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);
//创建背景图 并且设置坐标为左起点
auto background_sprite = Sprite::create("Games/bg1.jpg");
background_sprite->setPosition(visibleSize.width / 2.0f + 150.0f, visibleSize.height / 2.0f);
background_sprite->setScale(1.32f);
this->addChild(background_sprite, 0);
卡片与阳光框 Sprite对象
auto card_bar_sprite = Sprite::create("Games/ChooserBackground.png");
card_bar_sprite->setPosition(Vec2(visibleSize.width / 2.0f - 160.0f, visibleSize.height / 2.0f + 120.0f));
card_bar_sprite->setScale(1.3f);
background_sprite->addChild(card_bar_sprite, 1);
//覆盖初始阳光
auto card_bar_sprite2 = Sprite::create("Games/sunNum.png");
card_bar_sprite2->setPosition(Vec2(visibleSize.width / 2.0f - 320.0f, visibleSize.height / 2.0f + 100.0f));
card_bar_sprite2->setScale(1.3f);
background_sprite->addChild(card_bar_sprite2, 2);
// 阳光数量
sun_label = Label::createWithSystemFont(std::to_string(numofsum), "TypeFace/Marker Felt.ttf", 15);
sun_label->setPosition(Vec2(visibleSize.width / 2.0f - 320.0f, visibleSize.height / 2.0f + 100.0f));
background_sprite->addChild(sun_label, 3);
sun_label->setColor(Color3B::BLACK);
sun_label->setString(std::to_string(sun_total)); //用于动态修改阳光数量
// 卡片槽 Menu对象
// 铲子 Menu对象
/* auto shovelMenu = MenuItemImage::create("Games/shovel.png", "Games/shovel.png", CC_CALLBACK_1(GameScene::menuCloseCallback, this));
auto ShovelMenu = Menu::create(shovelMenu, NULL);
ShovelMenu->setPosition(visibleSize.width * 0.63f, visibleSize.height * 0.92f);
this->addChild(ShovelMenu, 1);*/
// 确认 Menu对象
//场景绑定
plants_vs_zombies->init_scene(this);
this->addChild(plants_vs_zombies);
//汽车创建
for (int i = 0; i < 5; i++) {
Car* temp_car = new Car;
temp_car->sprite_init(Vec2(car_positon[i]));
temp_car->sprite->setScale(1.8f);
plants_vs_zombies->addChild(temp_car->sprite);
temp_car->row = i; //设置为第n行
car_date.push_back(temp_car);
}
SunFlowerCard* card1 = new SunFlowerCard; //sunflower card
card1->sprite_init("SunFlower", Vec2(135, 555));
this->addChild(card1->sprite, 2);
card_date.push_back(card1);
PeashooterCard* card2 = new PeashooterCard; //peashooter card
card2->sprite_init("PeaShooter", Vec2(185, 555));
this->addChild(card2->sprite, 2);
card_date.push_back(card2);
WallNutCard* card3 = new WallNutCard; //wallnut card
card3->sprite_init("WallNut", Vec2(235, 555));
this->addChild(card3->sprite, 2);
card_date.push_back(card3);
auto sp1 = Sprite::create("Games/loading/timerBar2.png");
auto sp3 = Sprite::create("Games/loading/FlagMeterLevelProgress.png");
auto load_bar = ProgressTimer::create(Sprite::create("Games/loading/timerBar1.png")); // 加入进度条精灵
sp1->setScale(2);
sp3->setScale(2);
load_bar->setScale(2);
sp3->setPosition(Vec2(800, 30));
//三个默认设置 一般不改
load_bar->setType(ProgressTimer::Type::BAR); //方向
load_bar->setBarChangeRate(Vec2(1, 0));
load_bar->setMidpoint(Vec2(0, 0));
load_bar->runAction(ProgressFromTo::create(75, 0, 100)); // 时间 起点百分百 终点百分比
load_bar->setPosition(Vec2(800, 15));
sp1->setPosition(Vec2(800, 15));
this->addChild(load_bar, 3);
this->addChild(sp1, 2);
this->addChild(sp3, 2);
plants_vs_zombies->create_sun(300, 300);
/*auto sp_g1 = Sprite::create("Games/loading/LargeWave.png");
auto sp_g2 = Sprite::create("Games/loading/FinalWave.png");
sp_g1->setPosition(visibleSize.width / 2, visibleSize.height / 2);
sp_g2->setPosition(visibleSize.width / 2, visibleSize.height / 2);
sp_g1->setScale(4);
sp_g1->setVisible(false);
this->addChild(sp_g1 , 4);
sp_g2->setScale(2);
sp_g1->setVisible(false);
this->addChild(sp_g2, 4);*/
this->scheduleUpdate();
return true;
}
void GameScene::init_data() {
auto visibleSize = Director::getInstance()->getVisibleSize();
//坐标初始化
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 9; j++) {
float ii = 0.15f * i + 0.15f, jj = 0.21f + j * 0.09f;
plant_position[i][j] = Vec2(visibleSize.width * jj, visibleSize.height * ii);
}
}
//僵尸坐标初始 下标代表row 保证起点不同 出发的时间不同
zombie_positon[0] = Vec2(1400, visibleSize.height * (0.15f));
zombie_positon[1] = Vec2(1300, visibleSize.height * (0.15f * 1 + 0.17f));
zombie_positon[2] = Vec2(1000, visibleSize.height * (0.15f * 2 + 0.17f));
zombie_positon[3] = Vec2(1000, visibleSize.height * (0.15f * 3 + 0.20f));
zombie_positon[4] = Vec2(1200, visibleSize.height * (0.15f * 4 + 0.20f));
car_positon[0] = Vec2(visibleSize.width * 0.12f, visibleSize.height * (0.15f));
car_positon[1] = Vec2(visibleSize.width * 0.12f, visibleSize.height * (0.15f * 1 + 0.17f));
car_positon[2] = Vec2(visibleSize.width * 0.12f, visibleSize.height * (0.15f * 2 + 0.17f));
car_positon[3] = Vec2(visibleSize.width * 0.12f, visibleSize.height * (0.15f * 3 + 0.20f));
car_positon[4] = Vec2(visibleSize.width * 0.12f, visibleSize.height * (0.15f * 4 + 0.20f));
}
bool bg1 = false, bg2 = false;
void GameScene::update(float update_time) {
if (plants_vs_zombies->is_pass_time2 && !bg1) {
auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
bg1 = true;
/* auto sp_g1 = Sprite::create("Games/loading/LargeWave.png");
sp_g1->setPosition(visibleSize.width / 2, visibleSize.height / 2);
sp_g1->setScale(4);
sp_g1->setOpacity(254);
this->addChild(sp_g1, 4);
auto fadeOut = FadeOut::create(1.0f);
sp_g1->runAction(Sequence::create(DelayTime::create(2),RemoveSelf::create()));*/
auto game_BGM = AudioEngine::play2d("Music/finalwave.ogg", false);
}
if (plants_vs_zombies->is_pass_time3 && !bg2 ) {
auto visibleSize = Director::getInstance()->getVisibleSize();
bg2 = true;
auto game_BGM = AudioEngine::play2d("Music/awooga.ogg", false);
/* auto sp_g2 = Sprite::create("Games/loading/FinalWave.png");
sp_g2->setPosition(visibleSize.width / 2, visibleSize.height / 2);
sp_g2->setScale(2);
this->addChild(sp_g2, 4);*/
}
for (auto& it : card_date) {
if (it->judge_cd()) { // 如果在cd状态
it->time_count += update_time;
if (it->card_cd <= it->time_count) {
it->set_is_cd(false);
it->time_count = 0.0;
}
}
}
if (plants_vs_zombies->is_game_fail == true) { // 判断游戏失败
zombie_date.clear();
plant_date.clear();
bullet_date.clear();
card_date.clear();
car_date.clear();
sun_date.clear();
for (auto& it : plant_judge_position)
{
for (auto& elem : it)
{
elem = false;
}
}
//delete plants_vs_zombies;
sun_total = 50;
Director::getInstance()->replaceScene(GameOverScene::create());
plants_vs_zombies = new PlantVsZombies();
}
if (plants_vs_zombies->is_game_success == true) { // 判断游戏胜利
zombie_date.clear();
plant_date.clear();
bullet_date.clear();
card_date.clear();
car_date.clear();
sun_date.clear();
for (auto& it : plant_judge_position)
{
for (auto& elem : it)
{
elem = false;
}
}
sun_total = 50;
Director::getInstance()->replaceScene(GameVictorScene::create());
plants_vs_zombies = new PlantVsZombies();
}
}
void GameScene::menuCloseCallback(Ref* pSender) {
Director::getInstance()->end();
}
bool GameScene::onTouchBegan(Touch* touch, Event* unused_event) {
auto touch_position = touch->getLocation();
for (auto& it : sun_date) {//这里查看鼠标点击位置是否有阳光
if (it->judge_delete()) continue;
double width_ = it->sprite->getContentSize().width / 2;
double height_ = it->sprite->getContentSize().height / 2;
Vec2 SunPosition_ = it->sprite->getPosition();
auto offset_ = SunPosition_ - touch_position;
if ((fabs(offset_.x) <= width_) && (fabs(offset_.y) <= height_)) { //说明鼠标点击位置是阳光所在位置
sun_total += 50;
it->run_sun_collect_animation();
this->sun_label->setString(to_string(sun_total));
return true;
}
}
//这里查看鼠标点击的位置是不是植物卡片的位置
for (auto& it : card_date) {
if (it->judge_cd() || mouse_sprite != nullptr) continue;
double width_ = it->sprite->getContentSize().width / 2;
double height_ = it->sprite->getContentSize().height / 2;
Vec2 card_positon = it->sprite->getPosition();
auto offset_ = card_positon - touch_position;
if ((fabs(offset_.x) <= width_) && (fabs(offset_.y) <= height_)) {
switch (it->card_type) {
case CardType::card_type_Peashooter:
{
Peashooter* pe = new Peashooter;
mouse_sprite = pe->run_plant_animation(it->sprite->getPosition());
this->addChild(mouse_sprite, 1);
selete_plant_type = PlantType::Peashooter;
break;
}
case CardType::card_type_SunFlower:
{
SunFlower* pe = new SunFlower;
mouse_sprite = pe->run_plant_animation(it->sprite->getPosition());
this->addChild(mouse_sprite, 1);
selete_plant_type = PlantType::SunFlower;
break;
}
case CardType::card_type_WallNut:
{
WallNut* pe = new WallNut;
mouse_sprite = pe->run_plant_animation(it->sprite->getPosition());
this->addChild(mouse_sprite, 1);
selete_plant_type = PlantType::WallNut;
break;
}
default: {
break;
}
}
return true;
}
}
return false;
}
void GameScene::onTouchMoved(Touch* touch, Event* unused_event) {
if (mouse_sprite != nullptr && selete_plant_type != PlantType::plant_type_none) {
int row_, col_;
mouse_sprite->setPosition(touch->getLocation());
if (plants_vs_zombies->judge_vec2_in_row_col(touch->getLocation(), row_, col_)) { //判断鼠标是否在草地区域
if (plant_judge_position[row_][col_] == false) mouse_sprite->setPosition(plant_position[row_][col_]);
else {
mouse_sprite->setPosition(touch->getLocation());
}
}
else {
mouse_sprite->setPosition(touch->getLocation());
}
}
}
void GameScene::onTouchEnded(Touch* touch, Event* unused_event) {
if (mouse_sprite != nullptr && selete_plant_type != PlantType::plant_type_none) {
int row_, col_;
if (plants_vs_zombies->judge_vec2_in_row_col(touch->getLocation(), row_, col_)) {//鼠标位置在坑中
if (plants_vs_zombies->judge_plant(row_, col_) == false) {
plant_down(row_, col_, selete_plant_type);
}
}
selete_plant_type = PlantType::plant_type_none;
}
this->removeChild(mouse_sprite);
mouse_sprite = nullptr;
}
//种植 + 判断
void GameScene::plant_down(int row_, int col_, PlantType plant_type_) {
if (plant_judge_position[row_][col_] == true) return;
//根据类型 获取卡片对象
Card* temp_card = nullptr;
int idx = -1;
switch (plant_type_) {
case PlantType::SunFlower:
{
temp_card = card_date[0]; // 太阳花卡片
idx = 0;
break;
}
case PlantType::Peashooter:
{
temp_card = card_date[1]; // 豌豆卡片
idx = 1;
break;
}
case PlantType::WallNut:
{
temp_card = card_date[2]; // 坚果卡片
idx = 2;
break;
}
default:
break;
}
if (!temp_card->judge_cd()) { //不在冷却时间
//判断当前的阳光是否足够种植该植物
if (sun_total >= temp_card->sun_cost) { //阳光足够
sun_total -= temp_card->sun_cost;
this->sun_label->setString(to_string(sun_total));
card_date[idx]->set_is_cd(true); // 设置卡片为cd状态
card_date[idx]->init_card_cd_animation();
plant(row_, col_, plant_type_);
AudioEngine::play2d("Music/plant2.ogg", false);
return;
}
}
//plant(row_, col_, plant_type_);
}
void GameScene::plant(int row_, int col_, PlantType plant_type) {
if (plant_judge_position[row_][col_])
{
return;
}
plant_judge_position[row_][col_] = true;
//float cow_to_x[9] = { 0.21 , 0.30 , 0.39 , 0.49 , 0.58 , 0.67 , 0.755 , 0.84 , 0.94 };
//float row_to_y[5] = { 0.15 , 0.30 , 0.46 , 0.63 , 0.79 };
//int x_position = Director::getInstance()->getVisibleSize().width * cow_to_x[col_];
//int y_position = Director::getInstance()->getVisibleSize().height * row_to_y[row_];
Plant* temp_push = NULL;
switch (plant_type)
{
case PlantType::SunFlower:
temp_push = new SunFlower();
this->addChild(temp_push->run_plant_animation(plant_position[row_][col_]));
temp_push->set_plant_type(PlantType::SunFlower);
break;
case PlantType::WallNut:
temp_push = new WallNut();
this->addChild(temp_push->run_plant_animation(plant_position[row_][col_]));
temp_push->set_plant_type(PlantType::WallNut);
break;
case PlantType::Peashooter:
temp_push = new Peashooter();
this->addChild(temp_push->run_plant_animation(plant_position[row_][col_]));
temp_push->set_plant_type(PlantType::Peashooter);
break;
default:
break;
}
plant_date.emplace_back(temp_push);
}
int row_plant_cnt(int row_) {
int cnt = 0;
for (auto& it : plant_date) {
if (it->get_row() != row_) continue;
else cnt++;
}
return cnt;
} // 获取这一路的植物数量。
僵尸类
- 采用继承, 可以节省很多代码量
ZombieBase.h
#ifndef ZOMBIEBASE_H_
#define ZOMBIEBASE_H_
#include "cocos2d.h"
#include "Plant/PlantBase.h"
using namespace cocos2d;
enum ZombieType {
zombie_type_none = -1,
zombie_type_normal , // 普通僵尸
zombie_type_conehead,// 锥形头盔僵尸
zombie_type_buckethead,// 铁桶僵尸
zombie_type_flag //旗帜僵尸
// Other Zombie
};
//class Plant;
class Zombie :public Sprite {
public:
Zombie() = default;
~Zombie() = default;
virtual void zombie_init();// 变量初始化
void sprite_init(const Vec2& position_);//精灵初始化
virtual void set_scale(float val_);// 设置精灵的大小
virtual Vec2 get_position() const;
virtual double get_x();
virtual double get_y();
virtual int get_blood() const;
virtual int get_attack_time() const;
virtual int get_attack_num() const;
virtual double get_move_rate() const;
//加载动作
virtual void init_zombie_move_animation();
virtual void init_zombie_eat_animation();
virtual void init_zombie_wait_animation();
virtual void init_zombie_die_animation();
//运行动作
virtual bool run_zombie_move_animation();
virtual void run_zombie_eat_animation();
virtual void run_zombie_wait_animation();
virtual void run_zombie_die_animation();
//设置状态
virtual bool judge_eat() const;
virtual bool judge_dead() const;
virtual bool judge_move() const;
virtual bool judge_wait() const;
//变量
static int zombie_id; // 僵尸编号 唯一性
double blood; // 血量
double attack_time;// 间隔攻击时间
double time_count;// 时间计时器 统计使用精灵 到结束
double attack_num; //攻击值
float move_rate; // 移速
Vec2 position;//二维位置 变量
Sprite* sprite;// 精灵变量
//动作变量
Animate* zombie_move_animate;
Animate* zombie_eat_animate;
Animate* zombie_wait_animate;
Animate* zombie_die_animate;
Vector<SpriteFrame*> zombie_wait;
Vector<SpriteFrame*> zombie_move;
Vector<SpriteFrame*> zombie_eat;
Vector<SpriteFrame*> zombie_die;
//僵尸类型 enum 结合switch遍历
ZombieType zombie_type;
//僵尸状态变量
bool is_move;//僵尸是否处于行走状态
bool is_eat;//僵尸是否处于攻击状态
bool is_dead;//僵尸是否已经死亡
bool is_wait;//僵尸是否处于等待进攻状态
int row;
};
#endif // ZOMBIEBASE_H_
ZombieBase.cpp
#include "Zombie/ZombieBase.h"
int Zombie::zombie_id;
void Zombie::zombie_init() {
}// 变量初始化
// 精灵初始化 参数1 精灵图片名字 参数2 : 二维坐标名字
void Zombie::sprite_init( const Vec2& position_) {
sprite->setPosition(position_);
}
// 设置精灵的大小 参数:缩放倍数
void Zombie::set_scale(float val_) {
sprite->setScale(val_);
}
//获取二维坐标
Vec2 Zombie::get_position() const {
return position;
}
//获取二维坐标的X
double Zombie::get_x() {
return sprite->getPositionX();
}
//获取二维坐标的Y
double Zombie::get_y() {
return sprite->getPositionY();
}
//获取当前僵尸血量
int Zombie::get_blood() const {
return blood;
}
//获取当前僵尸的攻击间隔时间
int Zombie::get_attack_time() const {
return attack_time;
}
//获取攻击值
int Zombie::get_attack_num() const {
return attack_num;
}
//设置移动速度
double Zombie::get_move_rate() const {
return move_rate;
}
//virtual void attack_plant(Plant & plant_); //攻击植物 使植物掉血
// 创建 僵尸移动动画
void Zombie::init_zombie_move_animation() {
}
//创建 僵尸吃植物动画
void Zombie::init_zombie_eat_animation() {
}
//创建僵尸等待动画
void Zombie::init_zombie_wait_animation() {
}
//僵尸 死亡动画
void Zombie::init_zombie_die_animation() {
}
//时间开销分析
//就是额外构造俩对象的开销,不用从内存读数据,和原有的代码差不多
bool Zombie::run_zombie_move_animation() {
if (is_dead) return false ;
if (sprite == nullptr || zombie_move_animate == nullptr) return false ;
is_dead = false;
is_eat = false;
is_move = true;
is_wait = false;
sprite->stopAllActions();
sprite->runAction(RepeatForever::create(
Animate::create(Animation::createWithSpriteFrames(zombie_move, 1.0 / 10)))); // 运行移动动画
sprite->runAction(MoveTo::create(5.0f,Vec2(-100.0,get_y()))); // 可修改移动速度
}
void Zombie::run_zombie_eat_animation() {
if (sprite == nullptr || zombie_move_animate == nullptr) return;
this->is_dead = false;
this->is_eat = true;
this->is_move = false;
this->is_wait = false;
sprite->stopAllActions();
sprite->runAction(RepeatForever::create(
Animate::create(Animation::createWithSpriteFrames(zombie_eat, 1.0 / 4))));;
}
void Zombie::run_zombie_wait_animation() {
if (is_dead) return;
if (sprite == nullptr || zombie_move_animate == nullptr) return;
is_dead = false;
is_eat = false;
is_move = false;
is_wait = true;
sprite->stopAllActions();
sprite->runAction(RepeatForever::create(
Animate::create(Animation::createWithSpriteFrames(zombie_eat, 1.0 / 5))));
}
void Zombie::run_zombie_die_animation() {
if (sprite == nullptr || zombie_move_animate == nullptr) return;
//auto delayt = DelayTime::create(3);
is_dead = true;
is_eat = false;
is_move = false;
is_wait = false;
sprite->stopAllActions();
sprite->runAction(
Animate::create(Animation::createWithSpriteFrames(zombie_die, 1.0 / 2)));
sprite->runAction(Sequence::create(DelayTime::create(2.0f), Blink::create(2.0f, 5),RemoveSelf::create(), nullptr));
removeFromParent();
}
//判断状态
bool Zombie::judge_eat() const {
return is_eat;
}
bool Zombie::judge_dead() const {
return is_dead;
}
bool Zombie::judge_move() const {
return is_move;
}
bool Zombie::judge_wait() const {
return is_wait;
}
- 普通僵尸实现 其他的僵尸类似
NormalZombie.h
#ifndef _NOMALZOMBIE_H_
#define _NOMALZOMBIE_H_
#include "cocos2d.h"
#include "Zombie/ZombieBase.h"
using namespace cocos2d;
//class Plant;
class NormalZombie : public Zombie{
public:
NormalZombie();
~NormalZombie() = default;
virtual void update(float update_time); //调度函数 参数调度时间间隔
virtual void zombie_init();// 变量初始化
//重写基类动画
virtual void init_zombie_move_animation() ;
virtual void init_zombie_eat_animation();
virtual void init_zombie_wait_animation();
virtual void init_zombie_die_animation(); //僵尸死亡动画
static bool is_run_frame; //用于判断是否加载帧动画了 防止重复加载
Vector<SpriteFrame*> getAnimation(const char* format, int count);
};
#endif // ZOMBIEBASE_H_
NormalZombie.cpp
#include "cocos2d.h"
#include "Zombie/NormalZombie.h"
#include "AudioEngine.h"
using namespace cocos2d;
bool NormalZombie::is_run_frame = false; // 已经初始化 构造函数不用
//构造函数 调用 init函数 然后加载四个init动画
NormalZombie::NormalZombie() {
//类属性初始化
this->zombie_init();
this->init_zombie_move_animation();
this->init_zombie_die_animation();
this->init_zombie_eat_animation();
this->init_zombie_wait_animation();
sprite = Sprite::create();
sprite->setScale(1.6f);
sprite->runAction(RepeatForever::create(zombie_wait_animate));
is_run_frame = true;
//执行调度器
this->scheduleUpdate();
}
void NormalZombie::update(float update_time) {
time_count += update_time;
//auto move_sound = AudioEngine::play2d("Music/.ogg", true);//没有
//auto eat_sound = AudioEngine::play2d("Music/chomp.ogg", true);
if (is_dead) {
this->unscheduleUpdate();
removeFromParent();
}
} //调度函数 参数调度时间间隔
void NormalZombie::zombie_init() {
this->zombie_id = -1; // 僵尸编号
this->blood = 10; // 血量
this->attack_time = 2.0;// 间隔攻击时间
this->time_count = 0.0;// 时间计时器 统计使用精灵 到结束
this->attack_num = 100; //攻击值
this->move_rate = 0; // 移速 相对于移动时间
this->zombie_type = ZombieType::zombie_type_normal; //僵尸类型
this->is_move = false;//僵尸是否处于行走状态
this->is_eat = false;//僵尸是否处于攻击状态
this->is_dead = false;//僵尸是否已经死亡
this->is_wait = false;//僵尸是否处于等待进攻状
}// 变量初始化
void NormalZombie::init_zombie_move_animation() {
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ZomBies/NomalZombie/ZombieMove/Zombie_default.plist");
zombie_move = getAnimation("Zombie%d.png", 30); // 调用加载图片
sprite = Sprite::createWithSpriteFrame(zombie_move.front());
auto animation1 = Animation::createWithSpriteFrames(zombie_move, 1.0 / 10); // 缓存时间 约小则加载越快
zombie_move_animate = Animate::create(animation1);
}
void NormalZombie::init_zombie_eat_animation() {
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ZomBies/NomalZombie/ZombieAttack/ZombieAttack_default.plist");
zombie_eat = getAnimation("ZombieAttack%d.png", 20); // 调用加载图片
//sprite = Sprite::createWithSpriteFrame(frames.front());
auto animation1 = Animation::createWithSpriteFrames(zombie_eat, 1.0 / 4); // 缓存时间 约小则加载越快
zombie_eat_animate = Animate::create(animation1);
}
void NormalZombie::init_zombie_die_animation() {
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ZomBies/NomalZombie/ZombieDie/ZombieDie_default.plist");
zombie_die = getAnimation("ZombieDie%d.png", 9); // 调用加载图片
//sprite = Sprite::createWithSpriteFrame(frames.front());
auto animation1 = Animation::createWithSpriteFrames(zombie_die, 1.0f / 2); // 缓存时间 约小则加载越快
zombie_die_animate = Animate::create(animation1);
}
void NormalZombie::init_zombie_wait_animation() {
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ZomBies/NomalZombie/ZombieMove/Zombie_default.plist");
zombie_wait = getAnimation("Zombie%d.png", 5); // 调用加载图片
//sprite = Sprite::createWithSpriteFrame(frames.front());
auto animation1 = Animation::createWithSpriteFrames(zombie_wait, 1.0 / 5); // 缓存时间 约小则加载越快
zombie_wait_animate = Animate::create(animation1);
}
Vector<SpriteFrame*> NormalZombie::getAnimation(const char* format, int count) {
auto spritecache = SpriteFrameCache::getInstance();
Vector<SpriteFrame*> animFrames;
char str[100];
for (int i = 1; i <= count; i++) {
sprintf(str, format, i);
animFrames.pushBack(spritecache->getSpriteFrameByName(str));
}
return animFrames;
}
植物类
PlantBase.h
#ifndef _PLANTBASE_H_
#define _PLANTBASE_H_
#include "Bullet/Bullet.h"
#include "Card/Card.h"
#include "cocos2d.h"
using namespace cocos2d;
#include <string>
enum class PlantType {
plant_type_none = -1,
SunFlower,// 太阳花
Peashooter,//豌豆射手
WallNut, //坚果
CherryBomb, //樱桃炸弹
Squash // 窝瓜
};
class Plant : public Sprite {//基类
public:
Plant() = default; //继承后请同样直接在构造函数内部调用init函数,
//获取数据函数将不在保证无法访问未初始化数据,该功能由构造函数承担
~Plant() = default;
virtual void plant_init(); // 初始化 数据
virtual Sprite* sprite_init(const Vec2& position_); // 精灵初始化 在初始化精灵前请先初始化动画
virtual void set_blood(int val); // 设置血量
virtual void set_time_count(int val);//设置时间间隔
virtual void add_interval_time(float time_); //设置触发技能频率
virtual void set_plant_type(PlantType type);//设置植物的种类
virtual void set_is_plan();//设置是否种植
virtual void set_is_shoot(bool val);//设置is_shoot
virtual void set_scale(float val_);//设置大小
virtual void set_interval_time(float val);//增加间隔时间
virtual void set_rate_time(float val);
virtual Vec2 get_position() const; // 获取坐标
virtual double get_x() const; // 获取X 坐标
virtual double get_y() const; // 获取Y 坐标
virtual PlantType get_type() const; // 获取植物类型
virtual int get_blood() const;//获取当前血量
virtual bool get_is_shoot(); //获取当前is_shoot
virtual void by_attack(int val_);//遭受攻击后扣除血量
virtual float get_rate_time();//获取触发速率
virtual float get_interval_time();//获取间隔时间
virtual int get_row();//获取列
virtual int get_line();//获取行
virtual void init_plant_animation(); // 加载植物动画
virtual void set_plant_animation(Animate*); //获取植物动画
virtual Sprite* run_plant_animation(Vec2 position); // 运行植物动画动画
virtual Animate* get_plant_animate();//获取植物动画
virtual void load_animation(std::string pre_path, int number, cocos2d::Vector<cocos2d::SpriteFrame*>& res);//加载动画
//如果想使用该函数,必须保证.plist文件含有后缀_default
virtual void set_start_frame(SpriteFrame* frame); //设置第一帧
virtual void set_is_shoot(double delta);
virtual void do_action();
virtual Sprite* get_sprite();
protected:
private:
//变量
int blood; //生命值
bool is_plant; // 判断是否种植
Vec2 position; // 坐标
Sprite* sprite; // 精灵
PlantType plant_type;//植物类型变量
Animate* plant_animate; //植物动画变量
Animate* plant_down_animate; // 种植动画
SpriteFrame* start_frame; //第一帧动画
float interval_time;//距离上一次发射的时间
public:
bool is_shoot;//是否发射子弹的标志
double rate_time; //触发技能速率
double time_count;// 时间计时器 统计使用精灵 到结束
int row;
int line;
};
#endif // _PLANTBASE_H_
PlantBase.cpp
#include "Plant/PlantBase.h"
#include "Other/Data.h"
#include <string>
#include <iostream>
#include <exception>
void Plant::plant_init() {
}// 初始化 数据 为默认值
void Plant::set_plant_animation(Animate* animation)
{
this->plant_animate = animation;
return;
}
Animate* Plant::get_plant_animate()
{
return this->plant_animate;
}
void Plant::set_blood(int val_)
{
this->blood = val_;
}
void Plant::set_time_count(int val_)
{
this->time_count = val_;
}
void Plant::set_plant_type(PlantType p)
{
this->plant_type = p;
}
void Plant::set_is_plan()
{
this->is_plant = false;
}
Sprite* Plant::sprite_init(const Vec2& position_) {
Size show_range = Director::getInstance()->getVisibleSize();
//float x_to_line[9] = { 0.21 , 0.30 , 0.39 , 0.49 , 0.58 , 0.67 , 0.755 , 0.84 , 0.94 };
//float y_to_row[5] = { 0.15 , 0.30 , 0.46 , 0.63 , 0.79 };
//float x_range = show_range.width;
//float y_range = show_range.height;
//for(int i = 0 ; i < 9 ; i++)
//{
// if (position_.x <= x_range * x_to_line[i])
// {
// this->line = i; // 从0开始
// break;
// }
//}
//for (int i = 0; i < 5; i++)
//{
// if (position.y <= y_range * y_to_row[i])
// {
// this->row = i; // 从0开始
// break;
// }
//}
for (int i = 0; i < 5; i++)
{
for (int j = 0; j < 9; j++)
{
if (plant_position[i][j] == position_)
{
this->line = j;
this->row = i;
}
}
}
sprite = Sprite::createWithSpriteFrame(this->start_frame);
sprite->setPosition(position_);
this->position = position_;
return this->sprite;
} // 精灵初始化
Vec2 Plant::get_position() const {
return this->position;
} // 获取坐标
double Plant::get_x() const {
return this->position.x;
} // 获取X 坐标
double Plant::get_y() const {
return this->position.y;
}// 获取Y 坐标
PlantType Plant::get_type() const {
return this->plant_type;
} // 获取植物类型
int Plant::get_blood() const {
return this->blood;
}//获取当前血量
//设置攻击间隔 变量time_为攻击时间间隔
void Plant::set_rate_time(float time_) {
this->rate_time = time_;
}//设置触发技能频率
void Plant::set_interval_time(float time_)
{
this->interval_time = time_;
}
//我感觉不太对
//提供重载版本
//设置当前植物的精灵大小为val_
void Plant::set_scale(float val_)
{
this->sprite->setScale(val_);
return;
}
void Plant::init_plant_animation() {
//return this->plant_animate;
} //植物动画
void Plant::by_attack(int val_) {
blood -= val_;
}
void Plant::load_animation(std::string path, int number, cocos2d::Vector<cocos2d::SpriteFrame*>& res)
{
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(path);
auto sprite_cache = SpriteFrameCache::getInstance();
int pos_path = path.size();
int pos_end = pos_path;
while (path[pos_path] != '/')
{
if (path[pos_path] == '_')
pos_end = pos_path;
pos_path--;
}
pos_path++;
std::string pre = path.substr(pos_path, (pos_end - pos_path));
for (int i = 1; i <= number; i++)
{
std::string test = pre + std::to_string(i) + ".png";
auto temp = sprite_cache->getSpriteFrameByName(pre + std::to_string(i) + ".png");
res.pushBack(temp);
}
return;
}
void Plant::set_is_shoot(bool val)
{
this->is_shoot = val;
}
bool Plant::get_is_shoot()
{
return this->is_shoot;
}
void Plant::set_start_frame(SpriteFrame* frame)
{
this->start_frame = frame;
return;
}
//间隔时间增加
void Plant::add_interval_time(float val)
{
this->interval_time += val;
}
//返回间隔时间
float Plant::get_interval_time()
{
return this->interval_time;
}
float Plant::get_rate_time()
{
return (float)this->rate_time;
}
void Plant::do_action()
{
}
Sprite* Plant::run_plant_animation(Vec2 position)
{
this->init_plant_animation();
auto sptite = this->sprite_init(position);
sptite->runAction(RepeatForever::create(this->get_plant_animate()));
this->set_scale(1.85);
return sprite;
}
int Plant::get_row()
{
return this->row;
}
int Plant::get_line()
{
return this->line;
}
void Plant::set_is_shoot(double delta)
{
this->add_interval_time(delta);
int temp2 = this->get_interval_time();
int temp = this->get_rate_time();
if (this->get_interval_time() > this->get_rate_time())
{
this->set_interval_time(0);
this->set_is_shoot(true);
}
}
Sprite* Plant::get_sprite()
{
return this->sprite;
}
SunFlower.h
#ifndef SUNFLOWER_H
#define SUNFLOWER_H
#include "Plant/PlantBase.h"
class SunFlower :public Plant
{
public:
SunFlower();
~SunFlower() = default;
//初始化僵尸的属性(处理精灵 和动画外的 把基类的搬过来) 然后写在构造函数里面
virtual void plant_init();
//调度函数 参数:调度时间间隔
virtual void update(float update_time);
virtual void init_plant_animation(); // 种下后的植物动画
virtual void init_plant_down_animation(); //植物种植动画并且加上声音
static bool is_run_frame;// 用于判断是否加入帧动画了 防止调度重复加载
};
#endif // !SUNFLOWER_H
SunFlower.cpp
#include "Plant/SunFlower.h"
#include "Other/PlantsVsZombies.h"
#include <functional>
bool SunFlower::is_run_frame = false;//初始化为false 这个不用写init里面
//构造函数 调用init 然后 初始化动作
SunFlower::SunFlower() {
this->plant_init();
}
//初始化植物的属性(处理精灵 和动画外的 把基类的搬过来) 然后写在构造函数里面
//属性未修改
//在此修改属性
#define SUNFLOWER_BLOOD 300
#define SUNFLOWER_RATE_TIME 10.0
#define SUNFLOWER_TIME_COUNT 0.0
void SunFlower::plant_init() {
//is_shoot = true;
this->set_blood(SUNFLOWER_BLOOD);
this->set_is_plan();
this->set_plant_type(PlantType::SunFlower);
this->set_rate_time(SUNFLOWER_RATE_TIME);
this->set_time_count(SUNFLOWER_TIME_COUNT);
}
//调度函数 参数:调度时间间隔
void SunFlower::update(float update_time) {
if (this->get_blood() <= 0)
{
//当前植物将被删除
removeFromParent();
this->unscheduleUpdate();
}
}
void SunFlower::init_plant_animation() {
cocos2d::Vector<cocos2d::SpriteFrame*> res;
this->load_animation("Plants/SunFlower/SunFlower_default.plist",18, res);
this->set_start_frame(res.front());
auto animation = Animation::createWithSpriteFrames(res, 1.0f / 8);
this->set_plant_animation(Animate::create(animation));
return;
} // 种下后的植物动画
void SunFlower::init_plant_down_animation() {
} //植物种植动画并且加上声音
Peashooter.h
#ifndef PEASHOOTER_H
#define PEASHOOTER_H
#include "Plant/PlantBase.h"
class Peashooter :public Plant {
public:
Peashooter();
~Peashooter() = default;
//初始化僵尸的属性(处理精灵 和动画外的 把基类的搬过来) 然后写在构造函数里面
virtual void plant_init();
//调度函数 参数:调度时间间隔
virtual void update(float update_time);
virtual void init_plant_animation(); // 种下后的植物动画
static bool is_run_frame;// 用于判断是否加入帧动画了 防止调度重复加载
};
#endif // !SUNFLOWER_H
Peashooter.cpp
#include "Plant/Peashooter.h"
#include "Other/PlantsVsZombies.h"
bool Peashooter::is_run_frame = false;//初始化为false 这个不用写init里面
//构造函数 调用init 然后 初始化动作
Peashooter::Peashooter() {
this->plant_init();
//动作加载
is_run_frame = true;
//调度函数
}
//初始化植物的属性(处理精灵 和动画外的 把基类的搬过来) 然后写在构造函数里面
#define PEASHOOTER_BLOOD 300
#define PEASHOOTER_RATE_TIME 1.5f
#define PEASHOOTER_TIME_COUNT 0
void Peashooter::plant_init() {
this->set_blood(PEASHOOTER_BLOOD);
this->set_is_plan();
this->set_plant_type(PlantType::WallNut);
this->set_rate_time(PEASHOOTER_RATE_TIME);
this->set_time_count(PEASHOOTER_TIME_COUNT);
this->set_is_shoot(false);
this->set_interval_time(0);
}
//调度函数 参数:调度时间间隔
void Peashooter::update(float update_time) {
if (this->get_blood() < 0)
{
//删除植物
removeFromParent();
this->unscheduleUpdate();
}
else
{
this->set_interval_time(update_time);
if (this->get_interval_time() > this->get_rate_time())
{
this->set_interval_time(-this->get_interval_time());
this->set_is_shoot(true);
}
}
}
void Peashooter::init_plant_animation() {
cocos2d::Vector<cocos2d::SpriteFrame*> res;
this->load_animation("Plants/Peashooter/Peashooter_default.plist", 13, res);
this->set_start_frame(res.front());
auto animation = Animation::createWithSpriteFrames(res, 1.0f / 8);
this->set_plant_animation(Animate::create(animation));
// 把动作复制给变量
} // 植物动画
阳光类
Sun.h
#ifndef _SUN_H_
#define _SUN_H_
#include <iostream>
#include <vector>
using namespace std;
#include "cocos2d.h"
#include "Plant/PlantBase.h"
using namespace cocos2d;
class Sun : public Sprite{
public:
Sun();
~Sun() = default;
void sun_init(); // 初始化
virtual void update(float update_time); //调度函数
void sprite_init( const Vec2& position_);
// 精灵初始化 参1:精灵图片名字 参2:设置的二维坐标
void init_sun_produce_animation(); // ̫太阳生成动画
void init_sun_collect_animation(); // 太阳收集动画 moveto到初始化的位置
void run_sun_produce_animation(); // ̫运行太阳生成动画
void run_sun_collect_animation(); // 运行太阳收集动画 moveto到初始化的位置
void run_sun_delete_animation();
void set_is_delete(); // 设置为可删除
void set_is_produce(); // 设置为可生成
bool judge_prodece(); // 判断能否生成
bool judge_delete(); // 判断能否删除
int time_count;// 计时器 用于调度函数
Animate* sun_produce_animate; // 生成动画变量
MoveTo * sun_collect_animate; // 收集动画变量
Sprite* sprite;
Vec2 position;
int sun_num; // ̫太阳值
double sun_time; // 太阳保留时间
Vector<SpriteFrame*> Sun::getAnimation(const char* format, int count);
private:
bool is_delete; // 可以删除 :true 不可生成 :false
bool is_produce; //可以生成 : true 不可生成 : false
};
#endif // _SUM_H_
Sun.cpp
#include "Sun.h"
Sun::Sun() {
//调用init 动作初始化
this->init_sun_produce_animation();
this->sun_init();
sprite = Sprite::create();
sprite->runAction(RepeatForever::create(sun_produce_animate));
this->scheduleUpdate();
}
void Sun::sun_init() {
sun_num = 50;
sun_time = 0; //太阳保留时间
is_delete = false;
is_produce = false;
time_count = 0;
} // 初始化函数
//修改系统的时间调度函数
//参数 update_time 是系统调用该函数 的间隔时间
void Sun::update(float update_time) {
//time_count += update_time;
if (judge_delete()) {
//run_sun_delete_animation();
this->unscheduleUpdate();
}
} //调度函数
// 精灵初始化函数 参1 :图片名字 参2 : 二维坐标
void Sun::sprite_init(const Vec2& position_) {
//sprite = Sprite::create("Sums/Sun3.png");
sprite->setPosition(position_); // 随机生成
}
// 创建太阳生成动画
void Sun::init_sun_produce_animation() {
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("Plants/Sun/Sun_default.plist"); //22
auto frames = getAnimation("Sun%d.png", 8); // 调用加载图片
sprite = Sprite::createWithSpriteFrame(frames.front());
auto animation1 = Animation::createWithSpriteFrames(frames, 1.0f / 8); // 缓存时间 约小则加载越快
sun_produce_animate = Animate::create(animation1);
}
//创建太阳收集动画 未完善
void Sun::init_sun_collect_animation() {
sun_collect_animate = MoveTo::create(0.5f,Vec2(100,200));
}
void Sun::run_sun_produce_animation() {
sprite->runAction(RepeatForever::create(sun_produce_animate));
} // ̫运行太阳生成动画
void Sun::run_sun_collect_animation() {
this->sprite->runAction(MoveTo::create(2.0, Vec2(67, 560)));
auto seq = Sequence::createWithTwoActions(DelayTime::create(2.2f), RemoveSelf::create());
this->sprite->runAction(seq);
this->is_delete = true;
this->unscheduleUpdate();
}
void Sun::run_sun_delete_animation() {
auto seq = Sequence::createWithTwoActions(Blink::create(2.0, 5), RemoveSelf::create());
sprite->runAction(seq);
this->is_delete = true;
this->unscheduleUpdate();
}
//设置为可删除
void Sun::set_is_delete() {
is_delete = true;
}
//设置为可生成
void Sun::set_is_produce() {
is_produce = true;
}
bool Sun::judge_prodece() {
return is_produce;
} // 判断能否生成
bool Sun::judge_delete() {
return is_delete;
} // 判断能否删除
Vector<SpriteFrame*> Sun::getAnimation(const char* format, int count) {
auto spritecache = SpriteFrameCache::getInstance();
Vector<SpriteFrame*> animFrames;
char str[100];
for (int i = 1; i <= count; i++) {
sprintf(str, format, i);
animFrames.pushBack(spritecache->getSpriteFrameByName(str));
}
return animFrames;
}
子弹类
Bullet.h
#ifndef BULLET_H
#define BULLET_H
#include "cocos2d.h"
#include "Zombie/ZombieBase.h"
#include "Plant/PlantBase.h"
#include "AudioEngine.h"
using namespace cocos2d;
class Bullet : public Sprite {
public:
Bullet();//构造函数
~Bullet() = default;
virtual void bullet_init();// 初始化函数
virtual void update(double update_time); // 调度函数 参数:调度间隔时间
virtual void bullet_move_animation(); //创建子弹移动动画
//精灵初始化 参1 图片名字 参2:二维坐标
void sprite_init(const Vec2& position_);
virtual Vec2 get_position() const; // 获取二维坐标
virtual double get_x() const; // getPositionX
virtual double get_y() const;
virtual void set_crash(); // 设置为判断
virtual bool judge_crash(); // crash judgement, if ture, delete the bullet
virtual void set_attack_num(double damage);// 设置子弹伤害
virtual void delete_sprite(); // 删除精灵
int row;
//变量
Vec2 position; // 二维坐标
Sprite* sprite; //精灵变量
double attack_num; // 攻击伤害
bool is_crash; // 是否碰撞 true:碰撞 false:未碰撞
Animate* bullet_move_animate; // 子弹移动动作变量
};
#endif // _BULLET_H_
Bullet.cpp
#include "Bullet/Bullet.h"
// 子弹变量 初始化
//构造函数
Bullet::Bullet() {
//调用init函数
//调用精灵初始化函数 并且赋值
sprite = Sprite::create();
sprite->setScale(2);
//调用动作初始化函数 并且赋值
bullet_init();
this->scheduleUpdate();
}
void Bullet::bullet_init() {
attack_num = 1; // damage scale
is_crash = false; // 判断是否碰撞变量
}
//精灵初始化 参1 精灵图片名字 参2 二维坐标
// 精灵图 使用 豌豆的 大小设置为1 位置
void Bullet::sprite_init(const Vec2& position_) {
sprite = Sprite::create("Bullet/PeaBullet0.png");
sprite->setPosition(position_);
position = position_;
}
//修改系统的时间调度函数
//参数 update_time 是系统调用该函数 的间隔时间
void Bullet::update(double update_time) {
//状态 如果is_crash 为true 则删除子弹 并且产生碰撞音效
} //
//创建子弹移动动画
void Bullet::bullet_move_animation() {
//auto bullet_movement = MoveTo::create(2.0f, Vec2(1000,position.y)); // Position of the leftmost zombie in that row
//sprite->setScale(1.0f);
//auto bullet_move_animate = Sequence::create(bullet_callback_audio, bullet_movement, nullptr);
sprite->runAction(MoveTo::create(4.0f, Vec2(1000, position.y)));
}
//获取二维坐标
Vec2 Bullet::get_position() const {
return position;
}
//获取精灵 x坐标
double Bullet::get_x() const {
return sprite->getPositionX();
}
//获取精灵 y 坐标
double Bullet::get_y() const {
return sprite->getPositionY();
}
// 判断是否碰撞
bool Bullet::judge_crash() {
return is_crash;
}
//设置碰撞
void Bullet::set_crash() {
is_crash = true;
}
//设置 攻击伤害 参数:子弹伤害
void Bullet::set_attack_num(double plant_damage) {// damage scale
this->attack_num = plant_damage;
}
//删除 精灵 is_crash 变量执行 未完善
void Bullet::delete_sprite() {
if (is_crash) {
this->removeChild(this, true); // "this" stands for bullet object
}
}
卡片类
Card.h
#ifndef CARD_H
#define CARD_H
#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "Plant/PlantBase.h"
using namespace cocos2d;
using namespace ui;
enum class CardType{
card_type_none = -1,
card_type_SunFlower,// 太阳花 0
card_type_Peashooter,//豌豆射手 1
card_type_WallNut, //坚果 2
card_type_CherryBomb, //樱桃炸弹 3
card_type_Squash // 窝瓜 4
};
//卡片的图像大小为64*90
class Card : public Sprite{
public:
Card() = default;
~Card() = default;
virtual void card_init();//初始化函数
Sprite* sprite_init(const std::string& name_, const Vec2& position_);
Sprite* cd_sprite_init(const std::string& name_, const Vec2& position_);
virtual void init_card_cd_animation(); // 卡片冷却动画
virtual void init_card_move_animation(const Vec2& destination_); // 卡片点击后卡片移动到已选传送带内 : 选择界面
virtual void set_is_choose(const bool& state_); //设置状态 参数为状态
virtual void set_is_cd(const bool& state_);
virtual bool judge_choose();
virtual bool judge_cd();
Rect getRect(); //获取卡片所占范围
double card_cd; // 卡片冷却时间
double time_count;// 时间计时器 统计使用精灵
int sun_cost; // 太阳值费用
bool can_choose; //能被选中
CardType card_type;
Sprite* sprite; // 固定的精灵
Sprite* cd_sprite; // 冷却的精灵
FadeIn* card_cd_animate; // 卡片冷却动画
MoveTo* card_move_animate; // 卡片点击后卡片移动到已选传送带内 : 选择界面
bool is_choose; // 是否被选择了 该参数只用于左上角显示精灵
bool is_cd; // 判断 是否 要进入cd状态
};
#endif // !CARD_H_
Card.cpp
#include "Card/Card.h"
void Card::card_init() {
}//初始化函数
Sprite* Card::sprite_init(const std::string& name_, const Vec2& position_) {
sprite = Sprite::create("/Cards/" + name_ + ".png");
sprite->setPosition(position_);
return sprite;
} // 精灵初始化
Sprite* Card::cd_sprite_init(const std::string& name_, const Vec2& position_) {
cd_sprite = Sprite::create("/Cards/" + name_ + ".png");
cd_sprite->setPosition(position_);
return cd_sprite;
}
void Card::init_card_cd_animation() {
} // 卡片冷却动画
void Card::init_card_move_animation(const Vec2& destination_/*const std::string& name_, const Vec2& destination_*/) {
auto card_move_to = MoveTo::create(0.1, destination_);
this->runAction(card_move_to);
} // 卡片点击 移动到 已选框内 选择界面
void Card::set_is_choose(const bool& state_) {
is_choose = state_;
} // 设置已选
void Card::set_is_cd(const bool &state_) {
is_cd = state_;
}
bool Card::judge_choose() {
return is_choose;
}
bool Card::judge_cd() {
return is_cd;
}
by QZP20220815
Rect Card::getRect() {
float ori_x = this->sprite->getPosition().x - this->sprite->getContentSize().width * this->sprite->getAnchorPoint().x;
float ori_y = this->sprite->getPosition().y - this->sprite->getContentSize().height * this->sprite->getAnchorPoint().y;
float w = this->sprite->getContentSize().width;
float h = this->sprite->getContentSize().height;
return Rect(ori_x, ori_y, w, h);
} //获取卡片所占范围
SunFlower.h
#ifndef SUNFLOWERCARD_H
#define SUNFLOWERCARD_H
#include "cocos2d.h"
#include "ui/CocosGUI.h"
#include "Card/Card.h"
using namespace cocos2d;
using namespace ui;
//卡片的图像大小为64*90
class SunFlowerCard : public Card{
public:
SunFlowerCard();
virtual void update(float update_time); //调度函数
virtual void card_init();//初始化函数
virtual void init_card_cd_animation(); // 卡片冷却动画
};
#endif // !CARD_H_
SunFlower.cpp
#include "Card/SunFlowerCard.h"
SunFlowerCard::SunFlowerCard() {
this->card_init();
//this->sprite_init(sp_name,position); 初始化 先空着
//this->init_card_cd_animation(); // 加载动画
this->scheduleUpdate(); //启动调度函数
}
//调度函数 参数系统调用该函数的 间隔时间
void SunFlowerCard::update(float update_time) {
//this->time_count += update_time;
//if (judge_cd()) { //如果在cd
// this->init_card_cd_animation(); //播放冷却动画
// this->set_is_cd(false);
// this->time_count = 0; //开始计时
//}
//if (time_count >= card_cd + 0.1) { //0.1为卡片置为不可用动画的时间
// this->can_choose = true; //冷却动画完成,则卡片置为可选状态
//}
} //调度函数
void SunFlowerCard::card_init() {
card_cd = 10; //卡片冷却时间
time_count = 0;// 时间计时器 统计使用精灵
sun_cost = 50; // 太阳值费用
is_cd = false;// 判断 是否 进入cd状态
can_choose = true;
card_type = CardType::card_type_SunFlower;
}//初始化函数
void SunFlowerCard::init_card_cd_animation() {
//card_cd_animate 给 card 里面对应的动作变量赋值
/*auto card_cd1 = FadeOut::create(0.1);
auto card_cd2 = FadeIn::create(card_cd);
auto card_cd_seq = Sequence::create(card_cd1, card_cd2,nullptr);
this->sprite->runAction(card_cd_seq);*/
this->cd_sprite_init("SunFlowerCD", this->sprite->getPosition());
this->cd_sprite->setColor(Color3B::GRAY);
auto cd_sp_bar = ProgressTimer::create(this->cd_sprite);
cd_sp_bar->setPosition(this->sprite->getPosition()); //进度条生成在卡片位置
cd_sp_bar->setType(ProgressTimer::Type::BAR);
cd_sp_bar->setBarChangeRate(Vec2(0, 1));
cd_sp_bar->setMidpoint(Vec2(0, 1));
cd_sp_bar->runAction(ProgressFromTo::create(this->card_cd, 100, 0)); // 三个参数:时间 起点百分百 终点百分比
this->sprite->getParent()->addChild(cd_sp_bar, 3);
//card_cd_animate赋值?
} // 卡片冷却动画
汽车类
Car.h
#ifndef _CAR_H_
#define _CAR_H_
#include "cocos2d.h"
using namespace cocos2d;
class Car : public Sprite{
public:
Car();
~Car() = default;
virtual void update(float update_time);//调度函数
void sprite_init(const Vec2& position_);
void init_car_move_animation(); //汽车移动动画
Sprite* sprite; // 精灵
MoveTo* car_move_animate;
virtual Vec2 get_position() const; // 获取坐标xy
virtual double get_x() const; //相关函数 getPOsitionX / Y
virtual double get_y() const;
Vec2 position; // 位置
bool is_used; // 是否使用
int row;
};
#endif // _CAR_H_
Car.cpp
#include "Other/Car.h"
//构造函数
Car::Car() {
//调用init函数
is_used = false;
//调用精灵初始化函数 并且赋值
//sprite = Sprite::create();
//调用动作初始化函数 并且赋值
this->scheduleUpdate();// 启动调度函数
}
//修改系统的时间调度函数
//参数 update_time 是系统调用该函数 的间隔时间
void Car::update(float update_time) {
//for 循环遍历 判断每个车子是否使用
//如果使用就删去精灵
if (is_used) {
sprite->removeFromParentAndCleanup(true);
this->unscheduleUpdate(); //关闭调度函数
}
}
//精灵初始化 参数 二维坐标
void Car::sprite_init(const Vec2& position_) {
sprite = Sprite::create("Games/car.png");
sprite->setPosition(position_);
}
Vec2 Car::get_position() const {
return position;
} // 获取二维坐标Vec2
double Car::get_x() const {
return sprite->getPositionX();
} //相关函数 getPOsitionX / Y
double Car::get_y() const {
return sprite->getPositionY();
}
void Car::init_car_move_animation() {
//精灵动作 移动 该精灵的位置 到地图最右边
is_used = true;
car_move_animate = MoveTo::create(5, Vec2(2000, sprite->getPositionY()));
sprite->runAction(car_move_animate);
} //汽车移动动画
数据保存
Data.h
#ifndef DATE_H
#define DATE_H
#include <vector>
#include "Card/Card.h"
#include "Card/PeashooterCard.h"
#include "Card/SunFlowerCard.h"
#include "Card/WallNutCard.h"
#include "Other/Car.h"
#include "Other/Shovel.h"
#include "Other/User.h"
#include "Zombie/ZombieBase.h"
#include "Zombie/BucketheadZombie.h"
#include "Zombie/ConeheadZombie.h"
#include "Zombie/FlagZombie.h"
#include "Zombie/NormalZombie.h"
#include "Plant/PlantBase.h"
#include "Plant/Sun.h"
#include "Plant/Peashooter.h"
#include "Plant/SunFlower.h"
#include "Plant/WallNut.h"
#include "Bullet/Bullet.h"
extern std::vector<Zombie*> zombie_date;//用于保存已经创建的僵尸
extern std::vector<Plant*> plant_date;//用于保存已经创建的植物对象
extern std::vector<Bullet*> bullet_date;//用于保存已经创建的子弹对象
extern std::vector<Card*> card_date;//用于保存已经创建的卡片对象
extern std::vector<Car*> car_date;//用于保存已经创建的车对象
extern std::vector<Sun*> sun_date;//用于保存已经创建的阳光对象
extern int sun_total;//用于显示游戏中的阳光值
extern Vec2 plant_position[5][9];//用于保存各个二维坐标当中,植物的位置,5*9
extern bool plant_judge_position[5][9];//用于保存各个坐标当中,是否存在植物
extern Vec2 card_bar_position[4]; // 用于保存放在卡片栏的位置 暂时只弄四个 用于 图片的移动动画
extern Vec2 card_table_position[4]; // 用于保存卡片选择表的位置 暂时只弄四个
extern Vec2 zombie_positon[5]; // 用于记录僵尸五个起点
extern Vec2 car_positon[5]; // 用于保存五个车子的位置
#endif // !DATE_H
Data.cpp
#include "Other/Data.h"
#include <vector>
//保存数据 使用for + auto 进行遍历
std::vector<Zombie*> zombie_date;//用于保存已经创建的僵尸
std::vector<Plant*> plant_date;//用于保存已经创建的植物对象
std::vector<Bullet*> bullet_date;//用于保存已经创建的子弹对象
std::vector<Card*> card_date;//用于保存已经创建的卡片对象
std::vector<Car*> car_date;//用于保存已经创建的车对象
std::vector<Sun*> sun_date;//用于保存已经创建的车对象
int sun_total = 50;//用于显示游戏中的阳光值
Vec2 plant_position[5][9];//用于保存各个二维坐标当中,植物的位置,5*9
bool plant_judge_position[5][9];//用于保存各个坐标当中,是否存在植物
Vec2 card_bar_position[4]; // 用于保存放在卡片栏的位置 暂时只弄四个 用于 图片的移动动画
Vec2 card_table_position[4]; // 用于保存卡片选择表的位置 暂时只弄四个
Vec2 zombie_positon[5]; // 用于记录僵尸五个起点
Vec2 car_positon[5]; // 用于保存五个车子的位置
主游戏逻辑
PlantsVsZombies.h
#ifndef _PLANTSVSZOMBIES_H_
#define _PLANTSVSZOMBIES_H_
#include "Other/Data.h"
#include "AudioEngine.h"
#include "cocos2d.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
using namespace cocos2d;
using namespace ui;
// 僵尸vs植物 类 实现 僵尸的攻击 和 植物的各种攻击 和其他操作
class PlantVsZombies :public Node {
public:
PlantVsZombies(); // 构造函数
~PlantVsZombies() = default; //默认虚构
virtual void update(float update_time); //调度函数 计时器 实现第n波进攻 + 植物 (产生攻击 ) + 僵尸产生攻击 + 豌豆检测 + 阳光收集 +游戏失败
void init_data();//用于初始化 数据
void init_scene(Scene* scene_);//用于绑定场景,addChild 游戏场景:new一个节点PvsZ 然后 this->addchild(本节点)
Zombie* get_row_left_zombie(int row_);//获取在第row路最左边的僵尸
Plant* get_row_right_plant(int row_);//获取在第row行最右边的植物
virtual void peashooter_shoot(Plant* plant_);//豌豆射手发射一个豌豆
virtual void create_zombie(int row_, ZombieType type_);//在row行创建一个某种类型的僵尸
virtual void create_plant(int row_, int col_, PlantType type_);//在row行col列创建一个某种类型的植物
virtual bool judge_plant(int row_, int col_);//用于判断在row行col列是否可以种植植物 需要
virtual bool judge_vec2_in_row_col(Vec2 vec_position, int& row_, int& col_);//判断这个vec2坐标 鼠标点击的位置是不是在草地区域 结合鼠标使用种植植物
virtual void create_sun(int x_,int y_);//生成太阳 在 x y -》写到Vec里面
Scene* scene;//场景节点 用于添加到游戏场景
//时间变量 用于控制 对应时间段 僵尸的生成
double time1;
double time2;
double time3;
double time4;
double time5;
double time6;
double time7;
double time8;
// 判断是否经过了这个时间段了
bool is_pass_time1;
bool is_pass_time2;
bool is_pass_time3;
bool is_pass_time4;
bool is_pass_time5;
bool is_pass_time6;
bool is_pass_time7;
bool is_pass_time8;
double time_count;//用于计时,到达指定时间,生成对应波次的僵尸
double pruduce_time ; // 用于生成时间间隔 比如能被一个数整除就生成 time_count % produce == 0
bool is_game_fail;//判断游戏失败
bool is_game_success;//判断游戏是否获得胜利
};
#endif // !_PLANTSVSZOMBIES_H_
PlantsVsZombies.cpp
#include "Other/PlantsVsZombies.h"
PlantVsZombies::PlantVsZombies() {
this->init_data(); // 初始化数据
// 开启调度函数
//this->create_sun(500, 500);
this->scheduleUpdate();
} // 构造函数
void PlantVsZombies::init_data() {
time1 = 14;
time2 = 40;
time3 = 70;
time4 = 70;
time5 = 90;
time6 = 110;
time7 = 120;
time8 = 150;
// 判断是否经过了这个时间段了
is_pass_time1 = false;
is_pass_time2 = false;
is_pass_time3 = false;
is_pass_time4 = false;
is_pass_time5 = false;
is_pass_time6 = false;
is_pass_time7 = false;
is_pass_time8 = false;
time_count = 0.0;//用于计时,到达指定时间,生成对应波次的僵尸
pruduce_time = 0.0; // 生成僵尸的时间间隔 比如能被一个数整除就生成 time_count % produce == 0
is_game_fail = false;//判断游戏失败
is_game_success = false;//判断游戏是否获得胜利
//this->scheduleUpdate();
}//用于初始化 数据
void PlantVsZombies::update(float update_time) {
this->pruduce_time += update_time;
this->time_count += update_time;
// 第n波进攻
int rand_row = 0;
if (this->time_count >= time1 && !this->is_pass_time1) {
//生成僵尸
create_zombie(2, ZombieType::zombie_type_normal);
this->is_pass_time1 = true;
}
if (this->time_count >= time2 && !this->is_pass_time2) {
//生成僵尸
create_zombie(2, ZombieType::zombie_type_conehead);
create_zombie(3, ZombieType::zombie_type_flag);
create_zombie(4, ZombieType::zombie_type_buckethead);
this->is_pass_time2 = true;
}
if (this->time_count >= time3 && !this->is_pass_time3) {
create_zombie(2, ZombieType::zombie_type_conehead);
create_zombie(3, ZombieType::zombie_type_flag);
create_zombie(4, ZombieType::zombie_type_buckethead);
create_zombie(1, ZombieType::zombie_type_normal);
create_zombie(4, ZombieType::zombie_type_normal);
this->is_pass_time3 = true;
}
//if (this->time_count >= time4 && !this->is_pass_time4) {
// //生成僵尸
// create_zombie(5, ZombieType::zombie_type_normal);
// create_zombie(4, ZombieType::zombie_type_normal);
// create_zombie(3, ZombieType::zombie_type_flag);
// create_zombie(2, ZombieType::zombie_type_buckethead);
// create_zombie(1, ZombieType::zombie_type_conehead);
// this->is_pass_time4 = true;
//}
//if (this->time_count >= time5 && !this->is_pass_time5) {
// //生成僵尸
// create_zombie(5, ZombieType::zombie_type_normal);
// create_zombie(4, ZombieType::zombie_type_normal);
// create_zombie(2, ZombieType::zombie_type_buckethead);
// create_zombie(1, ZombieType::zombie_type_conehead);
// this->is_pass_time5 = true;
//}
//if (this->time_count >= time6 && !this->is_pass_time6) {
// //生成僵尸
// create_zombie(5, ZombieType::zombie_type_normal);
// create_zombie(4, ZombieType::zombie_type_normal);
// create_zombie(2, ZombieType::zombie_type_buckethead);
// create_zombie(1, ZombieType::zombie_type_conehead);
// this->is_pass_time6 = true;
//}
//if (this->time_count >= time7 && !this->is_pass_time7) {
// //生成僵尸
// create_zombie(2, ZombieType::zombie_type_normal);
// create_zombie(1, ZombieType::zombie_type_normal);
// create_zombie(4, ZombieType::zombie_type_buckethead);
// create_zombie(5, ZombieType::zombie_type_conehead);
// this->is_pass_time7 = true;
//}
//if (this->time_count >= time8 && !this->is_pass_time8) {
// //生成僵尸
// create_zombie(3, ZombieType::zombie_type_flag);
// create_zombie(5, ZombieType::zombie_type_conehead);
// create_zombie(4, ZombieType::zombie_type_buckethead);
// create_zombie(2, ZombieType::zombie_type_buckethead);
// create_zombie(1, ZombieType::zombie_type_conehead);
// this->is_pass_time8 = true;
//}
//遍历死亡
for (auto& it : zombie_date) {
if (it->is_dead) continue;
if (it->blood <= 0) {
it->run_zombie_die_animation();
//it->sprite->setPosition(10000, 0);
it->is_dead = true;
it->sprite = nullptr;
//it->sprite->runAction(RemoveSelf::create());
continue;
}
for (auto& ca : car_date) { // 当车子移动的时候遍历僵尸
int row_ = ca->row;
if (fabs(it->get_x() - ca->get_x()) <= 15 && ca->is_used && row_ == it->row) {
//ca->is_used = true;
it->blood = 0;
}
}
}
//遍历所有僵尸
for (auto& it : zombie_date) {
it->time_count += update_time;
if (it->is_dead) {
continue; // 如果僵尸死了
}
Plant* temp_plant = get_row_right_plant(it->row);
if (temp_plant != nullptr) {
if (it->time_count >= it->attack_time && fabs(it->get_x() - temp_plant->get_x()) <= 15) {
if (!it->is_eat) it->run_zombie_eat_animation();
temp_plant->by_attack(it->attack_num);
it->time_count = 0.0;
}
else {
if ((!it->judge_move() && fabs(it->get_x() - temp_plant->get_x()) >= 15 ) ) {
if(it->judge_eat())it->run_zombie_move_animation();
}
}
}
else if (it->judge_eat() ) {
it->run_zombie_move_animation();
}
}
for (auto it = plant_date.begin(); it != plant_date.end();) {
//遍历植物 执行植物的相应攻击动作
// 太阳花 就产生 太阳 豌豆就 生成子弹
//结合switch
if ((*it)->get_blood() <= 0)
{
plant_judge_position[(*it)->get_row()][(*it)->get_line()] = false;
(*it)->get_sprite()->removeFromParent();
(*it)->removeFromParent();
it = plant_date.erase(it);
continue;
}
(*it)->set_is_shoot(update_time);
if ((*it)->get_is_shoot() && (get_row_left_zombie((*it)->get_row()) != NULL || (*it)->get_type() == PlantType::SunFlower))
{
switch ((*it)->get_type())
{
case PlantType::SunFlower:
{
(*it)->time_count += update_time;
if ((*it)->time_count >= (*it)->rate_time) {
(*it)->time_count = 0.0;
this->create_sun((*it)->get_x() + 30, (*it)->get_y() + 30);
}
break;
}
case PlantType::Peashooter:
this->peashooter_shoot((*it));
break;
default:
break;
}
}
it++;
}
for (auto& it : bullet_date) {
//遍历所有子弹 如果碰撞了 就扣血 + 设置子弹为is_crash
if (it->judge_crash() || (get_row_left_zombie(it->row) == nullptr && !get_row_left_zombie(it->row)->is_dead)) continue;
if (get_row_left_zombie(it->row)->get_x() - it->sprite->getPositionX() <= 0) {
get_row_left_zombie(it->row)->blood -= it->attack_num;
it->set_crash();
this->removeChild(it->sprite);
}
}
for (auto& it : car_date) {
int row_ = it->row;
Zombie* temp_zombie = get_row_left_zombie(row_);
if (it->is_used || temp_zombie == nullptr) continue;
if (fabs(temp_zombie->get_x() - it->get_x()) <= 15) {
it->init_car_move_animation();
//it->is_used = true;
temp_zombie->blood = 0;
}
}
//执行生成阳光 根据间隔时间生成
if (pruduce_time >= 15.0) {
pruduce_time = 0.0;//置零
int rand_x = rand() % 500 + 100;
int rand_y = rand() % 600 + 200;
this->create_sun(rand_x, rand_y);
}
//阳光超过指定时间没有收集就删除
for (auto& it : sun_date) {
if (it->judge_delete()) continue;
if (it->sun_time >= 8.0) {
it->set_is_delete();
it->run_sun_delete_animation();
}
it->sun_time += update_time;
}
int zombie_cnt = 0;
//如果游戏结束了
for (auto& it : zombie_date) {
int x = it->row;
if (it->judge_dead()) continue; //如果状态为dead
zombie_cnt++;
if (it->sprite != nullptr && it->get_x() <= 0 && car_date[x] -> is_used ) {
is_game_fail = true;
break;
}
}
if (this->is_pass_time3 == true && zombie_cnt == 0) {
//如果最后一只僵尸死亡 游戏胜利
init_data();
is_game_success = true;
}
}
void PlantVsZombies::init_scene(Scene* scene_) {
scene = scene_;
}//用于绑定场景,addChild 游戏场景:new一个节点PvsZ 然后 this->addchild(本节点)
Zombie* PlantVsZombies::get_row_left_zombie(int row_) {
Zombie* left_zombie = nullptr;
double left = -1;
for (auto& it : zombie_date) {
if (it->row != row_ || it->is_dead) continue;
if (left == -1 || left >= it->get_x()) {
left = it->get_x();
left_zombie = it;
}
}
return left_zombie;
}//获取在第row路最左边的僵尸
Plant* PlantVsZombies::get_row_right_plant(int row_) {
Plant* right_plant = nullptr;
double right = -1.0;
for (auto& it : plant_date) {
if (it->row != row_ || it->get_blood() <= 0) continue;
if (right == -1 || right <= it->get_x()) {
right = it->get_x();
right_plant = it;
}
}
return right_plant;
}//获取在第row行最右边的植物
void PlantVsZombies::peashooter_shoot(Plant* plant_) {
Bullet* temp_bullet = new Bullet;
temp_bullet->sprite_init(plant_->get_position());
temp_bullet->bullet_move_animation();
this->addChild(temp_bullet->sprite, 2);
temp_bullet->row = plant_->row;
bullet_date.push_back(temp_bullet);
temp_bullet->setScale(2);
plant_->set_is_shoot(false);
}//豌豆射手发射一个豌豆
void PlantVsZombies::create_zombie(int row_, ZombieType type_) {
Zombie* temp_zombie;
switch (type_)
{
case zombie_type_normal:
{
temp_zombie = new NormalZombie();
break;
}
case zombie_type_conehead:
{
temp_zombie = new ConeheadZombie();
break;
}
case zombie_type_buckethead:
{
temp_zombie = new BucketheadZombie();
break;
}
case zombie_type_flag:
{
temp_zombie = new FlagZombie();
break;
}
default:
break;
}
temp_zombie->row = row_; // 0 1 2 3 4
temp_zombie->sprite_init(zombie_positon[row_]);
temp_zombie->run_zombie_move_animation();
this->addChild(temp_zombie->sprite, 3);
zombie_date.push_back(temp_zombie);
}//在row行创建一个某种类型的僵尸
void PlantVsZombies::create_plant(int row_, int col_, PlantType type_) {
plant_judge_position[row_][col_] = true;
}//在row行col列创建一个某种类型的植物
bool PlantVsZombies::judge_plant(int row_, int col_) {
return plant_judge_position[row_][col_];
}//用于判断在row行col列是否可以种植植物 需要
//判断这个vec2坐标 鼠标点击的位置是不是在草地区域 结合鼠标使用种植植物
bool PlantVsZombies::judge_vec2_in_row_col(Vec2 vec_position, int& _row, int& _col) {
//特判 :越界 if(越界) return false
auto visibleSize = Director::getInstance()->getVisibleSize();
if ((vec_position.x < visibleSize.width * 0.18) || (vec_position.x > visibleSize.width * 0.95)
|| (vec_position.y < visibleSize.height * 0.13) || (vec_position.y > visibleSize.height * 0.92)) return false;
int width_ = 125 / 2;
int height_ = 103 / 2;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 9; j++) {
Vec2 offset = vec_position - plant_position[i][j];
if ((fabs(offset.x) <= width_) && (fabs(offset.y) <= height_)) {
_row = i;
_col = j;
return true;
}
}
}
return false;
}
void PlantVsZombies::create_sun(int x_, int y_) {
Sun* temp_sun = new Sun;
temp_sun->sprite->setScale(1.5);
this->addChild(temp_sun->sprite, 5); //添加层数
sun_date.push_back(temp_sun);
temp_sun->sprite->setPosition(Vec2(x_ + 30, y_ + 30));
temp_sun->run_sun_produce_animation();
}//生成太阳 在 x y -》写到Vec里面
总结
用了大概20天的时间,和一群小伙伴完成了这个项目,这个项目代码感觉至少要个
4000
, debug 和git推送的冲突解决都让我受益良多,很充实的一段经历,也是我第一次写这么大的项目,大一结束了,暑假过完就大二了,还要继续努力!!
结语 : 天亮未亮,步履不停