Tower defense 2D - Une balle pour un ennemi

14

J'essaie de trouver une bonne solution pour qu'une balle frappe l'ennemi. Le jeu est la tour de défense 2D, la tour est censée tirer une balle et frapper l'ennemi garanti.

J'ai essayé cette solution - http://blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-1/

Le lien mentionné pour soustraire également l'origine de la balle et l'ennemi (soustraction vectorielle). J'ai essayé mais une balle suit juste autour de l'ennemi.

float diffX = enemy.position.x - position.x;
float diffY = enemy.position.y - position.y;

velocity.x = diffX;
velocity.y = diffY;

position.add(velocity.x * deltaTime, velocity.y * deltaTime);

Je connais les vecteurs mais je ne sais pas quelles étapes (opérations mathématiques vectorielles) doivent être effectuées pour que cette solution fonctionne.

Tashu
la source

Réponses:

11

Votre raisonnement était parfait: utilisez un vecteur pour passer de ma position à ma cible. C'est le but d'un vecteur ; vous avez simplement oublié la vitesse !

La vitesse est un vecteur: une vitesse et une direction. Cependant, si vous oubliez de normaliser le vecteur de différence et de le multiplier par la vitesse de la balle (un scalaire), vous dites essentiellement que si vous êtes proche de la cible (le vecteur de différence est petit), la balle ralentit ; tandis que si vous êtes loin, la vitesse des balles est plus grande.

C'est le problème sous-jacent: vous devez calculer à la fois la direction et la grandeur du vecteur.

FxIII
la source
Merci pour ton aide. J'ai essayé d'utiliser scalaire après avoir calculé le vecteur de différence, il semble que cela a fonctionné mais ne semble pas bon. J'ai essayé de voir si je calculais le vecteur de différence, normalisais, puis scalaisais la vitesse. Ça a l'air mieux en ce moment. Oui, je pense que j'ai besoin des missiles à tête chercheuse dans ce jeu un peu plus tard. Merci encore.
Tashu
1
Cette réponse n'a-t-elle aucun sens pour quelqu'un d'autre?
BlueRaja - Danny Pflughoeft
@Fxlll: Ok, je pense que je vois ce que vous essayez de dire. Il y a beaucoup de peluches sans rapport avec la réponse au début / à la fin, et j'ai également été confondu par votre anglais (qui, je le réalise, n'est probablement pas de votre faute) . J'ai soumis une suggestion de modification pour nettoyer cette réponse.
BlueRaja - Danny Pflughoeft
@BlueRaja - Danny Pflughoeft merci pour votre effort!
FxIII
7

Si la cible se déplace dans une direction stable à un rythme régulier et que votre trajectoire de balle est en ligne droite à un rythme constant, vous pouvez utiliser une équation quadratique pour prédire l'endroit exact où ils se croiseront et viser le pistolet de votre tour à cet endroit. .

Comme il est certain que la balle frappera sa marque et que vous pouvez calculer le temps exact qu'il faudra du tir à l'impact, aucune détection de collision ne serait nécessaire, il suffit de tirer le pistolet, d'attendre la durée calculée, d'enregistrer un coup.

Voici un pseudo code pour l'équation quadratique:

Vector totarget =  target.position - tower.position;

float a = Vector.Dot(target.velocity, target.velocity) - (bullet.velocity * bullet.velocity);
float b = 2 * Vector.Dot(target.velocity, totarget);
float c = Vector.Dot(totarget, totarget);

float p = -b / (2 * a);
float q = (float)Math.Sqrt((b * b) - 4 * a * c) / (2 * a);

float t1 = p - q;
float t2 = p + q;
float t;

if (t1 > t2 && t2 > 0)
{
    t = t2;
}
else
{
    t = t1;
}

Vector aimSpot = target.position + target.velocity * t;
Vector bulletPath = aimSpot - tower.position;
float timeToImpact = bulletPath.Length() / bullet.speed;//speed must be in units per second
Steve H
la source
Merci pour le pseudo code, je vais le vérifier pour voir comment l'équation quadratique fonctionne avec cette situation. Merci encore.
Tashu
Le problème est que l'utilisateur peut se déplacer vers la balle et juste avant de toucher, il peut s'éloigner de la trace de la balle. Dans ce cas, cette solution serait-elle suffisante?
Martin.
Non, comme indiqué dans la première phrase. Ce n'est pas pour tous les jeux mais pour un jeu où les cibles se déplacent à une vitesse constante uniquement. Une vitesse constante signifie à la fois la direction et la vitesse. Par exemple, le jeu de style Defense Grid peut utiliser cette approche.
Steve H
3

Vous devez «prédire» la position des objets au moment où la balle l'atteindra. Vous pouvez le faire en utilisant la vitesse / vitesse des objets (espérons-le, c'est constant;)) et son vecteur directionnel.

Je ne sais pas quelle est la formule exacte du haut de ma tête, mais je pense que c'est quelque chose comme ça:

NewPosition = OldPosition + (Speed ​​* DirectionVector);

Si vous avez un chemin défini, vous devrez recalculer lorsque l'objet change de direction. Utilisez ce NewPosition comme vecteur de l'ennemi.position et la balle devrait toucher l'objet sans «l'effet de homing». Le rapatriement se produit du fait que l'objet ennemi s'est déplacé depuis le calcul du vecteur d'origine, il ne peut rattraper son retard que lorsqu'un objet se déplace dans une direction suffisamment longtemps.

J'espère que cela t'aides :)

Geai
la source
3
Ou vous pouvez tricher et frapper automatiquement, puis utiliser le sprite en mouvement comme rétroaction visuelle. Ou tirez simplement vos balles à 50000 m².
Jonathan Connell
1

Vous pouvez éviter d'utiliser la racine carrée et la puissance de 2.

var distX:Float = target.x - x;
var distY:Float = target.y - y;
_velX = distX / timeTravel;
_velY = distY / timeTravel;

// Take out if you want a nice slow down as approaches effect.  
timeTravel -= 1.0; // make sure u have a positive timeTravel.
x += _velX;
y += _velY;

if (distX < 0)
    distX = -distX;

if (distY < 0)
    distY = -distY;

if (_velX < 0)
    _velX = -_velX;

if (_velY < 0)
    _velY = -_velY;

// Should both snap @ the same time.
if (distX < _velX)
x = target.x; // snap & see what happens.

if (distY < _velY)
y = target.y; // snap & see what happens.

// TODO: call your onHitTarget here ...
// Hopefully this shall provide 10x the performance 
// of using Math.sqrt and all the extra multiplications.

Tout est écrit de mémoire. Soit dit en passant, utilisez les éléments qui fonctionnent - testez-le ligne par ligne si vous êtes nouveau dans ce domaine. Float est Number dans AS3.

Chris
la source