对于虚拟摇杆在游戏开发中必不可少,Android方面的是由Himi自己实现封装的,大家可以移步到这里查看详细实现机制:
【Android游戏开发二十四】360°平滑游戏摇杆(触屏方向导航)
那么在Cocos2d引擎已提供此摇杆类(Joystick),所以Himi也就懒得重写了,但是Cocos2dx中并没有封装,那么这里Himi给出Cocos2dx版的Joystick(HRocker类),并且Himi对此类添加了一个跟随用户触点作为摇杆坐标的功能!
这里不多说代码结构直接贴出源码,然后重点说下使用与方法参数,具体实现可以参考源码以及Android部分Himi的实现机制;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
//
// 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
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
//
// 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类进行拷贝自己项目中,然后使用以下代码进行创建使用尝试下吧:
1
2
3
4
5
6
7
8
9
10
|
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就不添加了,毕竟每款游戏都有不同需求~