2012-05-04 28 views
1

我們從服務器發送到客戶端的球COORDS每300毫秒。我們必須插入座標來使移動平穩。下面是代碼(AS3):COORDS插值

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

  • 紅點 - 目標點

  • 黑線 - 線從curret點到目的地而不 正常化

  • 綠色點綴 - 球的路徑

也許有一種方法,使移動順暢,但更準確?

回答

1
  1. 如果你想插路徑步驟恰好有三個點,你需要使用quadratic Bezier curve數學能夠計算曲線上的任何位置從它的起點任何給定距離。您需要沿着曲線獲得相等的步驟,即您的照片。這很棘手,因爲當您使用多項式形式的貝塞爾曲線方程時,您無法獲得沿相同參數增量的曲線上的相等距離​​。

    Quadratic Bezier curve parametric polynomial

    所以,你需要把貝塞爾曲線的拋物線段(它實際上是),任務可以重新爲「隨長度相等的步驟拋物線步進」。這仍然是相當棘手的,但幸運的是有一個解決方案在那裏:

    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]; 
      } 
     } 
    } 
} 
0

你可以發送不止一個座標每個刻度。或者發送一些額外的屬性以及每個點,也許可以說是球的反彈點還是平滑點。

在一個事務中發送的一系列點的會給你更高的精確度,並不會增加太多的數據包大小,相對於發送,處理和接收的開銷。