反復橫跳的瞄准線!從向量計算說起!基於射線檢測的實現!Cocos Creator!


最近有小伙伴問我瞄准線遇到各種形狀該怎么處理?如何實現反復橫跳的瞄准線?最近剛好在《Cocos Creator游戲開發實戰》中看到物理系統有一個射線檢測,於是,基於這個射線檢測,寫了一個反復橫跳的瞄准線效果。一起往下看吧!文章底部獲取完整項目!

國際慣例,先上最終效果!

在講解之前我們需要一些向量的知識,簡單的介紹一些吧!

向量的加法,OA + AB = OB

向量的點乘,表示一個向量在另一個向量上的投影,是個標量,有正負之分。向量夾角小於 90度 為正數,等於 90度 為 零,大於 90度 為負數。

向量的叉乘,結果為向量,正好垂直於兩個向量構成的平面(右手系),也稱為法向量。這里暫時沒用到,順便提一下。

接下來進入正題,已知入射向量(單位向量),法向量(單位向量),如何得出反射向量?

我們將反射向量平移至入射向量起點,延長法向量與其相交,這個延長線的長度,剛好是 入射向量在法向量上的投影的相反數的兩倍 。再根據投影和向量加法可以推出反射向量的計算公式。

清楚了么?不清楚也沒關系,記得最后的公式就可以了,接下來進入 cocos creator 操作環節。

既然是物理系統中的碰撞檢測,我們在編輯器里添加的是物理系統中的碰撞器,而不是引擎的碰撞器,不要選錯了哦。

不動的剛體類型設為 static ,添加完所有的物理碰撞器后如下所示。

用到物理引擎自然要把物理引擎打開。

cc.director.getPhysicsManager().enabled = true;

如何進行射線檢測的?通過起始點、入射方向和剩余線段的長度獲取射線檢測的結果。如果檢測到碰撞體,就畫入射線段,並計算反射方向,再次進行射線檢測;如果未檢測到碰撞體,就把剩余線段畫完。主要代碼如下:

/**
 * @description 計算射線
 * @param startLocation 起始位置 世界坐標系
 * @param vector_dir 單位方向向量
 */
private drawRayCast(startLocation: cc.Vec2, vector_dir: cc.Vec2) {
    // 剩余長度
    const left_length = AIM_LINE_MAX_LENGTH - this._cur_length;
    if (left_length <= 0) return;
    // 計算線的終點位置
    const endLocation = startLocation.add(vector_dir.mul(left_length));
    // 射線測試
    const results = cc.director.getPhysicsManager().rayCast(startLocation, endLocation, cc.RayCastType.Closest);
    if (results.length > 0) {
        const result = results[0];
        // 指定射線與穿過的碰撞體在哪一點相交。
        const point = result.point;
        // 畫入射線段
        this.drawAimLine(startLocation, point);
        // 計算長度
        const line_length = point.sub(startLocation).mag();
        // 計算已畫長度
        this._cur_length += line_length;
        // 指定碰撞體在相交點的表面的法線單位向量。
        const vector_n = result.normal;
        // 入射單位向量
        const vector_i = vector_dir;
        // 反射單位向量
        const vector_r = vector_i.sub(vector_n.mul(2 * vector_i.dot(vector_n)));
        // 接着計算下一段
        this.drawRayCast(point, vector_r);
    } else {
        // 畫剩余線段
        this.drawAimLine(startLocation, endLocation);
    }
}

如何畫瞄准線小圈圈?通過結束位置和起始位置計算數量和間隔向量,畫出一個個小圓圈。參考代碼如下。

/**
 * @description 畫瞄准線
 * @param startLocation 起始位置 世界坐標系
 * @param endLocation 結束位置 世界坐標系
 */
private drawAimLine(startLocation: cc.Vec2, endLocation: cc.Vec2) {
    // 轉換坐標
    const graphic_startLocation = this.graphic_line.node.convertToNodeSpaceAR(startLocation);
    this.graphic_line.moveTo(graphic_startLocation.x, graphic_startLocation.y);
    // 畫小圓圓
    // 間隔
    const delta = 20;
    // 方向
    const vector_dir = endLocation.sub(startLocation);
    // 數量
    const total_count = Math.round(vector_dir.mag() / delta);
    // 每次間隔向量
    vector_dir.normalizeSelf().mulSelf(delta);
    for (let index = 0; index < total_count; index++) {
        graphic_startLocation.addSelf(vector_dir)
        this.graphic_line.circle(graphic_startLocation.x, graphic_startLocation.y, 2);
    }
}


完整代碼



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM