2010-09-07 11 views
2

Contexte: J'ai un jeu JavaScript de vue d'oiseau où le joueur contrôle un vaisseau spatial en touchant un cercle - par ex. touchez à gauche du centre du cercle, et le vaisseau se déplacera à gauche, touchera le coin supérieur droit et il se déplacera vers le coin supérieur droit et ainsi de suite ... plus loin du centre du cercle du pseudo joystick, plus la vitesse sera grande direction. Cependant, je ne suis pas régler directement la vitesse du navire, mais plutôt définir une valeur targetSpeed.x et targetSpeed.y, et le navire ajuste alors sa vitesse en utilisant quelque chose comme:Comment régler correctement la vitesse du sprite du lecteur? (Fondamentalement, une question de maths?)

if (this.speed.x < this.targetSpeed.x) { 
    this.speed.x += this.speedStep; 
} 
else if (this.speed.x > this.targetSpeed.x) { 
    this.speed.x -= this.speedStep; 
} 

... et même pour la vitesse y, et speedStep est une petite valeur pour le rendre plus lisse et pas trop abrupte (un vaisseau ne doit pas aller d'une direction rapide vers la gauche à une direction rapide vers la droite).

Ma question: En utilisant le code ci-dessus, je crois cependant que la vitesse sera ajustée plus rapidement dans les directions diagonales, et plus lente le long des lignes horizontales/verticales. Comment puis-je corriger cela pour avoir une vitesse cible égale?

Merci beaucoup pour toute aide!

+0

Pourriez-vous reformuler votre question s'il vous plaît? Qu'est-ce que tu veux faire exactement? Merci. –

+0

@Oren: Il est assez évident ce que l'OP veut faire --- faire en sorte que, si, disons, l'angle est de 45 degrés (par exemple, 'targetSpeed.x - speed.x == targetSpeed.y - speed.y'), alors l'incrément est toujours 'speedStep', pas' sqrt (2) * speedStep'. –

Répondre

5
var xdiff = targetSpeed.x - speed.x; 
var ydiff = targetSpeed.y - speed.y; 
var angle = Math.atan2(ydiff, xdiff); 
speed.x += speedStep * Math.cos(angle); 
speed.y += speedStep * Math.sin(angle); 
+0

+1 me battre. atan2 obtiendra l'angle entre 2 points. cos et sin obtiennent vos compensations x et y. J'aurais juste utilisé le pas de vitesse au lieu de calculer la norme sur les deux dernières lignes. –

+0

@DrDipshit: En effet, j'ai corrigé ma réponse pour faire exactement cela. :-) –

+1

Fonctionne comme un charme, j'adore Stackoverflow! Merci Chris! –

1

En supposant que vous avez déjà vérifié que le contact est à l'intérieur du cercle, et que le bord du cercle représente la vitesse maximale, et que le centre du cercle est circleTouch == [0, 0]

Dans certains C++ - comme le code pseudo :

Scalar circleRadius = ...; 
Scalar maxSpeed = ...; 
Scalar acceleration = ...; 

Vector calculateTargetSpeed(Vector circleTouch) { 
    Vector targetSpeed = maxSpeed * circleTouch/circleRadius; 

    return targetSpeed; 
} 

Vector calculateNewSpeed(Vector currentSpeed, Vector targetSpeed) { 
    Vector speedDiff = targetSpeed - currentSpeed; 

    Vector newSpeed = currentSpeed + acceleration * normalized(speedDiff); 

    return newSpeed; 
} 

// Divide v by its length to get normalized vector (length 1) with same x/y ratio 
Vector normalized(Vector v) { 
    return v/length(v); 
} 

// Pythagoras for the length of v 
Scalar length(Vector v) { 
    Scalar length = sqrt(v.x * v.x + v.y * v.y); // or preferably hypot(v.x, v.y) 

    return length; 
} 

Ceci est juste sur le dessus de ma tête, et je ne l'ai pas testé. L'autre réponse est correcte, je voulais juste donner une réponse sans fonctions de trigonométrie. :)

+0

Génial d'avoir ceci comme alternative, merci Christoffer! Pensez-vous que ce code peut être une alternative plus rapide parce qu'il évite certaines fonctions mathématiques? –

+0

@Philipp: Désolé, je n'en ai aucune idée, vous devrez vous comparer à vous-même. En outre, j'espère que le calcul vectoriel était assez compréhensible? :) –