cocos2dx 植物大战僵尸 6 植物层

上一节实现了塔基的行数的确定,这一节就着手于植物的创建。
下面就说说植物类的继承关系

这里说明下,这个游戏我打算使用box2d,不过这里并不是要进行物理模拟,而是仅仅用作物理碰撞,因为有些地方使用box2d会更好,比如,在屋顶场景中有个斜坡,豌豆等子弹碰到后会消失,使用box2d就不难实现,而且使用box2d也便于碰撞调试等等。另外,我也使用了Physics Editor和TexturePacker等软件(这两个软件都是收费的),主要是为了便于开发。
B2Entity 就是box2d entity,就是参与物理碰撞的实体。主要用于那些既参与碰撞,又显示贴图的对象。
/*主要了是为了在发生碰撞时便于类型转换*/
enum class CollisionType
{
	None,
	Plant,//植物类型
};

class B2Entity:public Entity
{
	SDL_SYNTHESIZE(CollisionType,m_collisionType,CollisionType);
protected:
	b2Body*m_pBody;
	bool m_bActive;//是否存活,如果是则存在box2d碰撞面积
public:
	B2Entity();
	~B2Entity();

	virtual void update(float dt) = 0;
	/**初始化刚体
	*/
	void initBody();
	/**为内部的body添加b2Fixture,内部由GB2ShapeCache-x提供支持
	@shape 在GB2ShapeCache中 的shape所对应的形体的名称
	shape必须在这之前已经加载到GB2ShapeCache中,并且body不能为nullptr
	*/
	void addFixturesToBody(const std::string &shape);
	//清除原来body的全部fixture
	void clearFixtures();
	//获取当前形状
	b2Fixture*getFixtureList()const;

	void setActive(bool active);
	bool isActive()const;
};
这里主要说明的就是CollisionType,box2d在发生碰撞时,如果需要对碰撞进行监听,就需要继承自吧b2ContactListener的类实现BegainContact和EndContact等方法,因为在box2d中碰撞的都是形状fixture,所以需要获取fixture的body,然后再根据body->GetUserData()获取刚体所对应的实体,然后再根据实体进行一些逻辑判断
B2Entity::~B2Entity()
{
	if(m_pBody)//回收内存
	{
		auto pWorld = GameScene::getWorld();
		if (pWorld)
			pWorld->DestroyBody(m_pBody);
	}
	m_pBody = nullptr;
}
void B2Entity::initBody()
{
	b2BodyDef bodyDef;
	bodyDef.type = b2_dynamicBody;
	//创建刚体
	b2World*pWorld = GameScene::getWorld();
	m_pBody = pWorld->CreateBody(&bodyDef);
	//设置刚体用户数据
	m_pBody->SetUserData(this);
}
void B2Entity::addFixturesToBody(const std::string &shape)
{
	GB2ShapeCache::getInstance()->addFixturesToBody(m_pBody,shape);
}

void B2Entity::clearFixtures()
{
	//先清除原先的fixture
	for(auto fixture = m_pBody->GetFixtureList();fixture;)
	{
		auto temp = fixture;
		
		fixture = fixture->GetNext();

		m_pBody->DestroyFixture(temp);
	}
}

b2Fixture*B2Entity::getFixtureList()const
{
	if(m_pBody)
		return m_pBody->GetFixtureList();
	return nullptr;
}

void B2Entity::setActive(bool active)
{
	if(m_pBody == nullptr)
		return;

	m_pBody->SetActive(active);
	m_bActive = active;
}

bool B2Entity::isActive()const
{
	return m_bActive;
}
在这里使用了GB2ShapeCache-x.h文件,这个是和PhysicsEditor的导出文件所对应的一个单例类,主要负责形状的创建和绑定刚体。
clearFixture()是为了便于重用。还有就是setActive无法在b2ContactListener的回调函数中进行使用,这个需要注意。

Plant则是植物类的父类,目前也没什么内容,待以后扩展使用。
class PlantDelegate
{
public:
	virtual ~PlantDelegate(){}
	virtual void makeSun(int number,FiniteTimeAction*action,const Point&bornPos)=0;
};

class Plant : public B2Entity
{
	SDL_SYNTHESIZE(float,m_fColdDownTime,ColdDownTime);//总cd
	SDL_SYNTHESIZE(int,m_nHitPoint,HitPoint);//血量
	SDL_SYNTHESIZE(ActiveTime,m_activeTime,ActiveTime);//活动时间
	SDL_SYNTHESIZE(string,m_plantName,PlantName);//植物名称
protected:
	PlantDelegate*m_pDelegate;
public:
	Plant();
	~Plant();

	void setDelegate(PlantDelegate*delegate);
	virtual void update(float dt);
};
Plant类中保存了一些基本的属性,还有一个就是PlantDelegate,这个使用的是委托,目前仅仅有一个makeSun方法,使用委托的好处就是解耦,这样Plant就不需要知道PlantDelegate是什么,只要它实现了对应的方法就可以了

接着就是PlantLayer植物层和PlantFactory植物工厂的实现了,植物层现在没什么内容,目前仅仅涉及了植物的逻辑更新和植物的产生,内部调用了植物工厂方法
bool PlantLayer::init()
{
	m_pPlantFactory = PlantFactory::create();
	m_pPlantFactory->retain();

	return true;
}
//进行植物的逻辑更新 TODO
void PlantLayer::update(float dt)
{
	for (auto it = m_plants.begin();it != m_plants.end();)
	{
		auto plant = *it;

		plant->update(dt);
		it++;
	}
}
另外植物工厂不是单例类,在植物层中保存了它的指针。
void GameScene::onTouchEnded(Touch*touch,SDL_Event*event)
{
	auto pos = touch->getLocation();
	//是否点击了ProductLayer
	auto product = m_pProductLayer->getClickedProduct(pos);
	if (product)
	{
		product->setClicked(true);
		this->collectProduct(product);

		return;
	}

	auto nodePos = m_pLevelLayer->convertToNodeSpace(pos);
	//是否点击了某一个terrain
	auto terrain = m_pLevelLayer->getClickedTerrain(nodePos);
	//所有操作对要经过terrain
	if (terrain == nullptr)
		return;

	auto selectedCard = m_pCardLayer->getSelectedCard();
	//存在选中的卡片,则阳光足够,cd完成
	if (selectedCard)
	{
		bool bRet = false;
		
		bRet = this->tryPlanting(selectedCard,terrain);
		//创建完成
		if (bRet)
		{
			//减少阳光值
			this->subSun(selectedCard->getWorth());
			//取消点击
			m_pCardLayer->unselectedCard();
			//该卡片开始cd
			selectedCard->setCurCD(selectedCard->getCD());
		}
	}
	//是否点击了铲子 TODO
}
和以前类似,只不过如果创建成功就减去阳光 取消卡片的选中,同时卡片开始cd
bool GameScene::tryPlanting(Card*card,Terrain*terrain)
{
	auto topPlant = terrain->getTopPlant();
	//获取必要物品
	auto necessaryItem = card->getNecessoryItem();
	//升级植物
	if (!necessaryItem.empty() && topPlant != nullptr
		&& topPlant->getPlantName() == necessaryItem)
	{
		//创建新植物
		//移除旧植物TODO
	}
	//种植植物
	else if (necessaryItem.empty())
	{
		//地形上的植物为空 并且地形符合,则创建
		if (topPlant == nullptr && card->isIncludeTerrain(terrain->getTerrainType()))
		{
			auto plant = m_pPlantLayer->makePlant(card->getCardName());
			//再设置一些基础属性
			plant->setActiveTime(card->getActiveTime());
			plant->setPosition(terrain->getPosition());
			plant->setDelegate(this);
			//添加到entity layer 场景
			auto entityLayer = this->getEntityLayer();
			entityLayer->addChild(plant);
			//设置塔基内部的植物
			terrain->setInnerPlant(plant);

			return true;
		}
		//存在植物,但如果是容器植物,则继续判断
		else if(topPlant != nullptr)
		{
		}
		
	}
	return false;
}
在这里进行了植物的创建,设置了一些属性,并且添加到了场景之中,其他的则是以后扩展使用的。
下一节实现向日葵
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值