Cocos Creator 3D 操纵杆

1,684 阅读4分钟

打算写一个Cocos Creator 3D组件系列的文章

记录下平时常用的组件,减少开发时间,如果有更好的实现方法,欢迎交流

这篇是实现一个操纵杆,先上效果

项目地址,欢迎Start

项目预览

1 实现了什么

  • 支持跟随手指操纵杆出现位置
  • 支持4向、8向、任意方向移动

2 跟随实现

首先监听屏幕上的触摸事件,分别为

  1. 触摸开始
  2. 触摸移动
  3. 触摸结束
  4. 触摸取消

如下:

this.node.on(Node.EventType.TOUCH_START, this.callbackTOUCH_START, this);
this.node.on(Node.EventType.TOUCH_MOVE, this.callbackTOUCH_MOVE, this);
this.node.on(Node.EventType.TOUCH_END, this.callbackTOUCH_END, this);
this.node.on(Node.EventType.TOUCH_CANCEL, this.callbackTOUCH_CANCEL, this);

当用户在屏幕上触摸开始时,就刚点击屏幕的一瞬间,获取到手指触摸屏幕的位置,设置操纵杆的位置为手指触摸的位置,实现如下:

let UITC: UITransformComponent = this.node.getComponent(UITransformComponent);//ui坐标转化组件
let localPosition: Vec3 = new Vec3();
let touch: Touch = event.touch;//触摸事件,存储触摸的位置坐标等
UITC.convertToNodeSpaceAR(new Vec3(touch.getUILocation().x, touch.getUILocation().y, 0), localPosition);//转化坐标
this.node.getChildByName("joystickBg").setPosition(localPosition);
this.node.getChildByName("joystickBar").setPosition(localPosition);

在Cocos3D中坐标转化需要拿到一个UITransformComponent组件,通过获取到手指触摸的ui坐标转化为操纵杆需要的本地坐标

上述就简单实现了跟随功能,难点是在坐标转化

3 方向移动实现

3.1 方向移动

我们之前监听了触摸移动事件,这时候需要用到了,思路如下

  1. 拿到手指移动时候的触摸点的位置坐标,判断手机的触摸点是在操控杆的圆内,返回操纵点的最后位置,并设置操纵杆的点的位置
  2. 判断触摸点方向,四向或者八向或者任意方向

3.1.1 设置操纵杆点的位置

获取手指触摸点离操纵杆的距离,判断是否在圆内

在园内就直接设置触摸点的坐标为操纵杆圆点的坐标

不在园内就获取该触摸点和操纵杆圆点所在直线和圆的交点,通过向量,取一方向的交点为设置操纵杆圆点的坐标

/**
  * 获取两点间的距离
  * @param p1 点1
  * @param p2 点2
  */
private getDistance(p1: Vec2, p2: Vec2): number {
    return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}

let dis = this.getDistance(nodePositionV2, cameraPt);//获取两点之间的距离,判断是否在园内
//距离和半径做比较
if (dis < rx) { //在园内
     result = cameraPt;//手指触摸点位置为操纵杆圆点位置
} else {
     let intersectionPosition = this.getInsertPointBetweenCircleAndLine(nodePositionV2, cameraPt, rx);//获取到圆外的点和圆之间的交点
     let sub = cameraPt.subtract(nodePositionV2);//向量减法,判断方向
     if (sub.x > 0) {
         result = intersectionPosition[0];
      } else {
         result = intersectionPosition[1];
     }

  }

3.2 判断触摸点方向

拿到触摸点移动的位置和操纵杆中心的位置

3.2.1 四方向

触摸点和操纵杆原点相减

let x = touchPosition.x - localPosition.x;//x方向的位移
let y = touchPosition.y - localPosition.y;//y方向的位移

判断x方向的位移是否大于y方向的位移,如果大于,则向左或者向右移动,反之亦然。再判断x是否大于0来判断向左或者向右位移

if (Math.abs(x) > Math.abs(y)) {
     if (x > 0) {
        this.direction = Dir.RIGHT;
     } else {
        this.direction = Dir.LEFT;
     }
} else {
     if (y > 0) {
        this.direction = Dir.UP;
     } else {
        his.direction = Dir.DOWN;
     }
}

3.2.2 八方向

我们把360度分成了8份,一个方向为45度,正右边为0度,所以-22.5到22.5为右方向,依次列出8个方向

我们通过点获取弧度,通过弧度获取角度,实现如下:

//弧度
let radian = Math.atan2(y, x);

//角度 = 弧度 * 180 / Math.PI;
let angel = radian * 180 / Math.PI;

//angel: +x:0 +y:90 -x:(180||-180) -y:-90

atan2函数返回的是原点至点(x,y)的方位角,即与 x 轴的夹角。也可以理解为复数 x+yi 的辐角。返回值的单位为弧度

设置方向

if (angel >= -22.5 && angel < 22.5) {
     this.direction = Dir.RIGHT;
} else if (angel >= 22.5 && angel < 67.5) {
     this.direction = Dir.UPRIGHT;
} else if (angel >= 67.5 && angel < 112.5) {
     this.direction = Dir.UP;
} else if (angel >= 112.5 && angel < 157.5) {
     this.direction = Dir.UPLEFT;
} else if ((angel >= 157.5 && angel <= 180) || (angel >= -180 && angel < -157.5)) {//特殊处理临界点
     this.direction = Dir.LEFT;
} else if (angel >= -157.5 && angel < -112.5) {
     this.direction = Dir.DOWNLEFT;
} else if (angel >= -112.5 && angel < -67.5) {
     this.direction = Dir.DOWN;
} else if (angel >= -67.5 && angel < -22.5) {
     this.direction = Dir.DOWNRIGHT;
}

3.2.3 任意方向

和八方向一致,先拿到角度,在转化为人物的角度,

let radian = Math.atan2(y, x);
let angelLocal = radian * 180 / Math.PI;

//angelLocal: +x:0 +y:90 -x:(180||-180) -y:-90

if (angelLocal >= -90 && angelLocal <= 180) {//坐标转化
     this.angel = angelLocal + 90;
} else if (angelLocal >= -180 && angelLocal < -90) {
     this.angel = angelLocal + 450;
}

//angel: +x:90 +y:180 -x:270 -y:360

人物的旋转角度为0~360,点的角度为0~180,需要再次转化坐标

在任意角度中,除了需要转方向,还需要求出在x方向和y方向的占比,赋予x方向速度多少和y方向速度多少

x = Math.sin(Math.PI/180*this.angel);
y = Math.cos(Math.PI/180*this.angel);

在四方向和八方向中操纵杆默认是1的速度,人物可以设置自己的速度

任意方向中需要获取x或者y向的速度

最后

完整代码已经上传至github https://github.com/keien411/eat_food_3d,

项目预览

欢迎来收藏订阅

不定期更新cocos creator3D 组件代码。

本文使用 mdnice 排版