【cocos creator】【TS】贝塞尔曲线,地图之间显示曲线,顺着曲线移动

参考:

https://blog.csdn.net/Ctrls_/article/details/108731313

https://blog.csdn.net/qq_28299311/article/details/104009804

typescript 复制代码
const { ccclass, property } = cc._decorator;

@ccclass
export default class mapPanel extends cc.Component {
    @property(cc.Node)
    player: cc.Node = null;
    @property(cc.Node)
    build: cc.Node = null;
    @property(cc.Node)
    point: cc.Node = null;
    @property(cc.Node)
    root: cc.Node = null;

    start() {
        this.init();
    }

    init(data?) {
        data = {
            mapData: [
                { id: 1, name: "1", pos: { x: 0, y: 100 } },
                { id: 2, name: "2", pos: { x: -100, y: -100 } },
                { id: 3, name: "3", pos: { x: 200, y: -80 } },
                { id: 4, name: "4", pos: { x: 180, y: 300 } },
                { id: 5, name: "5", pos: { x: 150, y: 50 } }
            ],
            linkData: [[2, 1], [1, 4], [5, 1], [5, 3], [2, 5]],
            startPosId: 2,
            road: [2, 5, 1, 4]
        }
        data.mapData.forEach(element => {
            this.creatOneBuild(element, data.startPosId)
        });
        this.player.position = data.mapData[data.startPosId - 1].pos
        data.linkData.forEach(element => {
            this.setPoint(cc.v2(data.mapData[element[0] - 1].pos), cc.v2(data.mapData[element[1] - 1].pos))
        });
        let roadArray = []
        data.road.forEach((element) => {
            roadArray.push(data.mapData[element - 1].pos);
        })
        this.playTween(roadArray);
    }

    playTween(roadArray, moveSpeed = 0.003, time = 1.5, delayTime = 0.3, cb?) {
        let tween = cc.tween(this.player)
        let nowPos = roadArray[0]
        for (let i = 1; i < roadArray.length; i++) {
            let nextPos = roadArray[i]
            let pointArr = this.getOneroad(nowPos, nextPos, 1)
            let speed = moveSpeed
            if (pointArr.length * moveSpeed > time) speed = (time / pointArr.length)
            // if (speed > moveSpeed) speed = moveSpeed
            pointArr.forEach(element => {
                tween.to(speed, { position: element })
            });
            tween.delay(delayTime)
            nowPos = nextPos;
        }
        tween
            .call(() => {
                cb && cb()
            })
            .start();
    }

    creatOneBuild(data, nowId) {
        let build = cc.instantiate(this.build);
        build.parent = this.root;
        build.position = cc.v3(data.pos);
        build.getChildByName("name").getComponent(cc.Label).string = data.name;
        build.active = true;
        build.getChildByName("light").active = nowId == data.id;
    }

    creatOnePoint(pos: cc.Vec3) {
        let build = cc.instantiate(this.point);
        build.parent = this.root;
        build.position = pos;
        build.active = true;
    }


    /**
     * 设置点
     * @param startPoint 起点
     * @param endPoint 终点
     * @param pointDistance 小点间距
     * @param angel 弧度
     */
    setPoint(startPoint, endPoint, pointDistance = 30, angel = 60) {
        let pointArr = this.getOneroad(startPoint, endPoint, pointDistance, angel)
        pointArr.forEach(element => {
            this.creatOnePoint(element)
            console.log(element);//每个小圆点点坐标,这里进行处理
        });
    }

    /**
     * 获取n点之间路径
     * @param startPoint 起点
     * @param endPoint 终点
     * @param pointDistance 小点间距
     * @param angel 弧度
     */
    getTotalRoad(arrList, pointDistance = 30, angel = 60) {
        let pointArrTotal = []
        let nowPos = pointArrTotal.shift()
        let list = arrList;
        while (1) {
            let nextPos = list.shift()
            if (nextPos) {
                let pointArr = this.getOneroad(nowPos, nextPos, pointDistance, angel)
                pointArrTotal = pointArrTotal.concat(pointArr)
                nowPos = nextPos;
            }
            else {
                break;
            }
        }
        return pointArrTotal
    }
    /**
     * 获取两点之间路径
     * @param startPoint 起点
     * @param endPoint 终点
     * @param pointDistance 小点间距
     * @param angel 弧度
     */
    getOneroad(startPoint, endPoint, pointDistance = 30, angel = 60) {
        startPoint = cc.v2(startPoint);
        endPoint = cc.v2(endPoint);
        let distance = startPoint.sub(endPoint).mag();
        let middlePoint = cc.v2((startPoint.x + endPoint.x) / 2, (startPoint.y + endPoint.y) / 2)
        let height = Math.sin(angel * (180 / Math.PI)) * (distance / 2) * 1.5;
        cc.log(height)
        let middlePoint2 = this.findPointCInRightTriangle(startPoint, middlePoint, height);
        let number = Number((distance / pointDistance).toFixed(0));
        let pointArr = this.getBezierPoints(number, startPoint, height ? middlePoint2 : middlePoint, endPoint)
        return pointArr;
    }

    /**
     * 获取两点之间垂直平分线线上的点
     * @param startPoint 
     * @param endPoint 
     * @param bcLength 
     * @returns 
     */
    findPointCInRightTriangle(startPoint: cc.Vec2, endPoint: cc.Vec2, bcLength: number, isUP = true): cc.Vec2 | null {
        let ax = endPoint.x;
        let ay = endPoint.y;
        let bx = startPoint.x;
        let by = startPoint.y;
        // 计算向量AB  
        const dx = bx - ax;
        const dy = by - ay;

        // 计算AB的长度  
        const abLength = Math.sqrt(dx * dx + dy * dy);

        // 检查AB长度是否为零,以避免除以零的错误  
        if (abLength === 0) {
            return null; // 无法确定C点位置,因为AB长度为0  
        }

        // 计算AC的长度(利用勾股定理)  
        const acLength = Math.sqrt(bcLength * bcLength - abLength * abLength);

        // 计算向量AB的单位向量  
        const abUnitX = dx / abLength;
        const abUnitY = dy / abLength;

        // 计算向量AC,它垂直于向量AB(因为ABC是直角三角形)  
        const acUnitX = -abUnitY; // 垂直向量的x分量是原向量y分量的相反数  
        const acUnitY = abUnitX;  // 垂直向量的y分量是原向量x分量  

        // 计算点C的坐标  
        const cx = ax + acLength * acUnitX * (isUP ? -1 : 1);
        const cy = ay + acLength * acUnitY * (isUP ? -1 : 1);

        return cc.v2(cx, cy);
    }
    /**
    * 获取贝塞尔曲线上的点
    * @param {返回的点的数组长度} num 
    * @param {起点} startPoint 
    * @param {控制点} middlePoint 
    * @param {终点} endPoint 
    */
    getBezierPoints(num, startPoint, middlePoint, endPoint) {
        let pointList = [];
        let x1 = startPoint.x, y1 = startPoint.y;
        let x2 = endPoint.x, y2 = endPoint.y;
        let cx = middlePoint.x, cy = middlePoint.y;
        let t = 0;
        for (let i = 1; i < (num + 1); i++) {
            //用i当作t,算出点坐标,放入数组
            t = i / num;
            let x = Math.pow(1 - t, 2) * x1 + 2 * t * (1 - t) * cx + Math.pow(t, 2) * x2;
            let y = Math.pow(1 - t, 2) * y1 + 2 * t * (1 - t) * cy + Math.pow(t, 2) * y2;
            pointList.push(cc.v2(x, y))
        }
        return pointList;
    }

    // update (dt) {}
}
相关推荐
烧仙草奶茶1 个月前
【cocos creator】输入框滑动条联动小组建
cocos creator·cocos-creator
烧仙草奶茶3 个月前
【cocos creator】2.x里,使用3D射线碰撞检测
3d·cocos creator·cocos-creator·2.x