底部操作栏包括手柄,按钮和一个梯度
手柄:
手柄的实现来自于Joystick(网上有其实现的源码)
当把摇杆往最右方向移动,然后靠着边绕一圈,发现其值是-1和1之间,即单位向量,所以如何计算出这个单位向量是实现的核心。
void Joystick::updateVelocity(CCPoint point) {
if(_diable) //不可用,则返回,不需计算
return;
// Calculate distance and angle from the center.
float dx = point.x;//当前的触摸点的x值
float dy = point.y;//当前的触摸点的y值
if(!_autoCenter && dx == 0 && dy == 0) {//原点则返回,不需计算
return;
}
float dSq = dx * dx + dy * dy;//计算x的平方加上y的平方
if(dSq <= _deadRadiusSq) {//如果小于死亡半径的平方(如果有设置死亡半径的话),返回原点坐标和向量
_velocity = CCPointZero;
_degrees = 0.0f;
_stickPosition = point;
return;
}
float angle = atan2f(dy, dx); //计算弧度
if(angle < 0){//弧度小于0,则加上2 * pi,即弧度的范围控制在0到2 * pi之间
angle += SJ_PI_X_2;
}
float cosAngle;
float sinAngle;
if(_isDPad){
float anglePerSector = 360.0f / _numberOfDirections * SJ_DEG2RAD;
angle = round(angle/anglePerSector) * anglePerSector;
}
cosAngle = cosf(angle);//计算余弦
sinAngle = sinf(angle);//计算正弦
// NOTE: Velocity goes from -1.0 to 1.0.
if (dSq > _joystickRadiusSq || _isDPad) { //计算x和y值
dx = cosAngle * _joystickRadius;
dy = sinAngle * _joystickRadius;
}
_velocity = CCPointMake(dx / _joystickRadius, dy / _joystickRadius);//计算控制器的点
_degrees = angle * SJ_RAD2DEG;
if(_isOverRange) {
dx = dx / 2;
dy = dy / 2;
}
// Update the thumb's position
_stickPosition = ccp(dx, dy);
}其思路可以概括为:
1、当触摸移动时,获取当前的坐标(节点内),根据坐标的x值和y值利用反正切函数求出当前的坐标的弧度
2、确保弧度范围是在0到2 * pi之间
3、利用弧度计算正弦和余弦
4、利用正弦和余弦计算出单位向量值
按钮:
实现思路如下:
1、判断触摸点是否在按钮的范围内
2、判断按钮是否需要冷却
2.1 不需冷却:那么在触摸移动时继续判断是否还是在按钮范围内,如果是,按钮的功能继续保持
2.2 需要冷却:那么当点击完按钮后,不需要往下分发触摸事件,点击完后执行冷却效果
bool Button::ccTouchBegan(CCTouch *touch, CCEvent *event) {
if(_active || _disable || GameLayer::shareGameLayer()->getShip()->getIsHyperspaceJump()) {//处于激活状态或者超空间跳跃状态
return false;
}
float radiusSq = _radius * _radius;
CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->getLocationInView());
location = this->convertToNodeSpace(location);
//判读触摸点是否在按钮上
if(location.x < -_radius || location.x > _radius || location.y < -_radius || location.y > _radius){
return false;
}else{
float dSq = location.x * location.x + location.y * location.y;
if(radiusSq > dSq){
if(this->_coolingEnd) {// 是否冷却结束
this->_active = true;
if(_cool && !_limit) {//执行冷却效果
_target->triggerButton(this->_buttonType);//执行按钮功能
this->_coolingEnd = false;
//执行冷却
CCProgressFromTo* to = CCProgressFromTo::create(_coolingTime, _percentage, 0);
CCProgressTimer* progress = CCProgressTimer::create(_sprite);
progress->setType(kCCProgressTimerTypeRadial);
progress->setTag(99);
progress->setReverseProgress(true);
this->getParent()->addChild(progress);
CCCallFunc* func = CCCallFunc::create(this, callfunc_selector(Button::onCallback));//按钮重置可用
progress->runAction(CCSequence::create(to, func, NULL));
return false;//结束触摸分发
}else {
_target->triggerButton(this->_buttonType);
}
}
return true;
}
}
return false;
}void Button::ccTouchMoved(CCTouch *touch, CCEvent *event) {
if(_limit && _active && !_cool) {//判断是否需要冷却
float radiusSq = _radius * _radius;
CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->getLocationInView());
location = this->convertToNodeSpace(location);
if(location.x < -_radius || location.x > _radius || location.y < -_radius || location.y > _radius){//触摸点是否离开按钮
_active = false;
return;
}else{
float dSq = location.x*location.x + location.y*location.y;
if(radiusSq > dSq){//触摸点还在按钮上,继续执行该按钮的功能
_target->triggerButton(this->_buttonType);
_active = true;
}
}
}
}其中按钮的功能通过一个协议来触发
在放置按钮的层上,继承了该协议,再由此层指派按钮的功能到各自实现类去实现,即MVC模式
首先定义一个协议
class ButtonDelegate
{
public:
virtual void triggerButton(HW_BUTTON_TYPE buttonType) = 0;//触发按钮事件
virtual void unTriggerButton(HW_BUTTON_TYPE buttonType) = 0;//触发结束事件
};其次定义按钮的功能类别
typedef enum {
MIN_SPPED = 0,
ADD_SPEED,
DODGE,
SHOOT_QUANTUM_GUN,
HYPERSPACE_JUMP,
SWITCH_HEAVY_MISSILE,
ADD_ION_LIMIT_TIME,
SAME_LOCKING_ENEMY,
BLACK_HOLE,
EMP
}HW_BUTTON_TYPE;最后,继承该协议,重写协议的两个方法
class BorderLayer : public CCLayer, public ButtonDelegate
void BorderLayer::triggerButton(HW_BUTTON_TYPE buttonType) {
switch (buttonType) {
case MIN_SPPED:
break;
case ADD_SPEED:
break;
case DODGE:
break;
case SHOOT_QUANTUM_GUN:
break;
...
}
}
void BorderLayer::unTriggerButton(HW_BUTTON_TYPE buttonType) {
//do something
}
本文深入解析游戏开发中按钮与手柄的操作实现机制,详细讲解了按钮和手柄的交互过程,包括触摸事件处理、按钮冷却机制以及手柄单位向量计算方法。同时,文章介绍了通过MVC模式将协议与功能类分离,实现灵活的按钮功能定制。
1万+

被折叠的 条评论
为什么被折叠?



