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

手游摇杆:

(零)摇杆设计原理
(一)最简单的四方向摇杆
(二)八方向摇杆和移动范围限制
(三)跟随式摇杆


前一篇博客实现的固定式摇杆,市面上很多游戏中都使用了这种方式。最后提到了一个不是太理想的点,在转向时需要移动的位置远,操作比较累;为了解决这个问题,出现了跟随式摇杆。

一 什么是跟随式摇杆

所谓跟随式摇杆,即:

  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的距离,即可完成转向。

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

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值