本文转载至Cocos2d-x v3.2学习笔记(十)Joystick 摇杆控件
代码:
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
|
#ifndef __Joystick__
#define __Joystick__
#include "cocos2d.h"
USING_NS_CC;
enum
JoystickEnum
{
DEFAULT,
D_UP,
D_DOWN,
D_LEFT,
D_RIGHT,
D_LEFT_UP,
D_LEFT_DOWN,
D_RIGHT_UP,
D_RIGHT_DOWN
};
class
Joystick :
public
Layer
{
public
:
/** 启动搖杆器 */
void
onRun();
/** 清除数据 */
void
onDisable();
/** 设置死亡半径,即超出半径將摇杆器失效 */
void
setDieRadius(
float
radius);
/** 设置无效区域半径(如果在无效区域內,將重置) */
void
setFailRadius(
float
radius);
/** 是否显示底盘和触点 */
void
setVisibleJoystick(
bool
visible);
/** 是否自由变换摇杆器的位置,即在屏幕上每一次按下鼠标时的坐标将是摇杆器的坐标,移动时将不改变摇杆器坐标,直到下次按下鼠标 */
void
setAutoPosition(
bool
value);
/** 回调函数指针 */
std::function<
void
(JoystickEnum)> onDirection;
/** 静态创建函数(需要传入底盘和触点图片路径) */
static
Joystick* create(std::string chassisPath,std::string dotPath);
/** 初始化摇杆器(需要传入底盘和触点图片路径) */
void
initWithJoystick(std::string chassisPath,std::string dotPath);
protected
:
/** 有效区域半径 */
float
_radius;
/** 失效区域半径 */
float
_failradius;
/** 是否移出有效区域 */
bool
isMoveOut;
/** 是否存在有效区域半径 */
bool
isDieRadius;
/** 是否自由变换摇杆器坐标 */
bool
isAutoPosition;
/** 方向 */
JoystickEnum _direction;
/** 底盘 */
Sprite* _chassis;
/** 触点 */
Sprite* _touchDot;
EventListenerTouchOneByOne* listener;
bool
onTouchBegan(Touch* touch,Event* event);
void
onTouchMoved(Touch* touch,Event* event);
void
onTouchEnded(Touch* touch,Event* event);
/**
1、设置触点,并判断是否在无效区域内(如果在无效区域内,将重置)
2、发送角度变化(如果不在无效区域内) */
void
setTouchDotPosition(Vec2 vec1,Vec2 vec2);
/**
1、计算摇杆器八方向
2、发送角度变化,回调弧度变化函数 */
void
changeAngle( Vec2 position );
/** 回调注册的监听函数 */
void
callDirectionFun();
/** 重置(当弧度不是 DEFAULT时才重置) */
void
resetState();
};
#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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
#include "Joystick.h"
Joystick* Joystick::create(std::string chassisPath,std::string dotPath)
{
auto joystick =
new
Joystick();
joystick->initWithJoystick(chassisPath,dotPath);
return
joystick;
}
void
Joystick::initWithJoystick(std::string chassisPath,std::string dotPath)
{
_chassis = Sprite::create(chassisPath);
this
->addChild(_chassis,0);
_touchDot = Sprite::create(dotPath);
this
->addChild(_touchDot,1);
isDieRadius =
false
;
isAutoPosition =
false
;
isMoveOut =
false
;
_direction = DEFAULT;
}
void
Joystick::onRun()
{
listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(
false
);
listener->onTouchBegan = CC_CALLBACK_2(Joystick::onTouchBegan,
this
);
listener->onTouchMoved = CC_CALLBACK_2(Joystick::onTouchMoved,
this
);
listener->onTouchEnded = CC_CALLBACK_2(Joystick::onTouchEnded,
this
);
this
->_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,
this
);
}
bool
Joystick::onTouchBegan(Touch* touch,Event* event)
{
Vec2 locationInNode =
this
->convertToNodeSpace(touch->getLocation());
if
( isAutoPosition )
{
this
->setPosition(touch->getLocation());
return
true
;
}
if
( isAutoPosition==
false
&& isDieRadius )
{
if
( locationInNode.getLength() > _radius )
{
return
false
;
}
}
_touchDot->setPosition(locationInNode);
if
( locationInNode.getLength() > _failradius )
{
changeAngle(locationInNode);
}
return
true
;
}
void
Joystick::onTouchMoved(Touch* touch,Event* event)
{
Vec2 locationInNode =
this
->convertToNodeSpace(touch->getLocation());
if
( isDieRadius )
{
if
( locationInNode.getLength() < _radius )
{
if
( isMoveOut )
{
_touchDot->setPosition(locationInNode);
isMoveOut =
false
;
}
setTouchDotPosition(locationInNode,_touchDot->getPosition() + touch->getDelta());
return
;
}
}
else
{
setTouchDotPosition(locationInNode,_touchDot->getPosition() + touch->getDelta());
return
;
}
isMoveOut =
true
;
_touchDot->setPosition(0,0);
resetState();
}
void
Joystick::onTouchEnded(Touch* touch,Event* event)
{
_touchDot->setPosition(0,0);
isMoveOut =
false
;
resetState();
}
void
Joystick::setTouchDotPosition(Vec2 vec1,Vec2 vec2)
{
_touchDot->setPosition(vec2);
if
( _failradius>0 )
{
if
( vec1.getLength() < _failradius )
{
resetState();
return
;
}
}
changeAngle(vec1);
}
void
Joystick::setDieRadius(
float
radius)
{
_radius = radius;
isDieRadius =
true
;
}
void
Joystick::setAutoPosition(
bool
value)
{
isAutoPosition = value;
}
void
Joystick::setFailRadius(
float
radius)
{
_failradius = radius;
}
void
Joystick::onDisable()
{
this
->_eventDispatcher->removeEventListener(listener);
isDieRadius =
false
;
isAutoPosition =
false
;
isMoveOut =
false
;
}
void
Joystick::changeAngle( Vec2 position )
{
auto angle = CC_RADIANS_TO_DEGREES(position.getAngle());
if
(angle > -22.5 && angle < 22.5)
{
_direction=D_RIGHT;
}
else
if
(angle > 22.5 && angle < 67.5)
{
_direction=D_RIGHT_UP;
}
else
if
(angle > 67.5 && angle < 112.5)
{
_direction=D_UP;
}
else
if
(angle > 112.5 && angle < 157.5)
{
_direction=D_LEFT_UP;
}
else
if
((angle > 157.5 && angle < 180)||(angle < -157.5 && angle > -180))
{
_direction=D_LEFT;
}
else
if
(angle < -112.5 && angle > -157.5)
{
_direction=D_LEFT_DOWN;
}
else
if
(angle < -67.5 && angle > -112.5)
{
_direction=D_DOWN;
}
else
if
(angle < -22.5 && angle > -67.5)
{
_direction=D_RIGHT_DOWN;
}
callDirectionFun();
}
void
Joystick::callDirectionFun()
{
if
( onDirection )
{
onDirection(_direction);
}
}
void
Joystick::resetState()
{
if
(_direction != DEFAULT)
{
_direction = DEFAULT;
callDirectionFun();
}
}
void
Joystick::setVisibleJoystick(
bool
visible)
{
_chassis->setVisible(visible);
_touchDot->setVisible(visible);
}
|
当然,如果有用到的朋友可以自己修改。这只是最简单的实现。
下面有效果图,不过加载比较慢
普通模式:
1
2
3
4
5
|
auto joystick = Joystick::create(
"rocker.png"
,
"rocker_joy.png"
);
//通过两张图片初始化控件
this
->addChild(joystick);
joystick->setPosition(VisibleRect::leftBottom()+Vec2(200,200));
//設置初始位置
joystick->onDirection=CC_CALLBACK_1(SceneMain::onDirection,
this
);
//角度变化更新(onDirection(JoystickEnum enums))
joystick->onRun();
//启动
|
存在死亡半径模式:(超出死亡半径将触点重置初始位置,移动失效)
1
2
3
4
5
6
|
auto joystick = Joystick::create(
"rocker.png"
,
"rocker_joy.png"
);
//通过两张图片初始化控件
this
->addChild(joystick);
joystick->setPosition(VisibleRect::leftBottom()+Vec2(200,200));
//设置初始位置
joystick->setDieRadius(60);
//设置死亡半径(外圈)
joystick->onDirection=CC_CALLBACK_1(SceneMain::onDirection,
this
);
//角度变化更新(onDirection(JoystickEnum enums))
joystick->onRun();
//启动
|
设置失效半径:(在失效半径内将不会触发角度改变事件)
1
2
3
4
5
6
7
|
auto joystick = Joystick::create(
"rocker.png"
,
"rocker_joy.png"
);
//通过两张图片初始化控件
this
->addChild(joystick);
joystick->setPosition(VisibleRect::leftBottom()+Vec2(200,200));
//设置初始位置
joystick->setDieRadius(60);
//设置死亡半径(外圈)
joystick->setFailRadius(30);
//设置失效半径(內圈)
joystick->onDirection=CC_CALLBACK_1(SceneMain::onDirection,
this
);
//角度变化更新(onDirection(JoystickEnum enums))
joystick->onRun();
//启动
|
设置自由变换位置:以鼠标按下的坐标为初始位置
1
2
3
4
5
6
|
auto joystick = Joystick::create(
"rocker.png"
,
"rocker_joy.png"
);
//通过两张图片初始化控件
this
->addChild(joystick);
joystick->setPosition(VisibleRect::leftBottom()+Vec2(200,200));
//设置初始位置
joystick->setAutoPosition(
true
);
//是否自由改变坐标
joystick->onDirection=CC_CALLBACK_1(SceneMain::onDirection,
this
);
//角度变化更新
joystick->onRun();
//启动
|
设置隐藏摇杆:(不显示摇杆底盘和触点,一般会设置成自由改变位置)
1
2
3
4
5
6
7
|
auto joystick = Joystick::create(
"rocker.png"
,
"rocker_joy.png"
);
//通过两张图片初始化控件
this
->addChild(joystick);
joystick->setPosition(VisibleRect::leftBottom()+Vec2(200,200));
//设置初始位置
joystick->setAutoPosition(
true
);
//是否自由改变坐标
joystick->setVisibleJoystick(
false
);
//是否显示
joystick->onDirection=CC_CALLBACK_1(SceneMain::onDirection,
this
);
//角度变化更新
joystick->onRun();
//启动
|