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
};

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
#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);
}

當然,如果有用到的朋友可以自己修改。這隻是最簡單的實現。

下面有效果圖,不過加載比較慢:

普通模式

  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();//啟動

存在死亡半徑模式:(超出死亡半徑將觸點重置初始位置,移動失效)

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();//啟動

設置失效半徑:(在失效半徑內將不會觸發角度改變事件)

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();//啟動

設置自由變換位置:以鼠標按下的座標為初始位置

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();//啟動

設置隱藏搖杆:(不顯示搖杆底盤和觸點,一般會設置成自由改變位置)

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();//啟動

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

时间: 2024-10-15 20:15:58

Cocos2d-x 3.2 学习笔记(十)Joystick 搖杆控件的相关文章

Silverlight学习笔记(三):控件布局管理

简介: 学习Silverlight控件在页面上是如何进行布局,实现多种复杂布局 一.常见的三种布局方式 1. Silverlight学习笔记(三):控件布局管理,码迷,mamicode.com

Android学习笔记(七)——常见控件

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! Android 给我们提供了大量的 UI控件,下面我们简单试试几种常用的控件. 一.TextView 在布局文件中加入TextView元素: 1 <TextView android:text="This is TextView!" 2 android:gravity="center" 3 android:layout_width="match_parent&qu

C#学习笔记(20140910)-单选控件和单选组控件、复选控件、复选组控件

晚上学习了一下单选控件和单选组控件.复选控件.复选组控件. 稍微动了点脑筋,做了一个小小的网页程序.主要功能是相互赋值已经设置标签的字体大小和颜色已经前后背景色. 主要功能: 1. 在文本输入框中输入文字,提交后可以对标签赋值: 2. 选择单选框可以给标签赋值: 3. 选择单选组控件时可以给标签设置颜色: 4. 选择单选组控件时可以给字体设置大小. 最后的效果如下: 分块设置就不多说了,看看用到了哪些模块吧: 1. 自定义了一个方法,把标签的值赋值给输入框.使得输入框中的内容和标签的内容一致.

cocos2d-x学习笔记(六)TextBMFont控件显示中文乱码或者无法显示

今天用cocos studio加了一个TextBMFont控件,然后需要动态修改TextBMFont控件显示的字符串,用来显示中文的,结果一直无法修改TextBMFont控件的值,最后原来是写到xml文件的中文字符串没有保存成UTF-8格式. ===================================================================================== 记录一下完整实现步骤 一.制作BMFont字体 1.下载并安装BMFont软件 2.

Excel开发学习笔记:界面交互与控件的布局

除了业务逻辑之外,比较耗时耗力的就是人机交互了.在编写excel定制程序的过程中,这次用到了以下几种交互方式: 通过excel工作表(worksheet)获取用户输入 通过按钮控件触发功能代码执行 通过TreeView控件显示内容摘要及导航 通过自定义的windows窗体提供交互 工作表的操作放到后面再说,讲一下按钮控件button和Treeview控件的布局. 放置控件的方法: 无非可视化放置和运行时代码加载两种.可视化放置比较直观,通过visual studio的toolbox工具栏拖动需要

C#学习笔记(20140909)-按钮控件:单击事件和command事件

在 Web 应用程序和用户交互时,常常需要提交表单.获取表单信息等操作.在这其间,按钮控件是非常必要的.按钮控件能够触发事件,或者将网页中的信息回传给服务器.在 ASP.NET 中,包含三类按钮控件,分别为 Button.LinkButton.ImageButton. Click 单击事件 在Click 单击事件中,通常用于编写用户单击按钮时所需要执行的事件,这种事件很简单,用户单击一个按钮,就会执行按钮中的代码. Command 命令事件 按钮控件中,Click 事件并不能传递参数,所以处理的

.net core 学习笔记(1)-分页控件的使用

最近有个小项目,用.net core开发练练手,碰到的第一个问题就是分页控件的问题,自己写太费时间,上网查了下,发现有人已经封装好了的,就拿过来用了,分页控件github:https://github.com/sgjsakura/AspNetCore/blob/master/PagerDemo.md 使用方法也很简单 后台代码如下:期中list是数据返回的数据,pagesize是每页的数量,page是当前页数,totalcount-总条数,pagenum-总页数 var model= new P

Swift学习笔记十二:下标脚本(subscript)

下标脚本就是对一个东西通过索引,快速取值的一种语法,例如数组的a[0].这就是一个下标脚本.通过索引0来快速取值.在Swift中,我们可以对类(Class).结构体(structure)和枚举(enumeration)中自己定义下标脚本的语法 一.常规定义 class Student{ var scores:Int[] = Array(count:5,repeatedValue:0) subscript(index:Int) -> Int{ get{ return scores[index];

第十七篇:实例分析(3)--初探WDDM驱动学习笔记(十)

续: 还是记录一下, BltFuncs.cpp中的函数作用: CONVERT_32BPP_TO_16BPP 是将32bit的pixel转换成16bit的形式. 输入是DWORD 32位中, BYTE 0,1,2分别是RGB分量, 而BYTE3则是不用的 为了不减少color的范围, 所以,都是取RGB8,8,8的高RGB5, 6, 5位, 然后将这16位构成一个pixel. CONVERT_16BPP_TO_32BPP是将16bit的pixel转换成32bit的形式 输入是WORD 16BIT中