手游摇杆(三)跟随式摇杆
发表于2017-12-13
前面一片文章给大家介绍了八方向摇杆和移动范围限制,基本相当于一个固定式摇杆,大家可以在很多手游中看到,但在最后也提出了一个不是太好的地方,就是转向需要移动的位置比较远,操作比较累,为了解决这个问题,出现了跟随式摇杆,下面就来给大家介绍下什么是跟随式摇杆。
一、什么是跟随式摇杆
所谓跟随式摇杆,即:
- 当摇杆中心在摇杆大圆范围内时,跟固定式一样,大圆不动,中心移动;
- 当遥感中心移动到大圆范围外时,大圆跟中心保持相对位置不变,大圆移动。
二、位置计算
在大圆内移动的计算跟前面的基本一样,主要看下超出之后的计算过程。
如图摇杆在触摸时的位置:
移动后的位置如下:
抽象出来即为:
三、示例
首先,修改前面的工程,将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的距离,即可完成转向。
当前市面的游戏主要就是这两种操作方式。