手游摇杆(三)跟随式摇杆

发表于2017-12-13
评论0 1.2k浏览

前面一片文章给大家介绍了八方向摇杆和移动范围限制,基本相当于一个固定式摇杆,大家可以在很多手游中看到,但在最后也提出了一个不是太好的地方,就是转向需要移动的位置比较远,操作比较累,为了解决这个问题,出现了跟随式摇杆,下面就来给大家介绍下什么是跟随式摇杆。

一、什么是跟随式摇杆

所谓跟随式摇杆,即:

  1. 当摇杆中心在摇杆大圆范围内时,跟固定式一样,大圆不动,中心移动;
  2. 当遥感中心移动到大圆范围外时,大圆跟中心保持相对位置不变,大圆移动。
二、位置计算

在大圆内移动的计算跟前面的基本一样,主要看下超出之后的计算过程。 
如图摇杆在触摸时的位置:

移动后的位置如下:

抽象出来即为:

三、示例

首先,修改前面的工程,将spRokerCenter从spRoker中拖出来,如图:

然后将上面计算过程换成代码:

cc.Class({
    extends: cc.Component,
    properties: {
        spPlayer: cc.Sprite,
        spRoker: cc.Sprite,
        spRokerCenter: cc.Sprite,
        moveSpeed: {
            type: cc.Float,
            default: 1
        },
        maxRadius: {
            type: cc.Float,
            default: 100
        }
    },
    onLoad: function () {
        this.oriRokerPos = this.spRoker.node.getPosition();
        this.oriRokerCenterPos = this.spRokerCenter.node.getPosition();
        this.spRoker.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.spRoker.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.spRoker.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
        this.spRoker.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
    },
    onTouchStart: function(event) {
        var touchPos = event.getLocation();
        var pos = this.spRoker.node.parent.convertToNodeSpaceAR(touchPos);
        var dir = this.getDirection(pos);
        this.moveDir = this.getDirection(pos);
        this.updateRokerPos(pos);
    },
    onTouchMove: function(event) {
        var touchPos = event.getLocation();
        var pos = this.spRoker.node.parent.convertToNodeSpaceAR(touchPos);
        this.moveDir = this.getDirection(pos);
        this.updateRokerPos(pos);
    },
    onTouchEnd: function(event) {
        this.spRokerCenter.node.setPosition(this.oriRokerCenterPos);
        this.spRoker.node.setPosition(this.oriRokerPos);
        this.moveDir = null;
    },
    onTouchCancel: function(event) {
        this.spRokerCenter.node.setPosition(this.oriRokerCenterPos);
        this.spRoker.node.setPosition(this.oriRokerPos);
        this.moveDir = null;
    },
    getDirection: function(pos) {
        var oriPos = this.spRoker.node.getPosition();
        var rad = Math.atan2(pos.y - oriPos.y, pos.x - oriPos.x);// [-PI, PI]
        if ((rad >= -Math.PI / 8 && rad < 0) || (rad >= 0 && rad < Math.PI / 8)) {
            return cc.v2(1, 0);// 右
        } else if (rad >= Math.PI / 8 && rad < 3 * Math.PI / 8) {
            return cc.v2(1, 1);// 右上
        } else if (rad >= 3 * Math.PI / 8 && rad < 5 * Math.PI / 8) {
            return cc.v2(0, 1);// 上
        } else if (rad >= 5 * Math.PI / 8 && rad < 7 * Math.PI / 8) {
            return cc.v2(-1, 1);// 左上
        } else if ((rad >= 7 * Math.PI / 8 && rad < Math.PI) || (rad >= -Math.PI && rad < -7 * Math.PI / 8)) {
            return cc.v2(-1, 0);// 左
        } else if (rad >= -7 * Math.PI / 8 && rad < -5 * Math.PI / 8) {
            return cc.v2(-1, -1);// 左下
        } else if (rad >= -5 * Math.PI / 8 && rad < -3 * Math.PI / 8) {
            return cc.v2(0, -1);// 下
        } else {
            return cc.v2(1, -1);// 右下
        }
    },
    updateRokerPos: function(pos) {
        this.spRokerCenter.node.setPosition(pos);
        var oriPos = this.spRoker.node.getPosition();
        var subVec = cc.v2(pos.x - oriPos.x, pos.y - oriPos.y);
        var len = subVec.mag();
        if (len > this.maxRadius) {
            var rate = this.maxRadius / len;
            var x = pos.x + (oriPos.x - pos.x) * rate;
            var y = pos.y + (oriPos.y - pos.y) * rate;
            this.spRoker.node.setPosition(x, y);
        }
    },
    updatePlayerPos: function(dir) {
        var size = cc.director.getWinSize();
        var x = this.spPlayer.node.x + dir.x * this.moveSpeed;
        var maxX = size.width * 0.5 - this.spPlayer.node.width * 0.5;
        var x = x > 0 ? Math.min(x, maxX) : Math.max(x, -maxX);
        var y = this.spPlayer.node.y + dir.y * this.moveSpeed;
        var maxY = size.height * 0.5 - this.spPlayer.node.height * 0.5;
        var y = y > 0 ? Math.min(y, maxY) : Math.max(y, -maxY);
        this.spPlayer.node.setPosition(x, y);
    },
    update: function(dt) {
        if (this.moveDir) {
            this.updatePlayerPos(this.moveDir);
        }
    },
});

这样就解决了前一篇文章最后提出的,转向时手指需要移动很远的问题,跟随式最多只需要移动一个maxRadius的距离,即可完成转向。

当前市面的游戏主要就是这两种操作方式。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: