天天看点

Cocos2d-js3.3 虚拟摇杆的实现

虚拟摇杆是在手机格斗游戏中经常看到的一个东西,今天就来了解一下如何在cocos2d-js实现一个虚拟摇杆...

首先,先来看一下这个虚拟摇杆的效果

默认类型(Default):

Cocos2d-js3.3 虚拟摇杆的实现

跟随类型(Follow):

Cocos2d-js3.3 虚拟摇杆的实现

下面,来看一下我实现的这个虚拟摇杆的创建方法:

var joystick = new Joystick(res.JoystickBG_png, 
                            res.Joystick_png, 
                            50, 
                            TouchType.DEFAULT, 
                            DirectionType.ALL, 
                            sprite);
joystick.setPosition(cc.p(100, 100));
joystick.setSpeedwithLevel1(1);
joystick.setSpeedwithLevel2(2);
//joystick.setOpacity(128);
//joystick.setEnable(true);
joystick.callback = this.onCallback.bind(this);
this.addChild(joystick, 0, 101);
           

可以看到,构造函数中传进了6个参数,分别是:

遥控杆的背景(底盘)图、遥控杆图、底盘半径、触摸类型、方向类型和要控制的目标

其中,触摸类型分为:默认(DEFAULT) 和跟随(FOLLOW)

方向类型分为:四方位(上下左右)、八方位(上下左右、左上左下、右上右下)、全方位

然后,我们可以设置摇杆的位置、速度1、速度2、透明度、是否可用、绑定回调函数。

这里解释一下,速度1和速度2,当控杆中心在底盘边缘,目标移动速度为速度2,否则移动速度为速度1

而绑定回调函数,是为了在控杆的角度变化时,能反馈过来,是否需要改变目标的朝向等。

最后,来看一下这个虚拟控杆类

var TouchType = {
    DEFAULT: "DEFAULT",
    FOLLOW: "FOLLOW"
};

var DirectionType = {
    FOUR: "FOUR",
    EIGHT: "EIGHT",
    ALL: "ALL"
};

var Joystick = cc.Node.extend({
    _stick: null,       //控杆
    _stickBG: null,     //控杆背景
    _listener: null,    //监听器
    _radius: 0,         //半径
    _angle: null,       //角度
    _radian: null,      //弧度
    _target: null,      //操控的目标
    _speed: 0,          //实际速度
    _speed1: 1,         //一段速度
    _speed2: 2,         //二段速度
    _touchType: null,   //触摸类型
    _directionType: null,   //方向类型
    _opacity: 0,        //透明度
    callback: null,     //回调函数
    ctor: function(stickBG, stick, radius, touchType, directionType, target)
    {
        this._super();
        this._target = target;
        this._touchType = touchType;
        this._directionType = directionType;

        //创建摇杆精灵
        this._createStickSprite(stickBG, stick, radius);

        //初始化触摸事件
        this._initTouchEvent();
    },

    _createStickSprite: function(stickBG, stick, radius)
    {
        this._radius = radius;

        if(this._touchType == TouchType.FOLLOW)
            this.setVisible(false);

        //摇杆背景精灵
        this._stickBG = new cc.Sprite(stickBG);
        this._stickBG.setPosition(cc.p(radius, radius));
        this.addChild(this._stickBG);

        //摇杆精灵
        this._stick = new cc.Sprite(stick);
        this._stick.setPosition(cc.p(radius, radius));
        this.addChild(this._stick);

        //根据半径设置缩放比例
        var scale = radius / (this._stickBG.getContentSize().width / 2);
        this._stickBG.setScale(scale);
        this._stick.setScale(scale);

        //设置大小
        this.setContentSize(this._stickBG.getBoundingBox());

        //设置锚点
        this.setAnchorPoint(cc.p(0.5, 0.5));
    },

    _initTouchEvent: function()
    {
        this._listener = cc.EventListener.create({
            event: cc.EventListener.TOUCH_ONE_BY_ONE,
            swallowTouches: false,
            onTouchBegan: this.onTouchBegan,
            onTouchMoved: this.onTouchMoved,
            onTouchEnded: this.onTouchEnded
        });

        //如果存在相同的对象,将被移除
        this.setUserObject(this._listener);

        //添加触摸监听
        cc.eventManager.addListener(this._listener, this._stickBG);
    },

    //计算角度并返回
    _getAngle: function(point)
    {
        var pos = this._stickBG.getPosition();
        this._angle = Math.atan2(point.y-pos.y, point.x-pos.x) * (180/cc.PI);
        return this._angle;
    },

    //计算弧度并返回
    _getRadian: function(point)
    {
        this._radian = cc.PI / 180 * this._getAngle(point);
        return this._radian;
    },

    //计算两点间的距离并返回
    _getDistance: function(pos1, pos2)
    {
        return Math.sqrt(Math.pow(pos1.x - pos2.x, 2) +
        Math.pow(pos1.y - pos2.y, 2));
    },

    onTouchBegan: function(touch, event)
    {
        //触摸监听目标
        var target = event.getCurrentTarget();

        //如果触摸类型为FOLLOW,则摇控杆的位置为触摸位置,触摸开始时候现形
        if(target.getParent()._touchType == TouchType.FOLLOW)
        {
            target.getParent().setPosition(touch.getLocation());
            target.getParent().setVisible(true);
            target.getParent().scheduleUpdate();
            return true;
        }
        else
        {
            //把触摸点坐标转换为相对与目标的模型坐标
            var touchPos = target.convertToNodeSpace(touch.getLocation());

            //点与圆心的距离
            var distance = target.getParent()._getDistance(touchPos, target);

            //圆的半径
            var radius = target.getBoundingBox().width / 2;

            //如果点与圆心距离小于圆的半径,返回true
            if(radius > distance)
            {
                target.getParent()._stick.setPosition(touchPos);
                target.getParent().scheduleUpdate();
                return true;
            }
        }
        return false;
    },

    onTouchMoved: function(touch, event)
    {
        //触摸监听目标
        var target = event.getCurrentTarget();

        //把触摸点坐标转换为相对与目标的模型坐标
        var touchPos = target.convertToNodeSpace(touch.getLocation());

        //点与圆心的距离
        var distance = target.getParent()._getDistance(touchPos, target);

        //圆的半径
        var radius = target.getBoundingBox().width / 2;

        //如果点与圆心距离小于圆的半径,控杆跟随触摸点
        if(radius > distance)
        {
            target.getParent()._stick.setPosition(touchPos);
        }
        else
        {
            var x = target.getPositionX() + Math.cos(target.getParent()._getRadian(touchPos)) * target.getParent()._radius;
            var y = target.getPositionY() + Math.sin(target.getParent()._getRadian(touchPos)) * target.getParent()._radius;
            target.getParent()._stick.setPosition(cc.p(x, y));
        }

        //更新角度
        target.getParent()._getAngle(touchPos);

        //设置实际速度
        target.getParent()._setSpeed(touchPos);

        //更新回调
        target.getParent()._updateCallback();
    },

    onTouchEnded: function(touch, event)
    {
        //触摸监听目标
        var target = event.getCurrentTarget();

        //如果触摸类型为FOLLOW,离开触摸后隐藏
        if(target.getParent()._touchType == TouchType.FOLLOW)
            target.getParent().setVisible(false);

        //摇杆恢复位置
        target.getParent()._stick.setPosition(target.getPosition());

        target.getParent().unscheduleUpdate();
    },

    //设置实际速度
    _setSpeed: function(point)
    {
        //触摸点和遥控杆中心的距离
        var distance = this._getDistance(point, this._stickBG.getPosition());

        //如果半径
        if(distance < this._radius)
        {
            this._speed = this._speed1;
        }
        else
        {
            this._speed = this._speed2;
        }
    },

    //更新回调
    _updateCallback: function()
    {
        if(this.callback && typeof(this.callback) === "function")
        {
            this.callback();
        }
    },

    //更新移动目标
    update: function(dt)
    {
        switch (this._directionType)
        {
            case DirectionType.FOUR:
                this._fourDirectionsMove();
                break;
            case DirectionType.EIGHT:
                this._eightDirectionsMove();
                break;
            case DirectionType.ALL:
                this._allDirectionsMove();
                break;
            default :
                break;
        }
    },

    //四个方向移动(上下左右)
    _fourDirectionsMove: function()
    {
        if(this._angle > 45 && this._angle < 135)
        {
            this._target.y += this._speed;
        }
        else if(this._angle > -135 && this._angle < -45)
        {
            this._target.y -= this._speed;
        }
        else if(this._angle < -135 && this._angle > -180 || this._angle > 135 && this._angle < 180)
        {
            this._target.x -= this._speed;
        }
        else if(this._angle < 0 && this._angle > -45 || this._angle > 0 && this._angle < 45)
        {
            this._target.x += this._speed;
        }
    },

    //八个方向移动(上下左右、左上、右上、左下、右下)
    _eightDirectionsMove: function()
    {
        if(this._angle > 67.5 && this._angle < 112.5)
        {
            this._target.y += this._speed;
        }
        else if(this._angle > -112.5 && this._angle < -67.5)
        {
            this._target.y -= this._speed;
        }
        else if(this._angle < -157.5 && this._angle > -180 || this._angle > 157.5 && this._angle < 180)
        {
            this._target.x -= this._speed;
        }
        else if(this._angle < 0 && this._angle > -22.5 || this._angle > 0 && this._angle < 22.5)
        {
            this._target.x += this._speed;
        }
        else if(this._angle > 112.5 && this._angle < 157.5)
        {
            this._target.x -= this._speed / 1.414;
            this._target.y += this._speed / 1.414;
        }
        else if(this._angle > 22.5 && this._angle < 67.5)
        {
            this._target.x += this._speed / 1.414;
            this._target.y += this._speed / 1.414;
        }
        else if(this._angle > -157.5 && this._angle < -112.5)
        {
            this._target.x -= this._speed / 1.414;
            this._target.y -= this._speed / 1.414;
        }
        else if(this._angle > -67.5 && this._angle < -22.5)
        {
            this._target.x += this._speed / 1.414;
            this._target.y -= this._speed / 1.414;
        }
    },

    //全方向移动
    _allDirectionsMove: function()
    {
        this._target.x += Math.cos(this._angle * (Math.PI/180)) * this._speed;
        this._target.y += Math.sin(this._angle * (Math.PI/180)) * this._speed;
    },

    //设置透明度
    setOpacity: function(opacity)
    {
        this._opacity = opacity;
        this._stick.setOpacity(opacity);
        this._stickBG.setOpacity(opacity);
    },

    //设置一段速度
    setSpeedwithLevel1: function(speed)
    {
        this._speed1 = speed;
    },

    //设置二段速度
    setSpeedwithLevel2: function(speed)
    {
        if(this._speed1 < speed)
        {
            this._speed2 = speed;
        }
        else
        {
            this._speed2 = this._speed2;
        }
    },

    //设置遥控杆开关
    setEnable: function(enable)
    {
        if(this._listener != null)
        {
            if(enable)
            {
                cc.eventManager.addListener(this._listener, this._stickBG);
            }
            else
            {
                cc.eventManager.removeListener(this._listener);
            }
        }
    },

    //获取角度
    getAngle: function()
    {
        return this._angle;
    },

    onExit: function()
    {
        this._super();
        //移除触摸监听
        if(this._listener != null)
        {
            cc.eventManager.removeListener(this._listener);
        }
    }
});
           

源码下载: 点击打开链接

继续阅读