之前在写一个项目需要把多点连成平滑的曲线,而且这些点是无法预知的。开始想到用贝塞尔曲线,但是具体贝塞尔曲线的控制点要怎么设定,怎样让多点都落在曲线上而且保持曲线的平滑,就一直没想到。最后参考原文:http://www.zheng-hang.com/?id=43 写得挺好的,不过没太仔细研究。

const {ccclass, property} = cc._decorator;
@ccclass
export default class NewClass extends cc.Component {
    @property(cc.Graphics)
    graphics: cc.Graphics = null;
    start () {
        var mPointList = [cc.v2(10, 10), cc.v2(120, 40), cc.v2(260, 180), cc.v2(380, 40), cc.v2(420, 120),
            cc.v2(510, 110), cc.v2(620, 140), cc.v2(760, 280), cc.v2(880, 240), cc.v2(920, 120)];
        var lineSmoothness = 0.32;
        this.measurePath(mPointList, lineSmoothness);
    }
    measurePath(positions: Array<cc.Vec2>,lineSmoothness) {
        var prePreviousPointX: number;
        var prePreviousPointY: number;
        var previousPointX: number;
        var previousPointY: number;
        var currentPointX : number;
        var currentPointY : number;
        var nextPointX: number;
        var nextPointY: number;
        var graphics = this.graphics;
        var lineSize = positions.length;
        for (var valueIndex = 0; valueIndex < lineSize; ++valueIndex) { 
            if (currentPointX) {
                var point = positions[valueIndex];
                currentPointX = point.x;
                currentPointY = point.y;
            }
            if (previousPointX) {
                //是否是第一个点
                if (valueIndex > 0) {
                    var point = positions[valueIndex-1];
                    previousPointX = point.x;
                    previousPointY = point.y;
                } else {
                    //是的话就用当前点表示上一个点
                    previousPointX = currentPointX;
                    previousPointY = currentPointY;
                }
            }
            if (prePreviousPointX) {
                //是否是前两个点
                if (valueIndex > 1) {
                    var point = positions[valueIndex-2];
                    prePreviousPointX = point.x;
                    prePreviousPointY = point.y;
                } else {
                    //是的话就用当前点表示上上个点
                    prePreviousPointX = previousPointX;
                    prePreviousPointY = previousPointY;
                }
            }
            // 判断是不是最后一个点了
            if (valueIndex < lineSize - 1) {
                var point = positions[valueIndex+1];
                nextPointX = point.x;
                nextPointY = point.y;
            } else {
                //是的话就用当前点表示下一个点
                nextPointX = currentPointX;
                nextPointY = currentPointY;
             }
            if (valueIndex == 0) {
                graphics.moveTo(positions[0].x, positions[0].y);
            } else {
                // 求出控制点坐标
                var firstDiffX = (currentPointX - prePreviousPointX);
                var firstDiffY = (currentPointY - prePreviousPointY);
                var secondDiffX = (nextPointX - previousPointX);
                var secondDiffY = (nextPointY - previousPointY);
                var firstControlPointX = previousPointX + (lineSmoothness * firstDiffX);
                var firstControlPointY = previousPointY + (lineSmoothness * firstDiffY);
                var secondControlPointX = currentPointX - (lineSmoothness * secondDiffX);
                var secondControlPointY = currentPointY - (lineSmoothness * secondDiffY);
                graphics.bezierCurveTo(firstControlPointX, firstControlPointY, secondControlPointX, secondControlPointY,  currentPointX, currentPointY)
                graphics.fill();
            }
            // 更新值,
            prePreviousPointX = previousPointX;
            prePreviousPointY = previousPointY;
            previousPointX = currentPointX;
            previousPointY = currentPointY;
            currentPointX = nextPointX;
            currentPointY = nextPointY;
        }
        graphics.stroke();
        graphics.fillColor= cc.color(0,0,0,255);
        for (var i=0;i<positions.length;i++){
            graphics.arc(positions[i].x,positions[i].y,5,0,Math.PI*2,true);
            graphics.fill();
        }
    }
}