Je travaille sur un jeu où le joueur peut ramasser des objets en utilisant quelque chose comme un rayon tracteur et les transporter.
Attirer l'objet vers le centre du faisceau n'est pas difficile. Mais une fois que l'objet est suffisamment proche du centre, je dois le garder là pendant que le joueur bouge, ce qui me pose problème. Je peux penser à deux façons de le faire, et les deux ont des problèmes:
Mettez à jour la position de l'objet chaque fois que la position du joueur change, en le gardant centré sur la poutre.
Mettez à jour la vitesse de l'objet pour pointer directement vers le centre du faisceau, plus loin, plus la vitesse est élevée.
Le déplacement et la rotation fonctionnent très bien avec les deux approches, mais la physique est erronée lorsque l'objet transporté entre en collision avec d'autres objets:
Avec la première approche, la physique est complètement ignorée. L'objet transporté ne fait qu'éloigner quoi que ce soit. En effet, les changements de position ne sont censés être effectués que dans le cadre de la physique mondiale, en fonction de la vitesse.
Avec la deuxième approche, la physique se comporte essentiellement comme elle le devrait, mais réagit de manière excessive. Le problème est le suivant: afin de maintenir l'objet transporté au centre du faisceau même en rotation et en mouvement, je dois utiliser des valeurs de vitesse élevées. Ainsi, une fois que l'objet transporté en a touché un autre, la vitesse de la collision est beaucoup trop élevée.
Comment puis-je l'implémenter correctement? Ma meilleure supposition en ce moment est d'aller avec la deuxième approche et d'ajouter une manipulation spéciale pour les objets transportés à la physique du monde, en réduisant la vitesse à des valeurs sensées pour les collisions ou lorsque le joueur cesse de les transporter. Mais cela semble être une solution de contournement assez inélégante.
Edit: Ajout d'un pseudo code pour illustrer comment cela fonctionne en ce moment (ce serait la deuxième approche ci-dessus)
void attract_object(object, ticks) {
Vector distance = beam_center - object.center;
// If the object is not close to the beam center, attract it slowly
if (magnitude(distance) > 10) {
object.velocity += distance.normalized() * ticks * 0.1;
return;
}
// Here comes the part we're talking about. That magic 0.5 is just high enough
// that the object isn't lost while moving around. But it's still so high that
// other objects are repelled with way too much force.
object.velocity = distance * ticks * 0.5;
}
D'après ce que je vois, cela se produit lorsque l'objet transporté repousse un autre objet:
- L'objet transporté entre en collision avec un autre objet
- Les vitesses des objets sont distribuées correctement, donc l'objet transporté est éloigné du centre du faisceau dans le processus
- Le code ci-dessus provoque le retour de l'objet transporté au centre du faisceau, avec une telle vitesse qu'il y retournera rapidement
- Lorsque l'objet transporté recule vers le centre du faisceau, la moitié de sa vitesse élevée est transférée à l'autre objet, le repoussant violemment. Étant donné que la vitesse initiale de l'objet transporté semble être saine, je peux imaginer que les étapes 2 à 4 sont répétées plusieurs fois, créant une vitesse aussi élevée.
Cela semble être la cause. Je ne peux pas penser à une belle façon de le réparer :(
Réponses:
Essentiellement, ce que vous recherchez, c'est que l'objet «rayonné» se comporte exactement comme si vous le saisissiez avec vos mains.
Une option serait de lui faire partager les vitesses d'accélération a / o de la «main» qui le tient au lieu d'ajuster sa vitesse pour combler l'écart avec le centre du faisceau.
Disons que le centre du faisceau est la main qui tient. si votre personnage pivote de 90 degrés vers sa gauche en 1 seconde, alors la vitesse de la main serait:
If R = length of the arm: which is the radius of the rotation circle
faites-le fois le temps écoulé du cadre pour trouver la vitesse que vous devez appliquer à votre objet. Trouvez la normale horizontale au faisceau pour trouver son vecteur de direction.R^2 *PI /4 would be the distance traveled over a second.
Mon point est que vous n'avez pas à résoudre les problèmes si vous essayez d'autres implémentations qui ne le causeront pas en premier lieu.
J'irais jouer avec le pistolet à gravité dans HL2 pour trouver de l'inspiration sur le problème, mais j'ai d'autres plans pour aujourd'hui.
EDIT: je suis désolé, je pensais que c'était pour un pistolet 3D, mais c'est essentiellement la même chose avec 2D sauf que les axes sont différents (et il n'y a pas de géométrie complexe)
la source
Que diriez-vous d'ajouter une connexion à ressort, c'est-à-dire de forcer l'objet transporté à revenir à la position de transport en fonction de la distance, tout en lui permettant d'être repoussé par des objets solides (comme des murs).
Ajustez constamment la vitesse de l'objet transporté (en changeant l'accélération en fonction de la position / distance) pour pointer vers la position du faisceau tracteur (c'est-à-dire votre deuxième approche). Si l'objet est trop éloigné, supprimez la connexion (et l'objet).
Je ne sais pas vraiment pourquoi vous auriez besoin de vitesses élevées. Surtout le cas "player let go" indiquerait que votre vitesse de rotation pourrait être trop élevée ou irréaliste. N'oubliez pas non plus des éléments tels que la résistance à l'air et la gravité.
Edit: Compte tenu du code mis à jour, le problème est plutôt trivial à trouver:
Le problème ici est le cas où la distance de l'objet à sa position de but est constamment trop éloignée (ie
> 10
). Tant que cette condition est vraie, sa vitesse augmente simplement encore et encore (c'est-à-dire indéfiniment).Deux solutions possibles pour cela:
Définissez une vitesse maximale:
Appliquez une vitesse fixe plutôt que d'accélérer:
Accélérer tout en étant trop loin est certainement une mauvaise approche ici. Une chose à propos de la traction d'un ressort ou d'un élastique: peu importe que vous le teniez pendant une seconde ou une minute. À la fin, il accélérera de la même manière (étant donné qu'il n'a pas été en mouvement et qu'aucune autre force n'est appliquée).
la source