游戏中的场景有的会产生阳光,所以需要在每一个关卡设置一个标识,来确定是否产生阳光,在tmx中添加以下属性
之后在LevelLayer中获取该属性
void LevelLayer::loadProperties()
{
auto &properties = m_pTiledMap->getProperties();
for (auto property : properties)
{
if (property.first == "produce sun")
{
m_bProduceSun = property.second.asBool();
}
}
}
然后就是在合适的时间产生阳光
void LevelLayer::update(float dt)
{
if (!m_bProduceSun)
return ;
m_elapsed += dt;
//产生阳光
if (m_elapsed >= 16.f)
{
m_elapsed -= 16.f;
Size visibleSize = Director::getInstance()->getVisibleSize();
Point bornPos = Point(visibleSize.width/2,0);
float duration = 6.f;
MoveBy*move = MoveBy::create(duration,Point(0,500.f));
m_pDelegate->makeSun(25,move,bornPos);
}
}
目前设置每16秒出现一次太阳,这个间隔时间也可以放到tmx中的。
另外实现了PanelLayet,目前保存了 阳光背景 阳光计数板和一个铲子背景(铲子以后实现),可以用外部文件,也可以使用代码生成(如果使用cocostudio,需要和cocos2dx版本对应),另外,如果使用外部文件的话,还需要获取这些控件,作扩展使用,另一个就是点击阳光后会有有一个移动到阳光计数器板的动作,也是需要获取阳光计数板的位置的
接着就是Product 和ProductLayer的实现
Product就是产品,这里包括 金币 阳光(还有以后扩展的花园模式的道具),都是Product,这些除了贴图不同,还有一个区别就是效果不同(效果在GameScene中判断),所以仅仅实现Product类就行了,然后使用enum来标识不同种类,再在GameScene中判断
生成太阳的方法如下
void ProductLayer::makeSun(int number,FiniteTimeAction*action,const Point&bornPos)
{
//生成太阳
Product*sun = Product::create();
//设置各种属性
sun->setNumber(number);
sun->setClicked(false);
sun->setUpdate(false);
sun->setDead(false);
sun->setDuration(10.f);
sun->setProductType(ProductType::Sun);
sun->setPosition(bornPos);
this->addChild(sun);
m_products.push_back(sun);
//设置动画
auto animationName = "Sun";
auto animation = AnimationCache::getInstance()->getAnimation(animationName);
//获取第一帧
auto firstFrame = (animation->getFrames().at(0))->getSpriteFrame();
//设置贴图
sun->bindSpriteWithSpriteFrame(firstFrame);
//根据number设置太阳大小
if (number < 25)
sun->getSprite()->setScale(0.5f,0.5f);
//运行动画和动作
sun->getSprite()->runAction(Animate::create(animation));
CallFunc*end = CallFunc::create([sun]()
{
sun->setUpdate(true);
});
auto seq = Sequence::createWithTwoActions(action,end);
sun->runAction(seq);
}
在这里我使用了AnimationCache读取的外部动画文件,在使用时直接加载就可以了
enum class ProductType
{
None,
Sun,//太阳
Gold,//金币
};
目前仅仅有太阳和金币这两种
void Product::update(float dt)
{
//如果死亡或者已经点击过了,则不进行更新
if (m_bDead || m_bClicked)
return;
if (m_bUpdate)
{
m_duration -= dt;
if (m_duration <= 0.f)
m_bDead = true;
}
}
这是产品的普遍更新函数,都有一定的存活时间,在时间消耗完后直接消失
目前的触碰到阳光放在了onTouchEnded(),主要是为了点击阳光成功就不会向下执行种植等操作。
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;
}
//...
}
在点击了阳光后会直接返回,不再执行后面的操作
void GameScene::collectProduct(Product*product)
{
//点击了太阳
if (product->getProductType() == ProductType::Sun)
{
//获取结束位置
auto endPos = m_pPanelLayer->getSunBgPosition();
auto deltaPos = product->getPosition() - endPos;
auto length = deltaPos.length();
MoveTo*move = MoveTo::create(length/400,endPos);
CallFunc*end = CallFunc::create([this,product]()
{
this->addSun(product->getNumber());
product->setDead(true);
});
auto seq = Sequence::createWithTwoActions(move,end);
//运行动作
product->stopAllActions();
product->runAction(seq);
}
}
这个结束位置就是获取在PanelLayer获取的阳光计数板背景的位置。