天天看點

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

Cocos Creator制作一個虛拟搖杆

  • 1. 示範
    • 版本:v2.4.3
    • 語言:TS
    • 示範GIF
  • 2. 實作過程
    • 素材
    • 期望效果
    • 過程
      • (1)搖杆跟随觸摸
      • (2)搖杆自動歸位
      • (3)限制搖杆不出界
        • 原理:
      • (4)添加箭頭
        • 原理:
    • 主腳本編寫
      • (1)主腳本部分實作功能
      • (2)示範
      • (3)實作
        • 搖杆腳本部分
        • 主腳本部分
  • 第一次發文章,若有錯誤望大佬們指正。
    • 源碼

1. 示範

版本:v2.4.3

語言:TS

示範GIF

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

2. 實作過程

素材

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。
Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。
Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

期望效果

  • 類似于王者榮耀的那種小搖杆
  • 搖杆中心位置為螢幕點選的位置
  • 搖杆點選部分不會出界

過程

(1)搖杆跟随觸摸

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。
this.Joystick = this.node.getChildByName("Joystick");
	// 此處監聽的joystick為搖杆
    this.Joystick.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
    onTouchMove(e: cc.Event.EventTouch) {
   		this.JoystickMove(e)
   	}
   	JoystickMove(e: cc.Event.EventTouch) {
        // 移動
        let delta = e.getDelta();
        let moveDistance = cc.v3(delta.x / this.node.scale, delta.y / this.node.scale) 
        // 此處增加縮放參數為了友善,使用時可以直接縮放大小
        this.Joystick.setPosition(this.Joystick.position.add(moveDistance)) 
   	}
           
Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

此時可以實作觸摸點跟随手指或者滑鼠移動。getDelta函數是擷取觸點距離上一次事件移動的距離對象,傳回的是一個Vec2。但此時搖杆不會自動歸位。

(2)搖杆自動歸位

this.Joystick.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
	this.Joystick.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
	onTouchEnd(e: cc.Event.EventTouch) {
	    this.JoystickReset()
	}
	onTouchCancel(e: cc.Event.EventTouch) {
	    this.JoystickReset()
	}
	JoystickReset() {
	    cc.tween(this.Joystick)
	        .to(0.05, {x: 0, y: 0})
	        .start()
	}
           
Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

TOUCH_END, TOUCH_CANCEL代表的狀态為當手指在目标節點區域内離開螢幕時,當手指在目标節點區域外離開螢幕時。使用緩動使動畫更流暢。

(3)限制搖杆不出界

原理:

此處思路來源于CSDN章魚仔,通過三角形的相似等比。

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

完善JoystickMove代碼

JoystickMove(e: cc.Event.EventTouch) {
        // 移動
        let delta = e.getDelta();
        let moveDistance = cc.v3(delta.x / this.node.scale, delta.y / this.node.scale)
        // 加上縮放參數,更加友善實用
        this.Joystick.setPosition(this.Joystick.position.add(moveDistance))      
        // 轉換坐标
        let touchPos = e.getLocation();     // 以目前螢幕左下角為坐标系原點所獲得的的位置
        let touchPosInNode = this.node.convertToNodeSpaceAR(touchPos)
        let distanceBetweenTouchPosToJoystick = touchPosInNode.mag() * this.node.scale; // 此處縮放參數作用與前邊同理
        // 限制移動 < 半徑
        if (distanceBetweenTouchPosToJoystick > this.radius) {
            let lengthScale = this.radius / distanceBetweenTouchPosToJoystick;
            this.Joystick.x = touchPosInNode.x * lengthScale;
            this.Joystick.y = touchPosInNode.y * lengthScale;
        }
    }
           
Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

此時移動不會出界,而且可以任意調整縮放倍數都可以保持不出界狀态!

注意getLocation()函數傳回的坐标是以螢幕左下角為坐标中心的坐标,并不是世界坐标!

節點.convertToNodeSpaceAR(位置)傳回的是這個位置在這個節點下的位置。

(4)添加箭頭

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

完善代碼

onTouchMove(e: cc.Event.EventTouch) {
        this.JoystickMove(e)
        this.arrowDirection()
    }
    arrowDirection() {
        // 設定箭頭大小
        this.setArrowLength()
        // 計算夾角
        this.setArrow(cc.v2(this.Joystick.position))
    }
    setArrowLength() {
	    let arrowParamScale = this.Joystick.position.mag() * this.node.scale / this.radius;
	    this.arrow.width = this.arrowMaxLenth * arrowParamScale;    // 箭頭長度
	    this.arrow.opacity = 255 * arrowParamScale;     // 箭頭透明度
    }
    /**
     * 
     * @param JoystickPos 搖杆節點坐标 
     */
    setArrow(JoystickPos: cc.Vec2) {
        let dir = JoystickPos.sub(cc.v2(0, 0))
        let vec = cc.v2(0, 1);    // 水準向右的對比向量
        let radian = dir.signAngle(vec);    // 求方向向量與對比向量間的弧度
        let rotate = cc.misc.radiansToDegrees(radian);    // 将弧度轉換為角度
        this.arrow.angle = -rotate - 90;    // ***此處rotate正負值以及減去的角度根據自己的圖檔去修改***
    }
           

再完善一下搖杆回彈時的動畫,讓箭頭可以複原!

JoystickReset() {
        let time: number = 0.05;
        let arrowReset = cc.tween(this.arrow).to(time, {width: 0, opacity: 0})

        cc.tween(this.Joystick)
            .call(() => {
                arrowReset.start()
            })
            .to(time, {x: 0, y: 0})
            .start()
    }
           
Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

原理:

首先dir是搖杆的向量與搖杆中心的一個帶方向的向量差,若是求向量夾角必須有另外一個參考向量,此處定義為(0, 1),求出的值為弧度是以需要将弧度轉換為我們要的角度。

弧度轉角度公式: 角度 = 弧度 * 180 / PI

cocos中可以直接使用cc.misc.radiansToDegrees()

singAngle()函數源碼部分如下,如果對向量的叉乘、點乘的幾何意義不熟悉可以看一下:

/*
    * 帶方向的夾角的弧度。該方法僅用做相容 2D 計算。
    */
   signAngle (vector) {
       cc.warnID(1408, 'vec3.signAngle', 'v2.1', 'cc.v2(selfVector).signAngle(vector)');
       let vec1 = new Vec2(this.x, this.y);
       let vec2 = new Vec2(vector.x, vector.y);
       return vec1.signAngle(vec2);
   }
   /*
    * 帶方向的夾角的弧度。
    */
   signAngle (vector: Vec2): number {
       let angle = this.angle(vector);
       return this.cross(vector) < 0 ? -angle : angle;
   }
   /*
    * 夾角的弧度。
    */
   angle (vector: Vec2): number {
       var magSqr1 = this.magSqr();
       var magSqr2 = vector.magSqr();

       if (magSqr1 === 0 || magSqr2 === 0) {
           console.warn("Can't get angle between zero vector");
           return 0.0;
       }

       var dot = this.dot(vector);
       var theta = dot / (Math.sqrt(magSqr1 * magSqr2));
       theta = misc.clampf(theta, -1.0, 1.0);
       return Math.acos(theta);	// 反餘弦函數
   }
   /*
    * 目前向量與指定向量進行叉乘。
    */
   cross (vector: Vec2): number {
       return this.x * vector.y - this.y * vector.x;
   }

  /**
    *目前向量與指定向量進行點乘。
    */
   dot (vector: Vec2): number {
       return this.x * vector.x + this.y * vector.y;
   }
   /*
    * 限定浮點數的最大最小值。
    * 數值大于 max_inclusive 則傳回 max_inclusive。
    * 數值小于 min_inclusive 則傳回 min_inclusive。
    * 否則傳回自身。
    */
   misc.clampf = function (value, min_inclusive, max_inclusive) {
       if (min_inclusive > max_inclusive) {
           var temp = min_inclusive;
           min_inclusive = max_inclusive;
           max_inclusive = temp;
       }
       return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive;
   };
           

主腳本編寫

(1)主腳本部分實作功能

  • 更改觸摸範圍為全屏
  • 跨腳本調用搖杆
  • 移動物體

(2)示範

Cocos Creator制作一個虛拟搖杆1. 示範2. 實作過程第一次發文章,若有錯誤望大佬們指正。

(3)實作

搖杆腳本部分

// 傳回給調用者需要用到的參數
	returnArrowAngle() {
        let radin = cc.misc.degreesToRadians(-this.arrow.angle - 90);
        cc.log(this.arrow.angle)
        let vec = cc.v2(0, 1);
        let targetVec = vec.rotate(-radin);

        let data = {
            angle: this.arrow.angle,    // 角度
            vec: targetVec,
            speedScale: this.arrow.width / this.arrowMaxLenth,
            moveState: this.Joystick.x != 0 && this.Joystick.y != 0 ? true : false,
        }

        return data;
    }
           

原理與計算朝向原理差不多,隻是這次将角度轉為弧度,再通過将參考的向量旋轉指定弧度(radin)後,即可得出指定已知角度的向量!

主腳本部分

@property({type: cc.Node, displayName: "可點選區域"})
    touchArea: cc.Node = null;
	@property({type: cc.Node, displayName: "搖杆"})
    joystick: cc.Node = null;
    @property({type: cc.Node, displayName: "移動物體"})
    thing: cc.Node = null;
    // 此腳本腳本全局函數區
    joystickCom: joystick;
    moveSpeed = 0.5;
    moveRotate: number;
    // 設定點選區域監聽
    onLoad () {
        this.joystickCom = this.joystick.getComponent(joystick);
        this.touchArea.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
        this.touchArea.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
        this.touchArea.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
    }
	onTouchStart(e: cc.Event.EventTouch) {
        this.joystickCom.onTouchStart(e);
    }
    onTouchMove(e: cc.Event.EventTouch) {
        this.joystickCom.onTouchMove(e);
    }
    onTouchEnd(e: cc.Event.EventTouch) {
        this.joystickCom.onTouchEnd(e);
    }
	// 移動實作
    thingMove() {
        let joystickFun = this.joystickCom.returnArrowAngle()
        this.thing.angle = joystickFun.angle + 90;  // 自行調整
        if (joystickFun.moveState) {
            this.thing.setPosition(this.thing.position.add(
                cc.v3(
                    joystickFun.vec.x * 5 * joystickFun.speedScale, 
                    joystickFun.vec.y * 5 * joystickFun.speedScale
                )
            ))
        }
    }
    update (dt) {
        this.thingMove();
    }
}
           

第一次發文章,若有錯誤望大佬們指正。

源碼

密碼: agzg

繼續閱讀