2015-01-09 57 views
0

我有一個精靈動畫,我已經設置了一個停止距離,並且想要計算我必須在該停止距離內減慢對象以達到其新目標的程度速度。但目前我沒有得到正確的結果。如何計算設定的距離和目標速度的速度

我的代碼如下所示:

function updatePosition(obj,brake){ 
    var delta = new Date().getTime() - obj.timer; //time since last frame 

    if(brake){   
     obj.velocity -= (Math.pow(obj.velocity,2) - Math.pow(obj.targetSpeed,2))/(2 * obj.stopDist); 
     if(obj.velocity < obj.targetSpeed){ 
      obj.velocity = obj.targetSpeed; 
     } 
    } 
} 

我的問題是精靈遠遠過去以速度遠高於目標速度的制動距離。

我創建了一個擺弄着一個紅點行駛到這裏目的地:http://jsfiddle.net/4tLmz3ch/1/

當行駛通過obj.stopDist設置應該往哪個應該很好地到達目的地前的目標速度的距離。但我顯然在這裏得到了一些不正確的數學。

希望你能幫助解釋我的誤解。

+0

速度不是標量值。你在混合標量和矢量計算,我認爲這是這裏的一個大問題。 – JLRishe

+0

@JLRishe不是100%確定我明白你的意思?我應該不改變速度值嗎? – Sir

+0

我得到它的工作.. – mike510a

回答

3

如果您提前確定所需的加速並在每次刷新期間使用該問題,則此問題要簡單得多。然後,對於每個幀的整個代碼(不包括繪製邏輯,並假設一維)剛剛變爲:

function frame() { 
    var t = new Date().getTime(); 
    var tDelta = t - obj.lastTime; 

    obj.lastTime = t; 

    obj.pos += obj.velocity * tDelta; 

    if (obj.velocity > obj.destVelocity) { 
     obj.velocity += obj.acceleration * tDelta; 
    } 

    draw(); 

    setTimeout(frame, 1); 
} 

給定一個起始和結束位置和速度,該公式爲需要(假設恆定加速度)的加速度:

(2 * v0 * (vf - v0) + (vf - v0)^2)/(2 * (xf - x0))

所以初始化像這樣的對象:

var obj = { 
    start: 10, 
    height: 200, 
    stopDist: 300, 
    dest: 500, 
    lastTime: new Date().getTime(), 
    velocity: 0.05, 
    destVelocity: 0.01, 
    pos: undefined, 
    acceleration: undefined 
}; 

這裏是我們如何能夠KIC k全部關閉:

function start(){ 
    var v0 = obj.velocity, 
     vf = obj.destVelocity, 
     x0 = obj.start, 
     xf = x0 + x.stopDist, 
     vDelta = vf - v0; 

    obj.pos = x0; 
    obj.acceleration = (2 * v0 * vDelta + vDelta * vDelta)/(2 * (xf - x0)); 

    frame(); 
} 

正如我上面所做的,首先解決1d情況是很有幫助的。這就是全部放在一起。

var canvas = document.getElementById('canvas'); 
 
var test = document.getElementById('test'); 
 
var ctx = canvas.getContext('2d'); 
 

 
function drawDot(color, x, y) { 
 
    ctx.fillStyle = color; 
 
    ctx.fillRect(x - 2, y - 2, 4, 4); 
 
} 
 

 
function draw() { 
 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 

 
    drawDot("red", obj.pos, obj.height); 
 
    drawDot("white", obj.start, obj.height); 
 
    drawDot("green", obj.dest, obj.height); 
 
    drawDot("yellow", obj.start + obj.stopDist, obj.height); 
 

 
    ctx.fillText("x = " + obj.pos.toFixed(5), 20, 400); 
 
    ctx.fillText("v = " + obj.velocity.toFixed(5), 20, 420); 
 
    ctx.fillText("distance traveled: " + (obj.pos - obj.start).toFixed(2), 20, 440); 
 
} 
 

 
var obj = { 
 
    start: 10, 
 
    height: 200, 
 
    stopDist: 300, 
 
    dest: 500, 
 
    lastTime: new Date().getTime(), 
 
    velocity: 0.05, 
 
    destVelocity: 0.01, 
 
    pos: undefined, 
 
    acceleration: undefined 
 
}; 
 

 
function frame() { 
 
    var t = new Date().getTime(), 
 
     tDelta = t - obj.lastTime; 
 
    obj.lastTime = t; 
 

 
    obj.pos += obj.velocity * tDelta; 
 
    if (obj.velocity > obj.destVelocity) { 
 
     obj.velocity += obj.acceleration * tDelta; 
 
    } 
 

 
    draw(); 
 

 
    setTimeout(frame, 1); 
 
} 
 

 
function start() { 
 
    var v0 = obj.velocity, 
 
     vf = obj.destVelocity, 
 
     x0 = obj.start, 
 
     xf = x0 + obj.stopDist, 
 
     vDelta = vf - v0; 
 

 
    obj.pos = x0; 
 
    obj.acceleration = (2 * v0 * vDelta + vDelta * vDelta)/(2 * (xf - x0)); 
 

 
    frame(); 
 
} 
 

 
start();
#canvas{ 
 
    background-color:black; 
 
}
<canvas id="canvas" width="700" height="700"></canvas>

http://jsfiddle.net/x7842xcb/3/


這裏是2D版本(振作起來):

var canvas = document.getElementById('canvas'); 
 
var test = document.getElementById('test'); 
 
var ctx = canvas.getContext('2d'); 
 

 
function drawDot(color, x, y) { 
 
    ctx.fillStyle = color; 
 
    ctx.fillRect(x - 2, y - 2, 4, 4); 
 
} 
 

 
function draw() { 
 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
 

 
    drawDot("red", obj.pos.x, obj.pos.y); 
 
    drawDot("white", obj.start.x, obj.start.y); 
 
    drawDot("green", obj.dest.x, obj.dest.y); 
 
    drawDot("yellow", obj.stopLocation.x, obj.stopLocation.y); 
 
    
 
    var dx = obj.pos.x - obj.start.x, 
 
     dy = obj.pos.y - obj.start.y, 
 
     dist = Math.sqrt(dx * dx + dy *dy), 
 
     v = obj.velocity, 
 
     speed = Math.sqrt(v.x * v.x + v.y * v.y); 
 
    
 
    ctx.fillText("distance traveled: " + dist.toFixed(5), 20, 400); 
 
    ctx.fillText("speed:    " + speed.toFixed(5), 20, 420); 
 
} 
 

 
var obj = { 
 
    start: { x: 400, y: 230 }, 
 
    stopDist: 350, 
 
    dest: { x: 50, y: 330 }, 
 
    lastTime: new Date().getTime(), 
 
    startSpeed: 0.05, 
 
    destSpeed: 0.1, 
 

 
    pos: null, 
 
    velocity: null, 
 
    destVelocity: null, 
 
    acceleration: null 
 
}; 
 

 
function sign(value) { 
 
    return value > 0 ? 1 : (value < 0 ? -1 : 0); 
 
} 
 

 
function reached(start, current, dest) { 
 
    return current === dest || 
 
     sign(current - dest) === sign(dest - start); 
 
} 
 

 
function frame() { 
 
    var t = new Date().getTime(), 
 
     tDelta = t - obj.lastTime, 
 
     v = obj.velocity, 
 
     destv = obj.destVelocity, 
 
     startv = obj.startVelocity; 
 
    obj.lastTime = t; 
 

 
    obj.pos.x += v.x * tDelta; 
 
    obj.pos.y += v.y * tDelta; 
 
    
 
    if (!reached(startv.x, v.x, destv.x) || 
 
     !reached(startv.y, v.y, destv.y)) { 
 
     v.x += obj.acceleration.x * tDelta; 
 
     v.y += obj.acceleration.y * tDelta; 
 
    } 
 

 
    draw(); 
 

 
    setTimeout(frame, 1); 
 
} 
 

 
function calcAcceleration(p0, pf, v0, vf) { 
 
    var vDelta = vf - v0; 
 
    
 
    return pf === p0 
 
     ? 0 
 
     : (2 * v0 * vDelta + vDelta * vDelta)/(2 * (pf - p0)); 
 
} 
 

 
function start() { 
 
    // positions and deltas 
 
    var start = obj.start, 
 
     dest = obj.dest, 
 
     dx = dest.x - start.x, 
 
     dy = dest.y - start.y, 
 
     totalDistance = Math.sqrt(dx * dx + dy * dy); 
 
    
 
    // x and y component ratio 
 
    var cx = dx/totalDistance, 
 
     cy = dy/totalDistance; 
 
    
 
    var stopLocation = { x: cx * obj.stopDist + start.x, 
 
         y: cy * obj.stopDist + start.y }; 
 
    
 
    // velocities 
 
    var startSpeed = obj.startSpeed, 
 
     destSpeed = obj.destSpeed, 
 
     startVelocity = { x: cx * startSpeed, y: cy * startSpeed }, 
 
     endVelocity = { x: cx * destSpeed, y: cy * destSpeed }; 
 
    console.log(startVelocity); 
 
    console.log(endVelocity); 
 
    
 
    // acceleration 
 
    var acceleration = { 
 
     x: calcAcceleration(start.x, stopLocation.x, startVelocity.x, endVelocity.x), 
 
     y: calcAcceleration(start.y, stopLocation.y, startVelocity.y, endVelocity.y) 
 
    }; 
 

 
    obj.pos = Object.create(start); 
 
    obj.startVelocity = startVelocity; 
 
    obj.velocity = Object.create(startVelocity); 
 
    obj.stopLocation = stopLocation; 
 
    obj.destVelocity = endVelocity; 
 
    obj.acceleration = acceleration; 
 
    
 
    frame(); 
 
} 
 

 
start();
#canvas{ 
 
    background-color:black; 
 
}
<canvas id="canvas" width="700" height="700"></canvas>

http://jsfiddle.net/1r3q4oob/3/

編輯關於我的事實後作出的修正:

與我最初的實現是,如果當前速度的X和Y兩個組件都是它只會更新速度的問題大於目標速度。這將防止正確的行爲,如果:

  • 所述的X或兩者的開始和結束的速度的Y分量分別爲0(即,如果它是完全水平或垂直移動)
  • 開始的X或Y分量和終點速度爲負(即如果在旅行向上和向左)
  • 需要增加而不是減少的速度(即點是加快到目標速度)

我解決這與如果(a)目標速度是之間當前速度和起始速度(即,目標速度)之間的基本上返回真的功能​​3210的添加。當前速度已超過目標速度),或(b)當前速度等於目標速度。

+0

我得到它在jsFiddle上工作,但是當我出於某種原因將它實現到我的網站時,檢查'velocity.x> destVelocity.x'是否等於'false'。但是對於'y軸'來說,它是'true'。這意味着它不會隨加速度改變速度。不知道爲什麼會出現這種情況,目標速度設置爲低於啓動速度。 = /我可以向你展示粘貼文件中的代碼,以便查看我可能會出錯的位置? – Sir

+0

好吧,我做了一些挖掘,如果路徑是例如在一個直線軸上的目標和開始x或y是相同的問題。例如:http://jsfiddle.net/8kzptxus/注意速度沒有變化 – Sir

+0

還試圖在你的示例代碼未修改:http://jsfiddle.net/au5ht6oh/速度沒有變化 – Sir