2012-12-12 13 views
6

So che questo è stato chiesto alcune volte in precedenza, ma non è stata trovata alcuna risposta che possa effettivamente funzionare. Ce n'è uno simile, ma la velocità varia a seconda della distanza percorsa.Spostamento di un oggetto lungo una linea retta a una velocità costante dal punto A al B

Quindi il mio problema è che sto cercando di ottenere un oggetto (un giocatore in questo caso) per spostare una lunga retta dal punto A a B a una velocità costante. Questo viene fatto facendo clic sul giocatore e trascinandolo dove voglio che cammini, in modo che possa essere in qualsiasi direzione e su qualsiasi distanza.

Ho un codice che funziona quasi, ma il lettore finisce sempre leggermente fuori rotta, tanto più è lunga la distanza percorsa. Ecco il codice:

window.addEventListener('mouseup', function(e) { 
    selectedPlayer.moveX = e.pageX; 
    selectedPlayer.moveY = e.pageY; 
    movePlayer(selectedPlayer); 
}); 

function movePlayer(player) { 

    var xDistance = player.moveX - player.x; 
    var yDistance = player.moveY - player.y; 
    var travelDistance = Math.sqrt((xDistance * xDistance) + (yDistance * yDistance)); 
    var timeToTravel = travelDistance; //This may seem pointless, but I will add a speed variable later 
    var playerAngle = Math.atan2(yDistance, xDistance) * (180/Math.PI); 
    var xRatio = Math.atan2(xDistance, travelDistance); 
    var yRatio = Math.atan2(yDistance, travelDistance); 

    //This function is called in another part of code that repeats it 60 times a second 
    walkPlayer = function() { 

     setTimeout(function(){ 
      player.x = player.moveX; 
      player.y = player.moveY; 
      selectedPlayer = undefined; 
      walkPlayer = undefined; 
     }, timeToTravel * 20) 

     player.angle = playerAngle; 
     player.x += xRatio; 
     player.y += yRatio; 
    }; 
} 

Spero che questo ha un senso, ho dovuto includere solo la parte del codice che è rilevante. Penso che il mio problema risieda probabilmente nelle parti di xRatio e yRatio, ma non riesco a capirlo; Sono completamente perplesso.

MODIFICA: Vorrei aggiungere che playerAngle fa affrontare il giocatore nella direzione del trascinamento e quella parte funziona correttamente.

+0

Sono x e y int? Perché il movimento richiederà probabilmente un galleggiante per essere stabile. (Non sono un vero esperto di javascript, quindi forse var è la cosa giusta?) – ninMonkey

+0

Che cosa dovrebbe fare "setTimeout"? Soprattutto se chiamato 60 volte al secondo? – Bergi

+0

@Bergi è un (brutto) tentativo di fermare il giocatore nel punto giusto. Funziona ma è piuttosto bacato e inefficiente. Non ho ancora avuto il tempo di esaminare quella parte, visto che ho cercato di risolvere il problema principale. –

risposta

8

Live Demo

Qui di seguito sono le basi necessarie per ottenere quello che ti serve a lavorare,

var tx = targetX - x, 
    ty = targetY - y, 
    dist = Math.sqrt(tx*tx+ty*ty), 
    rad = Math.atan2(ty,tx), 
    angle = rad/Math.PI * 180;; 

    velX = (tx/dist)*thrust; 
    velY = (ty/dist)*thrust; 

player.x += velX 
player.y += velY 

Questa è una demo che ho fatto un po 'indietro che suona come quello che stai cercando, ho aggiunto la possibilità di fare clic per modificare l'obiettivo in base al problema.

window.addEventListener('mouseup', function(e) { 
    targetX = e.pageX; 
    targetY = e.pageY; 
}); 

var ctx = document.getElementById("canvas").getContext("2d"), 
    x = 300, 
    y = 0, 
    targetX = Math.random()*300, 
    targetY = Math.random()*300, 
    velX = 0, 
    velY = 0, 
    thrust = 5; 


function draw(){ 
    var tx = targetX - x, 
     ty = targetY - y, 
     dist = Math.sqrt(tx*tx+ty*ty), 
     rad = Math.atan2(ty,tx), 
     angle = rad/Math.PI * 180;; 

    velX = (tx/dist)*thrust; 
    velY = (ty/dist)*thrust; 

    // stop the box if its too close so it doesn't just rotate and bounce 
    if(dist > 1){ 
     x += velX; 
     y += velY; 
    } 

    ctx.fillStyle = "#fff"; 
    ctx.clearRect(0,0,400,400); 
    ctx.beginPath(); 
    ctx.rect(x, y, 10, 10); 
    ctx.closePath(); 
    ctx.fill(); 

    ctx.fillStyle = "#ff0"; 
    ctx.beginPath(); 
    ctx.rect(targetX, targetY, 10, 10); 
    ctx.closePath(); 
    ctx.fill(); 

    setTimeout(function(){draw()}, 30); 
} 

draw(); 
+0

Sembra molto simile a quello che sto cercando, grazie! Proverò ad adattarlo un po 'per il mio codice e vedere se funziona e tornare da te su di esso. –

+0

@JamieRushworth sì, mi sono affrettato a postarlo, ho scritto un po 'di spiegazioni sopra e modificato il mio esempio di codice per basare il suo obiettivo fuori da dove l'utente fa clic. – Loktar

+0

Funziona molto meglio, grazie! Grazie per l'aggiornamento anche con il mouse, anche se nella tua demo sembra rimbalzare intorno al bersaglio che sembra un po 'strano. Penso che sia perché non c'è in realtà nulla che fermi la funzione di disegno una volta che ha raggiunto la sua destinazione? –

1

Il tuo problema sembra essere che xRatio e yRatio sono angoli, coordinate non vettoriale. Questo dovrebbe funzionare:

document.addEventListener('mouseup', function(e) { 
    movePlayer(selectedPlayer, {x:e.pageX, y:e.pageY}); 
}); 

function movePlayer(player, target) { 
    var start = { 
      x: player.x, 
      y: player.y, 
      t: Date.now() 
     }, 
     distance = Math.sqrt(distance.x*distance.x + distance.y*distance.y), 
     time = distance; //This may seem pointless, but I will add a speed variable later 
     difference = { 
      x: target.x - player.x, 
      y: target.y - player.y, 
      t: time 
     }; 

    player.angle = Math.atan2(distance.y, distance.x) * (180/Math.PI); 

    //This function is called in another part of code that repeats it 60 times a second 
    walkPlayer = function(curTime) { // we need timing information here: Date.now() 
     var elapsed = curTime - start.t, 
      ratio = elapsed/difference.t; 
     player.x = start.x + difference.x * ratio; 
     player.y = start.y + difference.y * ratio; 
     if (ratio >= 1) { 
      player.x = target.x; 
      player.y = target.y; 
      // end calling of walkPlayer 
     } 
    }; 
} 
+0

Grazie mille, ho usato la parte del tempo e funziona benissimo. Non posso revocare il tuo post finché non ottengo 15 reputazione, ma farò in modo di farlo quando posso! –

Problemi correlati