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

  • 相关阅读:
    FZU 1759 欧拉函数 降幂公式
    51nod 1126 矩阵快速幂 水
    Codeforces Round #325 (Div. 2) D bfs
    Codeforces Round #379 (Div. 2) A B C D 水 二分 模拟
    Codeforces Round #284 (Div. 2)A B C 模拟 数学
    CentOS 7 rsync
    子进程 已安装 pre-removal 脚本 返回了错误号 1或2 与 子进程 已安装 post-installation 脚本 返回了错误号 1或2
    VirtualBox
    Eclipse 安装 HDFS 插件
    docker log 文件 清理
  • 原文地址:https://www.cnblogs.com/Richard-Core/p/3915898.html
Copyright © 2020-2023  润新知