【iOS-cocos2d-X 游戏开发之十二】自定义Cocos2dx摇杆(增强Joystick),增加摇杆跟随用户触点作为摇杆坐标,让摇杆不再死板!

时间:2022-11-25 13:59:59

本站文章均为​ 李华明Himi ​​原创,转载务必在明显处注明


对于虚拟摇杆在游戏开发中必不可少,Android方面的是由Himi自己实现封装的,大家可以移步到这里查看详细实现机制:

​【Android游戏开发二十四】360°平滑游戏摇杆(触屏方向导航) ​

那么在Cocos2d引擎已提供此摇杆类(Joystick),所以Himi也就懒得重写了,但是Cocos2dx中并没有封装,那么这里Himi给出Cocos2dx版的Joystick(HRocker类),并且Himi对此类添加了一个跟随用户触点作为摇杆坐标的功能!

这里不多说代码结构直接贴出源码,然后重点说下使用与方法参数,具体实现可以参考源码以及Android部分Himi的实现机制;


​//​


​//  HRocker.h​


​//  RockerPro​


​//​


​//  Created by Himi on 12-3-30.​


​//  Copyright (c) 2012年 Himi. All rights reserved.​


​//​


 


​#ifndef RockerPro_HRocker_h​


​#define RockerPro_HRocker_h​


 


​#ifndef HRocker_H​


​#define HRocker_H​


​#include "cocos2d.h"​


 


​using​​ ​​namespace​​ ​​cocos2d;​


 


​class​​ ​​HRocker :​​ ​​public​​ ​​CCLayer {​


 


​public​​ ​​:​


​//初始化 aPoint是摇杆中心 aRadius是摇杆半径 aJsSprite是摇杆控制点 aJsBg是摇杆背景​


​static​​ ​​HRocker*  HRockerWithCenter(CCPoint aPoint ,​​ ​​float​​ ​​aRadius ,CCSprite* aJsSprite,CCSprite* aJsBg,​​ ​​bool​​ ​​_isFollowRole);​


 


​//启动摇杆​


​void​​ ​​Active();​


 


​//解除摇杆​


​void​​ ​​Inactive();​


 


​private​​ ​​:​


​HRocker * initWithCenter(CCPoint aPoint ,​​ ​​float​​ ​​aRadius ,CCSprite* aJsSprite,CCSprite* aJsBg,​​ ​​bool​​ ​​_isFollowRole);​


 


​CCPoint centerPoint;​​ ​​//摇杆中心​


 


​CCPoint currentPoint;​​ ​​//摇杆当前位置​


 


​bool​​ ​​active;​​ ​​//是否激活摇杆​


 


​float​​ ​​radius;​​ ​​//摇杆半径​


 


​CCSprite *jsSprite;​


 


​bool​​ ​​isFollowRole;​​ ​​//是否跟随用户点击​


 


​CCPoint getDirection();​


 


​float​​ ​​getVelocity();​


 


​void​​  ​​updatePos(ccTime dt);​


 


​virtual​​ ​​bool​​ ​​ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);​


​virtual​​ ​​void​​ ​​ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);​


​virtual​​ ​​void​​ ​​ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);​


​LAYER_NODE_FUNC(HRocker);​


​};​


​#endif​


 


​#endif​



​//​


​//  HRocker.cpp​


​//  RockerPro​


​//​


​//  Created by Himi on 12-3-30.​


​//  Copyright (c) 2012年 Himi. All rights reserved.​


​//​


​#include "HRocker.h"​


 


​void​​ ​​HRocker::updatePos(ccTime dt){​


​jsSprite->setPosition(ccpAdd(jsSprite->getPosition(),ccpMult(ccpSub(currentPoint, jsSprite->getPosition()),0.5)));​


​}​


​//启动摇杆​


​void​​ ​​HRocker::Active()​


​{​


​if​​ ​​(!active) {​


​active=​​ ​​true​​ ​​;​


​schedule(schedule_selector(HRocker::updatePos));​​ ​​//添加刷新函数​


​CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(​​ ​​this​​ ​​, 0,​​ ​​false​​ ​​);​​ ​​//添加触摸委托​


​}​​ ​​else​​ ​​{​


​}​


​}​


​//解除摇杆​


​void​​   ​​HRocker::Inactive()​


​{​


​if​​ ​​(active) {​


​active=​​ ​​false​​ ​​;​


​this​​ ​​->unschedule(schedule_selector(HRocker::updatePos));​​ ​​//删除刷新​


​CCTouchDispatcher::sharedDispatcher()->removeDelegate(​​ ​​this​​ ​​);​​ ​​//删除委托​


​}​​ ​​else​​ ​​{​


​}​


​}​


​//摇杆方位​


​CCPoint HRocker::getDirection()​


​{​


​return​​ ​​ccpNormalize(ccpSub(centerPoint, currentPoint));​


​}​


​//摇杆力度​


​float​​ ​​HRocker::getVelocity()​


​{​


​return​​ ​​ccpDistance(centerPoint, currentPoint);​


​}​


​HRocker* HRocker:: HRockerWithCenter(CCPoint aPoint ,​​ ​​float​​ ​​aRadius ,CCSprite* aJsSprite,CCSprite* aJsBg,​​ ​​bool​​ ​​_isFollowRole){​


​HRocker *jstick=HRocker::node();​


​jstick->initWithCenter(aPoint,aRadius,aJsSprite,aJsBg,_isFollowRole);​


​return​​ ​​jstick;​


​}​


​bool​​ ​​HRocker::ccTouchBegan(CCTouch* touch, CCEvent* event)​


​{​


 


​if​​ ​​(!active)​


​return​​ ​​false​​ ​​;​


​this​​ ​​->setIsVisible(​​ ​​true​​ ​​);​


​CCPoint touchPoint = touch->locationInView(touch->view());​


​touchPoint = CCDirector:: sharedDirector()->convertToGL(touchPoint);​


​if​​ ​​(!isFollowRole){​


​if​​ ​​(ccpDistance(touchPoint, centerPoint) > radius){​


​return​​ ​​false​​ ​​;​


​}​


​}​


​currentPoint = touchPoint;​


​if​​ ​​(isFollowRole){​


​centerPoint=currentPoint;​


​jsSprite->setPosition(currentPoint);​


​this​​ ​​->getChildByTag(88)->setPosition(currentPoint);​


​}​


​return​​ ​​true​​ ​​;​


​}​


​void​​  ​​HRocker::ccTouchMoved(CCTouch* touch, CCEvent* event)​


​{​


​CCPoint touchPoint = touch->locationInView(touch->view());​


​touchPoint = CCDirector:: sharedDirector()->convertToGL(touchPoint);​


​if​​ ​​(ccpDistance(touchPoint, centerPoint) > radius)​


​{​


​currentPoint =ccpAdd(centerPoint,ccpMult(ccpNormalize(ccpSub(touchPoint, centerPoint)), radius));​


​}​​ ​​else​​ ​​{​


​currentPoint = touchPoint;​


​}​


​}​


​void​​  ​​HRocker::ccTouchEnded(CCTouch* touch, CCEvent* event)​


​{​


​currentPoint = centerPoint;​


​if​​ ​​(isFollowRole){​


​this​​ ​​->setIsVisible(​​ ​​false​​ ​​);​


​}​


​}​


 


​HRocker* HRocker::initWithCenter(CCPoint aPoint ,​​ ​​float​​ ​​aRadius ,CCSprite* aJsSprite,CCSprite* aJsBg,​​ ​​bool​​ ​​_isFollowRole){​


 


​isFollowRole =_isFollowRole;​


​active = ​​ ​​false​​ ​​;​


​radius = aRadius;​


​if​​ ​​(!_isFollowRole){​


​centerPoint =aPoint;​


​}​​ ​​else​​ ​​{​


​centerPoint =ccp(0,0);​


​}​


 


​currentPoint = centerPoint;​


​jsSprite = aJsSprite;​


​jsSprite->setPosition(centerPoint);​


​aJsBg->setPosition(centerPoint);​


​aJsBg->setTag(88);​


​this​​ ​​->addChild(aJsBg);​


​this​​ ​​->addChild(jsSprite);​


​if​​ ​​(isFollowRole){​


​this​​ ​​->setIsVisible(​​ ​​false​​ ​​);​


​}​


​this​​ ​​->Active();​​ ​​//激活摇杆​


​return​​ ​​this​​ ​​;​


​}​


创建使用方法很eazy,如下函数:

HRocker* HRocker:: HRockerWithCenter(CCPoint aPoint ,float aRadius ,CCSprite* aJsSprite,CCSprite* aJsBg,bool _isFollowRole);

第一个参数aPoint:摇杆中心点的坐标;

第二个参数aRadius: 摇杆的半径

第三个参数:aJsSprite :摇杆的图片资源精灵

第四个参数:aJsBg: 摇杆背景图片资源精灵

第五个参数:isFollowRole:是否让摇杆永远跟随用户触屏点(Himi新添加的功能)

这里对于最后一个参数可能很多童鞋不太理解,那么这里大概描述下:

对于手机游戏而言,虚拟的摇杆并不是一个很好的操作方式,但是为了满足游戏的必要操作无疑必须使用,但是虚拟摇杆存在两方面问题:

1.没有实体感觉,对于用户来说不能触觉上明显分清当前自己有没有触摸在虚拟摇杆上或者当前是按下还是按上等;

2.遮挡部分游戏画面,这一点不仅仅式虚拟摇杆的存在造成遮挡画面,用户使用虚拟摇杆时更加的造成游戏画面被挡住;

3.不容易操作,过于死板,不小心就触发了虚拟摇杆区域之外;

对于虚拟摇杆存在的第一方面没有实体感我们没法改进,但是,是否触摸到虚拟键盘这个可以使用手机震动提示;第二,三方面的问题在当前iOS手机游戏上很多公司采用了让虚拟摇杆跟随用户触屏点为摇杆中心的方式!并且用户不触摸屏幕默认不显示虚拟摇杆;这么一来不仅让游戏画面能在不需要操作的时候尽可能的完美展示外,还能有效避免用户触摸不到摇杆判断区域的问题;摇杆跟随功能就是Himi封装Rocker类创建时第五个参数 isFollowRole,传入true即可跟随!

如果还有童鞋听的不是很清楚,那么将Himi这个Rocker类进行拷贝自己项目中,然后使用以下代码进行创建使用尝试下吧:


​CCSprite *spRocker=CCSprite::spriteWithFile(​​ ​​"CloseSelected.png"​​ ​​);​​ ​​//摇杆​


​CCSprite *spRockerBG=CCSprite::spriteWithFile(​​ ​​"rockerBg.png"​​ ​​);​​ ​​//摇杆背景​


​HRocker *rocker=HRocker::HRockerWithCenter(ccp(210.0f,130.0f),50.0f ,spRocker ,spRockerBG,​​ ​​false​​ ​​);​​ ​​//创建摇杆​


​this​​ ​​->addChild(rocker);​​ ​​//摇杆添加到layer中​


​//this 是个layer​


 


​CCSprite *spRocker2=CCSprite::spriteWithFile(​​ ​​"CloseSelected.png"​​ ​​);​​ ​​//摇杆​


​CCSprite *spRockerBG2=CCSprite::spriteWithFile(​​ ​​"rockerBg.png"​​ ​​);​​ ​​//摇杆背景​


​HRocker* rocker2=HRocker::HRockerWithCenter(ccp(210.0f,130.0f),50.0f ,spRocker2 ,spRockerBG2,​​ ​​true​​ ​​);​​ ​​//创建摇杆​


​this​​ ​​->addChild(rocker2);​​ ​​//摇杆添加到layer中​


截图如下:

​​

更多的自定义大家可以自行尝试,Himi就不添加了,毕竟每款游戏都有不同需求~