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

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


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

时间: 2024-11-03 21:08:42

Joystick 摇杆控件的相关文章

unity5.3+Easytouch4.3——EasyTouch及摇杆控件介绍

一.EasyTouch插件介绍 本文总结时,目前网上可以很方便的下载到EasyTouch4.3版本(额--你懂什么叫很方便的),由于某些版本和版本之间还是有很多改动,在此特意声明一下该文使用的版本是4.3,但插件的大体框架不会变动很多,也可以参考一下.有能力购买正版的童鞋也可以到官网支持一下EasyTouch. EasyTouch4.3版本开始已经支持UGUI,所以unity版本低于4.6的话是将不能使用这个版本EasyTouch,目前EasyTouch4.3亲测可以结合unity4.6~5.3

Cocos2d-x 3.2 学习笔记(十)Joystick 搖杆控件

最近想做格鬥遊戲,那麼就要有搖杆控件,不想去看別人的代碼就自己寫了個搖杆控件,實現起來很簡單. 話不多說,看代碼: #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 };

在DataGridView控件中实现冻结列分界线

我们在使用Office Excel的时候,有很多时候需要冻结行或者列.这时,Excel会在冻结的行列和非冻结的区域之间绘制上一条明显的黑线.如下图: (图1) WinForm下的DataGridView控件也能实现类似的冻结行或者列的功能(参见:http://msdn.microsoft.com/zh-cn/library/28e9w2e1(VS.85).aspx) ,但是呢,DataGridView控件默认不会在冻结列或者行的分界处绘制一个明显的分界线,这样的话,最终用户很难注意到当前有列或者

摆脱Login控件,自己定义登录操作

protected void ImageButton1_Click(object sender, ImageClickEventArgs e) { //在登录过程中,程序自动使用login.aspx进行拦截 //验证用户通过后,自动返回拦截的位置 if (Membership.ValidateUser(this.TextBox1.Text, this.TextBox2.Text)) { this.Session["xh"] = this.TextBox1.Text; FormsAuth

python selenium 处理时间日期控件(十五)

测试过程中经常遇到时间控件,需要我们来选择日期,一般处理时间控件通过层级定位来操作或者通过调用js来实现. 1.首先我们看一下如何通过层级定位来操作时间控件. 通过示例图可以看到,日期控件是无法输入日期,点击后弹出日期列表供我们选择日期,自己找了一个日期控制演示一下,通过两次定位,选择了日期 #-*- coding:utf-8 -*- import time from selenium import webdriver driver = webdriver.Chrome() driver.get

Delphi XE10 dxLayoutControl 控件应用指南

http://www.cnblogs.com/Bonny.Wong/p/7440288.html DevExpress VCL套件是一套非常强大的界面控件,可惜关于Delphi开发方面的说明太少,有些控件使用起来一头雾水,不知从何下手.本节详细介绍在Delphi Xe10 Seattle中如何利用dxLayoutControl 控件来做界面布局. 1.  首先从工具箱面板中将dxLayoutControl放在Form上,设置2个关键属性如下: 属性 属性值 说明 Align alClient 一

Android自己定义控件之轮播图控件

背景 近期要做一个轮播图的效果.网上看了几篇文章.基本上都能找到实现,效果还挺不错,可是在写的时候感觉每次都要单独去又一次在Activity里写一堆代码.于是自己封装了一下.这里仅仅是做了下封装成一个控件,不必每次反复写代码了. 效果图 实现分析 轮播图的功能就是实现左右滑动的广告.图片信息展示,那我们就用ViewPager来实现,由于考虑到用户体验,我们还须要在以下加一个指示器来标示滑动到了第几张轮播图.指示器我们能够用一个线性布局来依据要展示的轮播图设置显示的View,我们要做这种一个控件没

[ ObjectListView ] - ListView的增强控件 - 前言 (翻译)

********************************************************************************** 原  标 题: A Much Easier to Use ListView 原文地址: https://www.codeproject.com/Articles/16009/A-Much-Easier-to-Use-ListView 翻       译: 于国栋 http://www.shannon.net.cn *********

MFC 加入背景图片并让控件背景透明

/*加入背景图片*/ BOOL CTOOLDlg::OnEraseBkgnd(CDC* pDC) { // TODO: 在此加入消息处理程序代码和/或调用默认值 CDialog::OnEraseBkgnd(pDC); HBITMAP   m_hBitmap; HDC           m_hBkDC; m_hBitmap   =   ::LoadBitmap(::GetModuleHandle(NULL),MAKEINTRESOURCE(IDB_BITMAP2)); m_hBkDC     =