1

サーバーからクライアントに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));
    }
}

この問題は次の図で説明されています。

ここに画像の説明を入力してください

  • 赤い点-目的地

  • 黒い線-正規化せずにカレットポイントから宛先までの線

  • 緑の点線-ボールのパス

移動をスムーズに、しかしより正確にする方法があるのではないでしょうか。

4

2 に答える 2

1
  1. 正確に3つのポイントのパスステップを補間する場合は、2次ベジェ曲線計算を使用して、開始点から任意の距離の曲線上の任意の位置を計算できるようにする必要があります。あなたはあなたがあなたの写真に持っている曲線に沿って等しいステップを得るためにこれを必要とします。多項式形式でベジェ曲線の等式を使用すると、パラメーターのデルタが等しい場合、曲線に沿って等距離が得られないため、これはかなり注意が必要です。したがって、ベジェ曲線を放物線セグメント

    二次ベジェ曲線パラメトリック多項式

    (効果的にはそうです)として扱う必要があり、タスクは「同じ長さのステップで放物線に沿ってステップする」として再定式化できます。これはまだかなりトリッキーですが、幸いなことにそこに解決策があります:

    http://code.google.com/p/bezier/

    私はこのライブラリを数回使用し(放物線に沿って等しいステップを作成するため)、それは私にとって完全にうまく機能しました。

  2. ほとんどの場合、任意のポイントのセット間を補間する必要があります。この場合、ラグランジュ近似を使用できます。

    以下は、ラグランジュ近似の簡単な実装です。(グーグルで検索すると、さらに多くのことが得られます。)近似関数に任意の数の既知の関数値を指定すると、その間の引数の任意の値に対して滑らかな関数の値を生成できます。

-

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];
            }
        }
    }
}
于 2012-05-04T11:08:57.330 に答える
0

ティックごとに複数の座標を送信できます。または、各ポイントと一緒にいくつかの追加のプロパティを送信します。たとえば、ボールがバウンドするポイントであるかどうか、またはボールをスムージングできるかどうかなどです。

1つのトランザクションで一連のポイントを送信すると、送信、処理、および受信のオーバーヘッドと比較して、精度が向上し、パケットサイズが大きくなりすぎることはありません。

于 2012-05-04T11:07:40.837 に答える