hello,明天就要高考了,自己还是有点紧张,希望她/他们都能成功,
当下,天气晴朗,天气炎热。
好久没有更新游戏周边的内容了,今天继续。
(在文章的末尾有相关的效果图,可以先去看看)
游戏技能在格斗等一些类型的游戏中使用非常普遍。如果只是单单将技能图片以灰色的方式禁用掉的话,其实对于一些情况来说是非常不好的。就拿现在的《王者荣耀》来说,技能CD,我们可以推测技能还有多长时间就可以使用来决定要不要开团,这可能是游戏取胜的关键。
说了那么多,现在来看看它的实现原理吧。
这里我画一张图,方便理解。
这些层的关系是从上到下,逐渐降低。
1.遮罩层:
这里说的遮罩层,其实就是那个旋转一周的图层,其实它的前身是ProgressTimer(进度条) 只不过是另一种形式。
这里看一张图(如下图绿色箭头区域)。
2.禁用纹理层:
这里指的是技能图标的灰色区域,也就是下面这个(如图红色箭头区域)
3.按钮:
这个其实不用解释了就是技能图标本身,(下图蓝色区域)
代码的实现,额,因为只是一个例子,索性把这些东西写死,当然在实际游戏开发中是绝对不可能这样写死的;
class Bar:public Layer{
public:
virtual bool init();
CREATE_FUNC(Bar);
ProgressTimer*bartimer; //圆形进度条
MenuItemImage*buttom;//技能图标按钮
Sprite*mengban;
void callBack(Ref*pSender);//技能按钮回调
void actionCallBack();//动作结束后回调
Sprite*bardown;//禁用纹理层
};
实现
bool Bar::init(){
if(!Layer::init()){//父类初始化
return false;
}
Size visibleSize=Director::getInstance()->getVisibleSize();//使用导演获屏幕大小
buttom=MenuItemImage::create("Cn14.png","Cn15.png",CC_CALLBACK_1(Bar::callBack,this));//创建技能按钮,并且绑定回调函数
buttom->setPosition(Point(visibleSize.width/2,visibleSize.height/2-100));// 按钮设置位置
auto menu=Menu::create(buttom,NULL);//创建menu容器来装按钮(好通俗)
menu->setPosition(Point::ZERO);
this->addChild(menu,0);
bardown=Sprite::create("Cn15.png");// 这个是禁用层的纹理了
bardown->setPosition(Point(visibleSize.width/2,visibleSize.height/2-100));
bardown->setVisible(false); //开始的时候让它不可见
this->addChild(bardown,5);
mengban=Sprite::create("Cn14.png");//progresstimer遮罩层(也是另一种类型的进度条)
bartimer=ProgressTimer::create(mengban);//创建“遮罩层”
bartimer—>setPosition(Point(visibleSize.width/2,visibleSize.height/2-100));
bartimer->setVisible(false);//开始的时候让它不可见
bartimer->setType(ProgressTimerType::RADIAL);
this->addChild(bartimer,10);
return true;
}
//当技能图标被按下的,也就是表现在游戏中的释放技能,技能开始进入冷却的时候
void Bar::callBack(Ref*pSender){
buttom->setEnabled(false);//这时候这个技能按钮就不能被触发事件了
bartimer->setVisible(true);//开始让遮罩层显示出来
bardown->setVisible(true);//开始让禁用纹理层显示出来
auto actionto=ProgressTo::create(5, 100);//执行遮罩层的动作,参数为时间(CD),角度(百分比)
auto actioncall=CallFunc::create(CC_CALLBACK_0(Bar::actionCallBack,this));//执行完动作后需要恢复一些数据
auto seq=Sequence::create(actionto,actioncall, NULL);//把动作拼合起来
bartimer->runAction(seq);//开始执行
}
执行完冷却后,或者说是冷却完成后。
void Bar::actionCallBack(){
bardown->setVisible(false);//重新让禁用纹理层不可见
bartimer->setPercentage(0);//设置百分比为0
buttom->setEnabled(true);//重新让技能按钮可以接受事件
bartimer->setVisible(false);//重新让这遮罩层不可见
}
现在来看看效果吧:
慢着,是不是发现,哪里不对,CD里面的倒计时呢?
现在紧接着来实现这个功能
首先,要实现这个效果需要使用两个定时器,首先,CD结束后倒计时必须为0,不然就倒计时就没有意义了。
现在刚才的类内部添加如下代码:
void countDown(float dt);
int p_time;
LabelTTF*label;
init()方法中添加如下
abel=LabelTTF::create("5", "Arial", 20);
label->setPosition(Point(visibleSize.width/2,visibleSize.height/2-100));
this->addChild(label,11);
label->setVisible(false);
p_time=5;
按钮回调中添加:开启时间调度
void Bar::callBack(Ref*pSender){
schedule(schedule_selector(Bar::countDown), 1);
......
}
动作完成函数回调,添加,关闭时间调度,设置时间不可见
void Bar::actionCallBack(){
label->setVisible(false);
unschedule(schedule_selector(Bar::countDown));//停止时间调度
p_time=5;
}
//实现倒计时函数
void Bar::countDown(float dt){
--p_time;
label->setString(String::createWithFormat("%d",p_time)->getCString()); //往label写入数字
}
现在看看效果吧
差不多了。
还想还有什么不对,实际上在游戏中随着斤技能点数的提升,CD时间会越来越短。所以要想写得完善的,你应该传递技能点数给Bar。
关于创建我觉得可以写成这样。
首先,你得在玩家的属性中添加一个属性,比如:
int skillLevel;
再写一个Set方法和一个Get方法,对skillLevel进行改变
这个用来记录玩家一些技能的点数;
然后改变Bar 中的Cd时间。
这需要对类进行重新的规划。
比如在该类中对数据进行重新部署。
比如:
void setDate(Play*play,.......){//假设Play是玩家类
......play->getLevel();
对玩家的一些技能的技能点进行判断,决定cd 的时间。
}
好了今天就到这里,赶快给你的游戏装备上技能Cd吧!
明天就是高考了,希望她/他们都能成功。
如果你的朋友对这个也同样感兴趣,不要忘记推荐给他哦。
拜~