cocos2dx 植物大战僵尸 15 豌豆射手的实现

2023-10-13 10:50

本文主要是介绍cocos2dx 植物大战僵尸 15 豌豆射手的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

豌豆射手类似于向日葵,只不过向日葵发动技能是产生阳光,而豌豆射手则是产生豌豆子弹罢了。

我只找到了上图的资源,所以在豌豆射手的状态改变则简单多了。

class Peashooter : public Plant
{SDL_SYNTHESIZE(int,m_nDamage,Damage);//伤害值
private:float m_elapsed;
public:Peashooter();~Peashooter();static Peashooter*create(const string&plantName);bool init(const string&plantName);virtual void updateHook(float dt);
protected:void shoot();
};
初始化函数和以前的类似,就不添加了

void Peashooter::updateHook(float dt)
{//获取当前所在行int row = m_pCarrier->getRow();auto zombie = m_pDelegate->findFirstZombieOfRow(row);//僵尸存在并且还没有死亡,则进行攻击倒计时if (zombie != nullptr && !zombie->isDead()){m_elapsed += dt;//到达攻击时间if (m_elapsed > this->getColdDownTime()){m_elapsed -= this->getColdDownTime();//发射豌豆this->shoot();}}else{m_elapsed = 0.f;}
}
豌豆射手是获取所在行是否存在僵尸,然后判断是否发射子弹,m_pCarrier是豌豆射手所在的塔基。

ZombieBase*ZombieLayer::findFirstZombieOfRow(int row)
{auto it = m_zombies.find(row);ZombieBase*zombie = nullptr;if (it != m_zombies.end()){auto&zombies = it->second;//TODOif (!zombies.empty()){zombie = zombies.front();}}return zombie;
}
这个函数是ZombieLayer提供的,就是获取某一行是否存在僵尸,如果存在,则获取第一个,否则返回nullptr

class PlantDelegate
{
public:virtual ~PlantDelegate(){}virtual void makeSun(int number,FiniteTimeAction*action,const Point&bornPos)=0;virtual ZombieBase*findFirstZombieOfRow(int row) = 0;virtual void addPeaBullet(int damage,int row,const Point&startPos) = 0;
};
这是目前的植物的委托类里的函数,豌豆射手需要的后两个都需要在GameScene中有对应的实现
void Peashooter::shoot()
{		int row = m_pCarrier->getRow();int damage = this->getDamage();Point startPos = this->getPosition();Size size = this->getContentSize();//对发射的位置进行确定startPos.x += size.width/2.f;startPos.y -= size.height/4.f;//添加豌豆子弹m_pDelegate->addPeaBullet(damage,row,startPos);
}
豌豆的发射函数,在这里调整了以下豌豆的出生位置为豌豆的右上角左右的位置。

好了,现在先测试测试吧

void GameScene::addPeaBullet(int damage,int row,const Point&startPos)
{printf("pea bullet shoot\n");
}
编译运行后在豌豆射手所在行放置僵尸就会在控制台上每隔1.4s就会打印一句"pea bullet shoot"的。

接下来就是实现子弹类和豌豆子弹了

,这两个就是豌豆的贴图和死亡动画(死亡动画只有一帧,持续0.5秒)

class Bullet : public Entity
{
public://使用cocos2dx,把SDL修改为CCSDL_SYNTHESIZE(int,m_nRow,Row);//子弹当前的行数SDL_SYNTHESIZE(int,m_nHitPoint,HitPoint);//当前血量SDL_SYNTHESIZE(int,m_nDamage,Damage);//当前伤害SDL_BOOL_SYNTHESIZE(m_bDead,Dead);//是否死亡SDL_BOOL_SYNTHESIZE(m_bTrack,Track);//是否是追踪弹
public:Bullet();~Bullet();virtual void hurt();bool isDying()const;
};
//-----------------------豌豆子弹PeaBullet------------------------------
class PeaBullet : public Bullet
{
public:PeaBullet();~PeaBullet();CREATE_FUNC(PeaBullet);bool init();virtual void hurt();
};
子弹类有一些基础的数值,值得一提的就是m_bTrack了,这个主要是为了标识该子弹是否是追踪子弹(如屋顶类植物,卷心菜和玉米发射的子弹),因为豌豆子弹会攻击第一个碰到的僵尸,而卷心菜等则是到达目的地后就直接尝试攻击(2d实现类似3D的攻击效果),这个留给以后扩展使用。然后就是hurt(),不同类型的子弹的hurt()是不同的,如豌豆子弹,在碰到第一个僵尸后就死亡了,即不再参与碰撞。而像西瓜,在攻击僵尸后还会有一个溅射伤害,就可以以在这里进行相应的判断。

bool Bullet::isDying()const
{return m_nHitPoint <= 0;
}
//---------------------PeaBullet-----------------------------
PeaBullet::PeaBullet()
{
}PeaBullet::~PeaBullet()
{
}bool PeaBullet::init()
{//绑定精灵auto spriteName = STATIC_DATA_STRING("pea_bullet_sprite_name");this->bindSpriteWithSpriteFrameName(spriteName);return true;
}void PeaBullet::hurt()
{if (this->isDying() || this->isDead())return;m_nHitPoint = 0;//设置豌豆死亡auto animationName = "pea_bullet_dead_anim";Animation*animation = AnimationCache::getInstance()->getAnimation(animationName);Animate*animate = Animate::create(animation);//运行死亡动画this->getSprite()->runAction(animate);//在死亡动画持续后真正死亡DelayTime*delayTime = DelayTime::create(animate->getDuration());CallFunc*end = CallFunc::create([this](){this->setDead(true);});//运行死亡动作auto seq = Sequence::createWithTwoActions(delayTime,end);this->stopAllActions();this->runAction(seq);
}
豌豆在死亡后,会有一个死亡动画,之后豌豆就真正死亡了(m_bDead 为true时,从场景中移除)

然后新建一个BulletLayer层,负责子弹的生成,更新和死亡。

class BulletLayerDelegate
{
public:virtual ~BulletLayerDelegate(){}virtual vector<ZombieBase*> getZombiesOfRow(int row)=0;
};class BulletLayer : public Layer
{
private:vector<Bullet*> m_bullets;BulletLayerDelegate*m_pDelegate;
public:BulletLayer();~BulletLayer();CREATE_FUNC(BulletLayer);bool init();void update(float dt);//添加豌豆子弹 TODOBullet*addPeaBullet();void setDelegate(BulletLayerDelegate*pDelegate);
private:void checkCollisionBetweenZombieAndBullet(Bullet*bullet);
};
子弹层有一个委托类,目前仅仅有一个方法,就是获取特定行的僵尸,这个主要是为了便于子弹对僵尸的攻击

void BulletLayer::update(float dt)
{for (auto it = m_bullets.begin();it != m_bullets.end();){auto bullet = *it;//移除该子弹if (bullet->isDead()){bullet->removeFromParent();it = m_bullets.erase(it);printf("pea dead\n");}else{//当前子弹不是追踪性子弹if (!bullet->isTrack()){this->checkCollisionBetweenZombieAndBullet(bullet);}it++;}}
}
在这里对子弹进行遍历,看是否产生碰撞或移除。
void BulletLayer::checkCollisionBetweenZombieAndBullet(Bullet*bullet)
{auto row = bullet->getRow();auto zombies = m_pDelegate->getZombiesOfRow(row);auto r = bullet->getBoundingBox();for (auto it = zombies.begin();it != zombies.end();it++){auto zombie = *it;if (bullet->isDying())break;auto rect = zombie->getCollisionBoundingBox();//僵尸收到伤害if (r.intersectsRect(rect)){bullet->hurt();//僵尸受伤}}
}
因为目前僵尸还没有受伤的方法,所以就先空着,这个方法的目的很明确,就是检测子弹是否和僵尸发生碰撞。

vector<ZombieBase*> ZombieLayer::getZombiesOfRow(int row)
{auto it = m_zombies.find(row);if (it != m_zombies.end()){auto vec = it->second;return vec;}return vector<ZombieBase*>();
}
僵尸层的一个方法,获取对应行的僵尸(目前暂时不考虑杨桃这种特殊植物,目前思路如下,杨桃的所在行设置为-1,然后在僵尸层进行判断,如果是-1就把所有的僵尸都放到一个vector中,进行一次完全遍历)

void GameScene::addPeaBullet(int damage,int row,const Point&startPos)
{Size visibleSize = Director::getInstance()->getVisibleSize();Point deltaPos(visibleSize.width - startPos.x,0);auto bullet = m_pBulletLayer->addPeaBullet();//设置基础属性bullet->setRow(row);bullet->setDamage(damage);bullet->setPosition(startPos);//添加到场景中auto entityLayer = this->getEntityLayer();entityLayer->addChild(bullet,BULLET_TAG);//设置位置deltaPos = m_pLevelLayer->convertToNodeSpace(deltaPos);//设置动作auto length = deltaPos.length();auto move = MoveBy::create(length/300.f,deltaPos);CallFunc*end = CallFunc::create([bullet](){bullet->setDead(true);});//运行动作auto seq = Sequence::createWithTwoActions(move,end);bullet->runAction(seq);
}
修改GameScene的addPeaBullet方法,这里需要注意,豌豆子弹在出了场景之后就直接死亡的。

本节截图

这篇关于cocos2dx 植物大战僵尸 15 豌豆射手的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/202692

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、