文章目录

  • 前言
    • 创建cmake 俩条指令
  • 环境
  • 实现需要的前置知识
  • 实现思路
    • 文件架构
    • 场景类
    • 僵尸类
    • 植物类
    • 阳光类
    • 子弹类
    • 卡片类
    • 汽车类
    • 数据保存
    • 主游戏逻辑
  • 总结

前言

  • gitee仓库链接 : 链接点击跳转
  • 视频演示: 链接点击跳转

创建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 callbackvoid 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 manuallyCREATE_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 cardcard1->sprite_init("SunFlower", Vec2(135, 555));this->addChild(card1->sprite, 2);card_date.push_back(card1);PeashooterCard* card2 = new PeashooterCard;   //peashooter cardcard2->sprite_init("PeaShooter", Vec2(185, 555));this->addChild(card2->sprite, 2);card_date.push_back(card2);WallNutCard* card3 = new WallNutCard;     //wallnut cardcard3->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_shootvirtual 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_shootvirtual 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文件含有后缀_defaultvirtual 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.0void 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 0void 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  不可生成 :falsebool 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; // getPositionXvirtual double get_y() const;virtual void set_crash(); // 设置为判断virtual bool judge_crash(); // crash judgement, if ture, delete the bulletvirtual 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 scaleis_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 scalethis->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,// 太阳花 0card_type_Peashooter,//豌豆射手 1card_type_WallNut, //坚果 2card_type_CherryBomb, //樱桃炸弹 3card_type_Squash // 窝瓜 4
};//卡片的图像大小为64*90class 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*90class 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; // 获取坐标xyvirtual double get_x() const; //相关函数 getPOsitionX / Yvirtual 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;
} // 获取二维坐标Vec2double Car::get_x() const {return sprite->getPositionX();
} //相关函数 getPOsitionX / Ydouble 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();) {//遍历植物  执行植物的相应攻击动作// 太阳花 就产生 太阳   豌豆就 生成子弹  //结合switchif ((*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_crashif (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; //如果状态为deadzombie_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 4temp_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 falseauto 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推送的冲突解决都让我受益良多,很充实的一段经历,也是我第一次写这么大的项目,大一结束了,暑假过完就大二了,还要继续努力!!
结语 : 天亮未亮,步履不停

【C++项目】基于Cocos2d-x 4.0的 植物大战僵尸 Plants vs Zombies相关推荐

  1. C++开源游戏推荐,植物大战僵尸(Cocos2dx开源项目)

    声明:项目非本人原创,仅仅分享链接! 声明:项目非本人原创,仅仅分享链接! 声明:项目非本人原创,仅仅分享链接! 原创请参见: C++ 重制植物大战僵尸(Cocos2dx开源项目)_尔灵尔亿的博客-C ...

  2. java设计建议植物大战僵尸_基于Java的游戏设计之植物大战僵尸

    植物大战僵尸这款游戏相信大家或多或少都玩过,那么大家有没有想过自己尝试着做一下植物大战僵尸的游戏设计呢.本文将基于Java语言为大家展示如何开发出植物大战僵尸游戏的简易版本,主要内容包括规则.对象.功 ...

  3. 植物大战僵尸 1.0 简体中文版

    植物大战僵尸是由PopCap Games开发的一款益智策略类单机游戏,玩家通过武装多种植物切换不同的功能,快速有效地把僵尸阻挡在入侵的道路上.不同的敌人,不同的玩法构成五种不同的游戏模式,加之黑夜.浓 ...

  4. 基于浪潮“源1.0”的AI反诈项目:看高智商AI如何反杀诈骗犯

    近日,B站一位开发者UP主基于开源大模型"源1.0",开发了一个能够无障碍进行微信聊天的人工智能"小源",并在与骗子的真实对话场景中进行测试,破解"杀 ...

  5. 图文并茂使用CocosBuilder制作Cocos2D游戏 分享0

    图文并茂使用CocosBuilder制作Cocos2D游戏  分享0 目 录 The Game 设置工程 创建动画类型的主界面 本文由Zynga 工程师原创,翻译:Iven,张作宸,Butterfly ...

  6. EMAIL发送系统(C#+基于SMTP认证) 2.0

    这个是对于 EMAIL发送系统(C#+基于SMTP认证) 1.0 的改版这个第一版是2002年11月写的,过了一年半了,才有人提意见,就修正了一下,因为后来做的项目一直用不上,也就没有注意到 前段时间 ...

  7. 开源项目-基于Intel VT技术的Linux内核调试器

    本开源项目将硬件虚拟化技术应用在内核调试器上,使内核调试器成为VMM,将操作系统置于虚拟机中运行,即操作系统成为GuestOS,以这样的一种形式进行调试,最主要的好处就是调试器对操作系统完全透明.如下 ...

  8. 如何调用DLL (基于Visual C++6.0的DLL编程实现)

    如何调用DLL (基于Visual C++6.0的DLL编程实现) http://www.programfan.com/article/showarticle.asp?id=2923 一.前言 自从微 ...

  9. iKcamp出品|全网最新|微信小程序|基于最新版1.0开发者工具之初中级培训教程分享...

    ?? 微信小程序课程,面向所有具备前端基础知识的同学 ?? iKcamp官网:http://www.ikcamp.com 访问官网更快阅读全部免费分享课程:<iKcamp出品|全网最新|微信小程 ...

最新文章

  1. R语言编写自定义函数自定义ggplot图像中的图例(legend)的位置、图例标题、键值、文本字体大小(title、text、key)、颜色标识的大小、点形状pch的大小
  2. phpstudy-5.6.27-nts  安装redis扩展
  3. php面试题2018
  4. Spring依赖注入–字段vs设置器vs构造函数注入
  5. OCI runtime exec failed: exec failed:解决方法
  6. CentOS 7 安装Mono 和 MonoDevelop
  7. 计算机网络成绩分析单,【计算机网络论文】计算机网络技术课程教考分离解析(共2033字)...
  8. DEV 实现CheckBox单选
  9. matlab gui界面设计 打开文件,matlab GUI界面设计 点击按钮加载.mat数据的所有变量到工作空间中...
  10. java image 提取色彩通道_Java:从BufferedImage中提取Alpha通道
  11. Waterfall Header Bidding机制
  12. SpringBoot2.0.X使用Redis连接池Lettuce踩坑
  13. L1-040 最佳情侣身高差
  14. Linux、MacOS本地调用STF远程设备(stf.sh、stf-connect.js、stf-disconnect.js)
  15. 西工大-网安学院-2021复试-面试题目
  16. 在计算机系统内部使用的汉子编码是,数据库系统工程师考试汉字编码输入码
  17. 软工1816 · 团队现场编程实战(抽奖系统)
  18. 基于JAVA邢台市公寓式月亮酒店管理系统计算机毕业设计源码+系统+数据库+lw文档+部署
  19. gitlab-ce搭建和数据迁移
  20. VS2022修改模板文件

热门文章

  1. Question | 标注下数据、训练个模型,商用的智能鉴黄有这么简单吗?
  2. Java的单分派与双分派以及访问者模式的关系
  3. 双十一频繁弹窗,一招解决
  4. ixgbe网卡驱动(一)
  5. MySQL的索引(普通索引、唯一索引,主键索引、组合索引、全文索引、空间索引)相关操作
  6. 手把手的教你用MapABC的地图API制作自己的免费地图
  7. flv.js 是一个使用纯JavaScript编写的FLV(HTML5 Flash Video)播放器
  8. MBA-day5数学-应用题-工程问题
  9. 图形类的实现(java)
  10. 《查理·芒格传》精髓:查理芒格传奇的一生及背后的投资逻辑。