下面的源码是用开源的Sneaky 改的, 可以在cocos2d-x 2.0.x后的版本运行。 只需要修改几个地方。
在当前改好的源码里,我加入了JoyStick控制方向的时候改变按钮的状态。 分为diable 和press 。 加入了相应方法。 有的方法里对应的进行修改。
如果有哪里改的不好或是还要改进的建议,需要提下,谢谢留个言~
这个sneaky 主要是四个类。 SneakyButtton ,SneakButtonSkinnedBase,SneakyJoystic,SneakyJoysticSkinnerBase。
我在我的工程里用到,写了个使用sneaky的类ToggleLayer。
使用的时候可以复制所有,然后修改toggleLayer的相应方法里的数据就可以达到控制目的。
SneakyButton.h~~~~~~~~~~~
#ifndef __SNEAKY_BUTTON_H__ #define __SNEAKY_BUTTON_H__ #include "cocos2d.h" class SneakyButton : public cocos2d::CCNode, public cocos2d::CCTargetedTouchDelegate { public: static SneakyButton *initSneakyButton(); protected: cocos2d::CCPoint center; float radiusSq; cocos2d::CCRect bounds; CC_SYNTHESIZE(bool, status, Status); CC_SYNTHESIZE_READONLY(bool, active, IsActive); CC_SYNTHESIZE_READONLY(bool, value, Value); CC_SYNTHESIZE(bool, isHoldable, IsHoldable); CC_SYNTHESIZE(bool, isToggleable, IsToggleable); CC_SYNTHESIZE(float, rateLimit, RateLimit); CC_SYNTHESIZE_READONLY(float, radius, Radius); //Public methods virtual void onEnterTransitionDidFinish(); virtual void onExit(); bool initWithRect(cocos2d::CCRect rect); void limiter(float delta); void setRadius(float r); virtual bool ccTouchBegan(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); virtual void ccTouchMoved(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); virtual void ccTouchEnded(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); virtual void ccTouchCancelled(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); void touchDelegateRelease(); void touchDelegateRetain(); }; #endif
sneakyButton.cpp
#include "SneakyButton.h" using namespace cocos2d; void SneakyButton::onEnterTransitionDidFinish() { CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true); } void SneakyButton::onExit() { CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); } bool SneakyButton::initWithRect(CCRect rect) { bool pRet = false; //if(CCSprite::init()){ bounds = CCRectMake(0, 0, rect.size.width, rect.size.height); center = CCPointMake(rect.size.width/2, rect.size.height/2); status = 1; //defaults to enabled active = false; value = 0; isHoldable = 0; isToggleable = 0; radius = 32.0f; rateLimit = 1.0f/120.0f; setPosition(rect.origin); //not sure about this pRet = true; //} return pRet; } void SneakyButton::limiter(float delta) { value = 0; this->unschedule(schedule_selector(SneakyButton::limiter)); active = false; } void SneakyButton::setRadius(float r) { radius = r; radiusSq = r*r; } bool SneakyButton::ccTouchBegan(CCTouch *touch, CCEvent *event) { if (active) return false; CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->locationInView()); location = this->convertToNodeSpace(location); //Do a fast rect check before doing a circle hit check: 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){ active = true; if (!isHoldable && !isToggleable){ value = 1; this->schedule(schedule_selector(SneakyButton::limiter), rateLimit); } if (isHoldable) value = 1; if (isToggleable) value = !value; return true; } } return false; } void SneakyButton::ccTouchMoved(CCTouch *touch, CCEvent *event) { if (!active) return; CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->locationInView()); location = this->convertToNodeSpace(location); //Do a fast rect check before doing a circle hit check: if(location.x < -radius || location.x > radius || location.y < -radius || location.y > radius){ return; }else{ float dSq = location.x*location.x + location.y*location.y; if(radiusSq > dSq){ if (isHoldable) value = 1; } else { if (isHoldable) value = 0; active = false; } } } void SneakyButton::ccTouchEnded(CCTouch *touch, CCEvent *event) { if (!active) return; if (isHoldable) value = 0; if (isHoldable||isToggleable) active = false; } void SneakyButton::ccTouchCancelled(CCTouch *touch, CCEvent *event) { this->ccTouchEnded(touch, event); } void SneakyButton::touchDelegateRelease() { this->release(); } void SneakyButton::touchDelegateRetain() { this->retain(); } SneakyButton * SneakyButton::initSneakyButton() { SneakyButton *button = new SneakyButton(); button->initWithRect(CCRectZero); button->autorelease(); return button; }
SneakyButtonSkinnedBase.h
#ifndef __SNEAKY_BUTTON_SKINNED_H__ #define __SNEAKY_BUTTON_SKINNED_H__ #include "SneakyButton.h" class SneakyButtonSkinnedBase : public cocos2d::CCLayer { CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, defaultSprite, DefaultSprite); CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, activatedSprite, ActivatedSprite); CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, disabledSprite, DisabledSprite); CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, pressSprite, PressSprite); CC_SYNTHESIZE_READONLY(SneakyButton *, button, Button); //Not sure about this //Public methods LAYER_NODE_FUNC(SneakyButtonSkinnedBase); SneakyButtonSkinnedBase(); virtual ~SneakyButtonSkinnedBase(); bool init(); void watchSelf(float delta); void setContentSize(cocos2d::CCSize s); void setDefaultSprite(cocos2d::CCSprite *aSprite); void setActivatedSprite(cocos2d::CCSprite *aSprite); void setDisabledSprite(cocos2d::CCSprite *aSprite); void setPressSprite(cocos2d::CCSprite *aSprite); void setButton(SneakyButton *aButton); }; #endif
SneakyButtonSkinnerBase.cpp
#include "SneakyButtonSkinnedBase.h" using namespace cocos2d; SneakyButtonSkinnedBase::~SneakyButtonSkinnedBase() { if (defaultSprite) { defaultSprite->release(); defaultSprite = NULL; } if (activatedSprite) { activatedSprite->release(); activatedSprite = NULL; } if (disabledSprite) { disabledSprite->release(); disabledSprite = NULL; } if (pressSprite) { pressSprite->release(); pressSprite = NULL; } if (button) { button->release(); button = NULL; } this->unschedule(schedule_selector(SneakyButtonSkinnedBase::watchSelf)); } bool SneakyButtonSkinnedBase::init() //Possible errors here { bool pRet = false; if(CCLayer::init()){ this->defaultSprite = NULL; //defaultSprite->retain(); this->activatedSprite = NULL; //activatedSprite->retain(); this->disabledSprite = NULL; //disabledSprite->retain(); this->pressSprite = NULL; //pressSprite->retain(); this->button = NULL; //button->retain(); this->schedule(schedule_selector(SneakyButtonSkinnedBase::watchSelf)); pRet = true; } return pRet; } void SneakyButtonSkinnedBase::watchSelf(float delta) //Be Careful Here { if (!this->button->getStatus()){ if(disabledSprite){ disabledSprite->setVisible(true); } else { disabledSprite->setVisible(false); } } else { if(!this->button->getIsActive()){ pressSprite->setVisible(false); if(this->button->getValue() == 0){ activatedSprite->setVisible(false); if(defaultSprite){ defaultSprite->setVisible(true); } } else { activatedSprite->setVisible(true); } } else { defaultSprite->setVisible(false); if(pressSprite){ pressSprite->setVisible(true); } } } } void SneakyButtonSkinnedBase::setContentSize(CCSize s) { CCLayer::setContentSize(s); //if (defaultSprite) //{ // defaultSprite->setContentSize(s); //} //button->setRadius(s.width/2); } void SneakyButtonSkinnedBase::setDefaultSprite(CCSprite *aSprite) { defaultSprite = aSprite; //Check again here defaultSprite->retain(); if(aSprite){ this->addChild(defaultSprite, 0); this->setContentSize(defaultSprite->getContentSize()); } } void SneakyButtonSkinnedBase::setActivatedSprite(CCSprite *aSprite) { /*if(activatedSprite){ if(activatedSprite->getParent()) activatedSprite->getParent()->removeChild(activatedSprite, true); activatedSprite->release(); }*/ aSprite->retain(); activatedSprite = aSprite; if(aSprite){ this->addChild(activatedSprite, 1); this->setContentSize(activatedSprite->getContentSize()); } } void SneakyButtonSkinnedBase::setDisabledSprite(CCSprite *aSprite) { if(disabledSprite){ if(disabledSprite->getParent()) disabledSprite->getParent()->removeChild(disabledSprite, true); disabledSprite->release(); } aSprite->retain(); disabledSprite = aSprite; if(aSprite){ this->addChild(disabledSprite, 2); this->setContentSize(disabledSprite->getContentSize()); } } void SneakyButtonSkinnedBase::setPressSprite(CCSprite *aSprite) { /*if(pressSprite){ if(pressSprite->getParent()) pressSprite->getParent()->removeChild(pressSprite, true); pressSprite->release(); }*/ aSprite->retain(); pressSprite = aSprite; if(aSprite){ this->addChild(pressSprite, 3); this->setContentSize(pressSprite->getContentSize()); } } void SneakyButtonSkinnedBase::setButton(SneakyButton *aButton) { /*if(button){ if(button->getParent()) button->getParent()->removeChild(button, true); button->release(); }*/ aButton->retain(); button = aButton; if(aButton){ this->addChild(button, 4); if(defaultSprite) button->setRadius(defaultSprite->boundingBox().size.width/2); } } SneakyButtonSkinnedBase::SneakyButtonSkinnedBase() { this->schedule(schedule_selector(SneakyButtonSkinnedBase::watchSelf)); }
SneakyJoyStick.h
#ifndef __SNEAKY_JOYSTICK_H__ #define __SNEAKY_JOYSTICK_H__ #include "cocos2d.h" class SneakyJoystick : public cocos2d::CCNode, public cocos2d::CCTargetedTouchDelegate { protected: float joystickRadiusSq; float thumbRadiusSq; float deadRadiusSq; //来来检测当前按钮是否被按下。 CC_SYNTHESIZE_READONLY(bool, active, IsActive); CC_SYNTHESIZE_READONLY(cocos2d::CCPoint, stickPosition, StickPosition); CC_SYNTHESIZE_READONLY(float, degrees, Degrees); CC_SYNTHESIZE_READONLY(cocos2d::CCPoint, velocity, Velocity); CC_SYNTHESIZE(bool, autoCenter, AutoCenter); CC_SYNTHESIZE_READONLY(bool, isDPad, IsDPad); CC_SYNTHESIZE(bool, hasDeadzone, HasDeadzone); CC_SYNTHESIZE(int, numberOfDirections, NumberOfDirections); CC_SYNTHESIZE_READONLY(float, joystickRadius, JoystickRadius); CC_SYNTHESIZE_READONLY(float, thumbRadius, ThumbRadius); CC_SYNTHESIZE_READONLY(float, deadRadius, DeadRadius); virtual ~SneakyJoystick(); bool initWithRect(cocos2d::CCRect rect); virtual void onEnterTransitionDidFinish(); virtual void onExit(); void setIsDPad(bool b); void setJoystickRadius(float r); void setThumbRadius(float r); void setDeadRadius(float r); virtual bool ccTouchBegan(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); virtual void ccTouchMoved(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); virtual void ccTouchEnded(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); virtual void ccTouchCancelled(cocos2d::CCTouch *touch, cocos2d::CCEvent *event); void touchDelegateRelease(); void touchDelegateRetain(); private: void updateVelocity(cocos2d::CCPoint point); void setTouchRadius(); }; #endif
#include "SneakyJoystick.h" using namespace cocos2d; #define SJ_PI 3.14159265359f #define SJ_PI_X_2 6.28318530718f #define SJ_RAD2DEG 180.0f/SJ_PI #define SJ_DEG2RAD SJ_PI/180.0f SneakyJoystick::~SneakyJoystick() { } bool SneakyJoystick::initWithRect(CCRect rect) { bool pRet = false; //if(CCSprite::init()){ stickPosition = CCPointZero; degrees = 0.0f; velocity = CCPointZero; autoCenter = true; isDPad = false; hasDeadzone = false; active = false; numberOfDirections = 4; this->setJoystickRadius(rect.size.width/2); this->setThumbRadius(32.0f); this->setDeadRadius(0.0f); //Cocos node stuff setPosition(rect.origin); pRet = true; //} return pRet; } void SneakyJoystick::onEnterTransitionDidFinish() { CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true); } void SneakyJoystick::onExit() { CCDirector::sharedDirector()->getTouchDispatcher()->removeDelegate(this); } float round(float r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); } void SneakyJoystick::updateVelocity(CCPoint point) { // Calculate distance and angle from the center. float dx = point.x; float dy = point.y; float dSq = dx * dx + dy * dy; if(dSq <= deadRadiusSq){ velocity = CCPointZero; degrees = 0.0f; stickPosition = point; return; } float angle = atan2f(dy, dx); // in radians if(angle < 0){ 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) { dx = cosAngle * joystickRadius; dy = sinAngle * joystickRadius; } velocity = CCPointMake(dx/joystickRadius, dy/joystickRadius); degrees = angle * SJ_RAD2DEG; // Update the thumb's position stickPosition = ccp(dx, dy); } void SneakyJoystick::setIsDPad(bool b) { isDPad = b; if(isDPad){ hasDeadzone = true; this->setDeadRadius(10.0f); } } void SneakyJoystick::setJoystickRadius(float r) { joystickRadius = r; joystickRadiusSq = r*r; } void SneakyJoystick::setThumbRadius(float r) { thumbRadius = r; thumbRadiusSq = r*r; } void SneakyJoystick::setDeadRadius(float r) { deadRadius = r; deadRadiusSq = r*r; } bool SneakyJoystick::ccTouchBegan(CCTouch *touch, CCEvent *event) { CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->locationInView()); //if([background containsPoint:[background convertToNodeSpace:location]]){ location = this->convertToNodeSpace(location); //Do a fast rect check before doing a circle hit check: if(location.x < -joystickRadius || location.x > joystickRadius || location.y < -joystickRadius || location.y > joystickRadius){ return false; }else{ float dSq = location.x*location.x + location.y*location.y; if(joystickRadiusSq > dSq){ this->updateVelocity(location); this->active = true; return true; } } return false; } void SneakyJoystick::ccTouchMoved(CCTouch *touch, CCEvent *event) { CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->locationInView()); location = this->convertToNodeSpace(location); this->updateVelocity(location); } void SneakyJoystick::ccTouchEnded(CCTouch *touch, CCEvent *event) { CCPoint location = CCPointZero; if(!autoCenter){ CCPoint location = CCDirector::sharedDirector()->convertToGL(touch->locationInView()); location = this->convertToNodeSpace(location); } this->updateVelocity(location); this->active = false; } void SneakyJoystick::ccTouchCancelled(CCTouch *touch, CCEvent *event) { this->ccTouchEnded(touch, event); } void SneakyJoystick::touchDelegateRelease() { this->release(); } void SneakyJoystick::touchDelegateRetain() { this->retain(); }
#ifndef __JOYSTICK_SKINNED_H__ #define __JOYSTICK_SKINNED_H__ #include "cocos2d.h" #include "SneakyJoystick.h" class SneakyJoystickSkinnedBase : public cocos2d::CCLayer { CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, backgroundSprite, BackgroundSprite); //当无压住按钮时候的sprite CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, disableThumbSprite, DisableThumbSprite); //当出现压住按钮时候的sprite CC_SYNTHESIZE_READONLY(cocos2d::CCSprite *, pressThumbSprite, PressThumbSprite); CC_SYNTHESIZE_READONLY(SneakyJoystick *, joystick, Joystick); //Public methods LAYER_NODE_FUNC(SneakyJoystickSkinnedBase); virtual ~SneakyJoystickSkinnedBase(); bool init(); void updatePositions(float delta); void setContentSize(cocos2d::CCSize s); void setBackgroundSprite(cocos2d::CCSprite *aSprite); void setDisableThumbSprite(cocos2d::CCSprite *aSprite); void setPressThumbSprite(cocos2d::CCSprite *aSprite); void setJoystick(SneakyJoystick *aJoystick); }; #endif
SneakyJoyStickSkinner.cpp
#include "SneakyJoystickSkinnedBase.h" using namespace cocos2d; SneakyJoystickSkinnedBase::~SneakyJoystickSkinnedBase() { if (backgroundSprite) { backgroundSprite->release(); backgroundSprite = NULL; } if (pressThumbSprite) { pressThumbSprite->release(); pressThumbSprite = NULL; } if (disableThumbSprite) { disableThumbSprite->release(); disableThumbSprite = NULL; } if (joystick) { joystick->release(); joystick = NULL; } } bool SneakyJoystickSkinnedBase::init() { bool pRet = false; if(CCLayer::init()){ this->backgroundSprite = NULL; this->disableThumbSprite = NULL; this->pressThumbSprite = NULL; this->joystick = NULL; this->schedule(schedule_selector(SneakyJoystickSkinnedBase::updatePositions)); pRet = true; } return pRet; } void SneakyJoystickSkinnedBase::updatePositions(float delta) { if(joystick) { pressThumbSprite->setVisible(false); disableThumbSprite->setVisible(false); if (joystick->getIsActive()) { if (pressThumbSprite){ pressThumbSprite->setVisible(true); pressThumbSprite->setPosition(joystick->getStickPosition()); } } else{ if(disableThumbSprite) { disableThumbSprite->setVisible(true); disableThumbSprite->setPosition(joystick->getStickPosition()); } } } } void SneakyJoystickSkinnedBase::setContentSize(CCSize s) { CCLayer::setContentSize(s); } void SneakyJoystickSkinnedBase::setBackgroundSprite(CCSprite *aSprite) { backgroundSprite = aSprite; backgroundSprite->retain(); if(aSprite){ this->addChild(backgroundSprite, 0); this->setContentSize(backgroundSprite->getContentSize()); } } void SneakyJoystickSkinnedBase::setJoystick(SneakyJoystick *aJoystick) { joystick = aJoystick; joystick->retain(); if(aJoystick){ this->addChild(aJoystick, 2); if(disableThumbSprite) joystick->setThumbRadius(disableThumbSprite->boundingBox().size.width/2); else joystick->setThumbRadius(0); if(backgroundSprite) joystick->setJoystickRadius(backgroundSprite->boundingBox().size.width/2); } } void SneakyJoystickSkinnedBase::setDisableThumbSprite( cocos2d::CCSprite *aSprite ) { disableThumbSprite = aSprite; disableThumbSprite->retain(); if(aSprite){ this->addChild(disableThumbSprite, 0); //joystick->setThumbRadius(thumbSprite->getContentSize().width/2); } } void SneakyJoystickSkinnedBase::setPressThumbSprite( cocos2d::CCSprite *aSprite ) { pressThumbSprite = aSprite; pressThumbSprite->retain(); if(aSprite){ this->addChild(pressThumbSprite, 1); //joystick->setThumbRadius(thumbSprite->getContentSize().width/2); } }
#include "cocos2d.h" #include "SneakyButton.h" #include "SneakyButtonSkinnedBase.h" #include "SneakyJoystick.h" #include "SneakyJoystickSkinnedBase.h" USING_NS_CC; /** *遥控层 **/ class ToggleLayer :public cocos2d::CCLayer { public: ToggleLayer(void); ~ToggleLayer(void); //加入遥控和按钮 void addToggleAndButton(); private: //摇杆和按钮触控update更新 void update(float dt); SneakyButton *buttonA; SneakyJoystick *joystick; static float fireTime; };
#include "ToggleLayer.h" #include "GameScene.h" ToggleLayer::ToggleLayer(void) { addToggleAndButton(); } ToggleLayer::~ToggleLayer(void) { } void ToggleLayer::addToggleAndButton() { CCSize size = CCDirector::sharedDirector()->getWinSize(); float buttonRadius=50; buttonA=new SneakyButton(); buttonA->initWithRect(CCRectZero); buttonA->setIsToggleable(false); buttonA->setIsHoldable(true); //SneakyButtonSkinnedBase *buttonASkin=new SneakyButtonSkinnedBase(); SneakyButtonSkinnedBase *buttonASkin= new SneakyButtonSkinnedBase();//::createSkin(); buttonASkin->init(); buttonASkin->setPosition(ccp(size.width-buttonRadius,buttonRadius)); buttonASkin->setDefaultSprite(CCSprite::create("button-default.png"));//可以修改 // buttonASkin->setDisabledSprite(CCSprite::spriteWithFile("button-disabled.png"));// buttonASkin->setPressSprite(CCSprite::create("button-pressed.png"));//可以修改 buttonASkin->setActivatedSprite(CCSprite::create("button-activated.png"));//可以修改 buttonASkin->setButton(buttonA); this->addChild(buttonASkin); float joystickRadius=50; joystick=new SneakyJoystick(); joystick->initWithRect(CCRectZero); joystick->setAutoCenter(true); joystick->setHasDeadzone(true); joystick->setDeadRadius(10); SneakyJoystickSkinnedBase *joystickSkin=new SneakyJoystickSkinnedBase(); joystickSkin->init(); CCSprite *bgSprite = CCSprite::create("skeany_bg.png"); joystickSkin->setBackgroundSprite(bgSprite); //默认的Sprite joystickSkin->setDisableThumbSprite(CCSprite::create("skeanyCenter.png")); //disable的状态的图片 //当出现压住按钮时候的sprite joystickSkin->setPressThumbSprite(CCSprite::create("skeanyCenter2.png")); //press的状态时候的图片 //joystickSkin->getThumbSprite()->setScale(0.5f); joystickSkin->setPosition( ccp(bgSprite->getContentSize().width*0.5f+10,bgSprite->getContentSize().height*0.5+10)); joystickSkin->setJoystick(joystick); this->addChild(joystickSkin); this->scheduleUpdate(); } #define FIRE_INTERVAL 0.3f float ToggleLayer::fireTime=0; void ToggleLayer::update( float dt ) { CCPoint velocity=joystick->getVelocity(); if(velocity.x!=0||velocity.y!=0) { velocity = ccpMult(velocity,2.5); CCLOG("joystick:[%f,%f]",velocity.x,velocity.y); //CCPoint position = GameScene::shareGameScene()->getShip()->getPosition(); //if (GameScene::shareGameScene()->getShip()) //{ // GameScene::shareGameScene()->getShip()->setPosition(ccpAdd(position,velocity)); //}
//这里加入你要控制方向的精灵。
}
fireTime+=dt;
if(buttonA->getIsActive()&&fireTime>=FIRE_INTERVAL)
{
CCLOG("buttonA pressed.");
//if(GameScene::shareGameScene()->getShip())
// GameScene::shareGameScene()->getShip()->shootButtleFromToggle();
fireTime=0;
}
}
使用后的效果示意图: