Joystick 摇杆控件

本文转载至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();//启动

1408606310243864.gif

 

存在死亡半径模式:(超出死亡半径将触点重置初始位置,移动失效)

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();//启动

1408606352236053.gif

 

设置失效半径:(在失效半径内将不会触发角度改变事件)

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();//启动

1408606384119875.gif

 

设置自由变换位置:以鼠标按下的坐标为初始位置

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();//启动

1408606989191417.gif

 

设置隐藏摇杆:(不显示摇杆底盘和触点,一般会设置成自由改变位置)

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();//启动

1408606470587043.gif

 

posted @ 2015-06-11 19:02  silent-bobo  阅读(375)  评论(0编辑  收藏  举报