Coords插值

时间:2012-05-04 08:51:10

标签: actionscript-3 math interpolation

我们每300毫秒从服务器发送到客户端的球的坐标。我们必须插入坐标以使移动平稳。这是代码(AS3):

private function run(event:Event):void
{
    // Current frame ball position
    var currentPosition:Point = new Point(this.x, this.y);

    // Vector of the speed
    _velocity = _destinationPoint.subtract(currentPosition);

    // Interpolation
    // Game.timeLapse - time from last package with coordinates (last change of destinationPoint)
    // stage.frameRate - fps
    _velocity.normalize(_velocity.length * 1000 / Game.timeLapse / stage.frameRate);

    // If ball isn't at the end of the path, move it
    if (Point.distance(currentPosition, _destinationPoint) > 1) {
        this.x += _velocity.x;
        this.y += _velocity.y;
    } else {
        // Otherwise (we are at the end of the path - remove listener from this event
        this.removeEventListener(Event.ENTER_FRAME, run);
        this.dispatchEvent(new GameEvent(GameEvent.PLAYER_STOP));
    }
}

问题如下图所示:

enter image description here

  • 红点 - 目的地点

  • 黑线 - 从电流点到目的地的线路没有 归一化

  • 绿色点缀 - 球的路径

也许有办法使移动平稳但更准确?

2 个答案:

答案 0 :(得分:1)

  1. 如果要精确插入三个点的路径步骤,则需要使用quadratic Bezier curve数学计算从起点开始任何给定距离的曲线上的任何位置。您需要这样才能在曲线上获得相等的步骤。这是相当棘手的,因为当您使用多项式形式的贝塞尔曲线方程时,对于相等的参数增量,沿着曲线不会获得相等的距离。

    Quadratic Bezier curve parametric polynomial
    因此,您需要将 bezier曲线视为抛物线段(它实际上是有效的),并且可以将任务重新表述为“沿着具有相等长度的步长的抛物线曲线”。这仍然非常棘手,但幸运的是有一个解决方案:
    http://code.google.com/p/bezier/

    我多次使用这个库(沿着抛物线曲线做出相同的步骤),它对我来说非常有效。

  2. 您很可能希望在任意一组点之间进行插值。如果是这种情况,您可以使用拉格朗日近似

    以下是拉格朗日近似的简单实现。 (谷歌搜索它肯定会给你更多。)你为近似器提供任意数量的已知函数值,它可以为中间任何参数值生成平滑函数的值。
  3. -

    package org.noregret.math 
    {
        import flash.geom.Point;
        import flash.utils.Dictionary;
    
        /**
         * @author Michael "Nox Noctis" Antipin
         */
        public class LagrangeApproximator {
    
            private const points:Vector.<Point> = new Vector.<Point>();
            private const pointByArg:Dictionary = new Dictionary();
    
            private var isSorted:Boolean;
    
            public function LagrangeApproximator()
            {
            }
    
            public function addValue(argument:Number, value:Number):void
            {
                var point:Point;
                if (pointByArg[argument] != null) {
                    trace("LagrangeApproximator.addValue("+arguments+"): ERROR duplicate function argument!");
                    point = pointByArg[argument];
                } else {
                    point = new Point();
                    points.push(point);
                    pointByArg[argument] = point;
                }
                point.x = argument;
                point.y = value;
                isSorted = false;
            }
    
            public function getApproximationValue(argument:Number):Number
            {
                if (!isSorted) {
                    isSorted = true;
                    points.sort(sortByArgument);
                }
                var listLength:uint = points.length;
                var point1:Point, point2:Point;
                var result:Number = 0;
                var coefficient:Number;
                for(var i:uint =0; i<listLength; i++) {
                    coefficient = 1;
                    point1 = points[i];
                    for(var j:uint = 0; j<listLength; j++) {
                        if (i != j) {
                            point2 = points[j];
                            coefficient *= (argument-point2.x) / (point1.x-point2.x);
                        }
                    }        
                    result += point1.y * coefficient;
                }
                return result;
            }
    
            private function sortByArgument(a:Point, b:Point):int
            {
                if (a.x < b.x) {
                    return -1;
                }
                if (a.x > b.x) {
                    return 1;
                }            
                return 0;
            }
    
            public function get length():int
            {
                return points.length;            
            }
    
            public function clear():void
            {
                points.length = 0;
                var key:*;
                for (key in pointByArg) {
                    delete pointByArg[key];
                }
            }
        }
    }
    

答案 1 :(得分:0)

每个刻度线都可以发送多个坐标。或者发送一些额外的属性以及每个点,也许是说它是一个球反弹的点,还是可以平滑。

与发送,处理和接收的开销相比,在一个事务中发送一系列点将提供更高的准确性,并且不会对数据包大小添加太多。