Avant d'appliquer l'extrapolation au mouvement de mon sprite, ma collision a parfaitement fonctionné. Cependant, après avoir appliqué une extrapolation au mouvement de mon sprite (pour lisser les choses), la collision ne fonctionne plus.
Voici comment les choses fonctionnaient avant l'extrapolation:
Cependant, après avoir implémenté mon extrapolation, la routine de collision se rompt. Je suppose que c'est parce qu'il agit sur la nouvelle coordonnée qui a été produite par la routine d'extrapolation (qui est située dans mon appel de rendu).
Après avoir appliqué mon extrapolation
Comment corriger ce comportement?
J'ai essayé de mettre un contrôle de collision supplémentaire juste après l'extrapolation - cela semble résoudre beaucoup de problèmes, mais j'ai écarté cela car il n'est pas question de mettre de la logique dans mon rendu.
J'ai également essayé de faire une copie de la position de spritesX, d'extrapoler et de dessiner en utilisant cela plutôt que l'original, laissant ainsi l'original intact pour que la logique reprenne - cela semble une meilleure option, mais cela produit toujours des effets étranges en entrant en collision avec des murs. Je suis presque sûr que ce n'est pas non plus la bonne façon de gérer cela.
J'ai trouvé quelques questions similaires ici, mais les réponses ne m'ont pas aidé.
Voici mon code d'extrapolation:
public void onDrawFrame(GL10 gl) {
//Set/Re-set loop back to 0 to start counting again
loops=0;
while(System.currentTimeMillis() > nextGameTick && loops < maxFrameskip){
SceneManager.getInstance().getCurrentScene().updateLogic();
nextGameTick+=skipTicks;
timeCorrection += (1000d/ticksPerSecond) % 1;
nextGameTick+=timeCorrection;
timeCorrection %=1;
loops++;
tics++;
}
extrapolation = (float)(System.currentTimeMillis() + skipTicks - nextGameTick) / (float)skipTicks;
render(extrapolation);
}
Appliquer l'extrapolation
render(float extrapolation){
//This example shows extrapolation for X axis only. Y position (spriteScreenY is assumed to be valid)
extrapolatedPosX = spriteGridX+(SpriteXVelocity*dt)*extrapolation;
spriteScreenPosX = extrapolationPosX * screenWidth;
drawSprite(spriteScreenX, spriteScreenY);
}
Éditer
Comme je l'ai mentionné ci-dessus, j'ai essayé de faire une copie des coordonnées du sprite spécifiquement pour dessiner avec ... cela a ses propres problèmes.
Tout d'abord, quelle que soit la copie, lorsque le sprite se déplace, il est super lisse, lorsqu'il s'arrête, il oscille légèrement à gauche / à droite - car il extrapole toujours sa position en fonction du temps. Est-ce un comportement normal et pouvons-nous le «désactiver» lorsque le sprite s'arrête?
J'ai essayé d'avoir des drapeaux pour gauche / droite et d'extrapoler uniquement si l'un d'eux est activé. J'ai également essayé de copier les dernières positions et les positions actuelles pour voir s'il y a une différence. Cependant, en ce qui concerne la collision, cela n'aide pas.
Si l'utilisateur appuie sur le bouton droit et que le sprite se déplace vers la droite, lorsqu'il touche un mur, si l'utilisateur continue de maintenir le bouton droit enfoncé, le sprite continuera à s'animer vers la droite, tout en étant arrêté par le mur ( donc pas réellement en mouvement), mais parce que le bon drapeau est toujours positionné et aussi parce que la routine de collision déplace constamment le sprite hors du mur, il semble toujours au code (pas au joueur) que le sprite est toujours en mouvement, et donc l'extrapolation se poursuit. Donc, ce que le joueur verrait, c'est le sprite 'statique' (oui, il est animé, mais il ne se déplace pas réellement sur l'écran), et de temps en temps, il tremble violemment alors que l'extrapolation tente de faire sa chose ..... .. J'espère que cette aide
Réponses:
Je ne peux pas encore poster de commentaire, je vais donc poster ceci comme réponse.
Si je comprends bien le problème, cela ressemble à ceci:
Je peux penser à 3 solutions possibles. Je les énumérerai dans l'ordre le plus souhaitable pour le moins à mon humble avis.
Exemple de code pour # 2.
Je pense que le n ° 2 serait probablement le plus rapide et le plus facile à démarrer, bien que le n ° 1 semble être une solution plus précise sur le plan logique. Selon la façon dont vous gérez votre delta time, la solution # 1 peut être cassée de la même manière par un grand delta, auquel cas vous devrez peut-être utiliser à la fois # 1 et # 2 ensemble.
EDIT: J'ai mal compris votre code plus tôt. Les boucles sont censées être rendues aussi rapidement que possible et mises à jour à un intervalle défini. C'est pourquoi vous interpoleriez la position du sprite, pour gérer le cas où vous dessinez plus que la mise à jour. Cependant, si la boucle prend du retard, vous interrogez sur la mise à jour jusqu'à ce que vous soyez rattrapé ou que vous ayez ignoré le nombre maximal de tirages d'image.
Cela étant dit, le seul problème est que l'objet se déplace après une collision. En cas de collision, l'objet doit cesser de se déplacer dans cette direction. Donc, s'il y a une collision, définissez sa vitesse sur 0. Cela devrait empêcher la fonction de rendu de déplacer l'objet plus loin.
la source
Il semble que vous ayez besoin de séparer entièrement le rendu et la mise à jour de la physique. Habituellement, la simulation sous-jacente s'exécutera à des pas de temps discrets et la fréquence ne changera jamais. Par exemple, vous pouvez simuler le mouvement de votre balle tous les 1 / 60ème de seconde, et c'est tout.
Afin de permettre une fréquence d'images variable, le code de rendu doit fonctionner sur une fréquence variable, mais toute simulation doit toujours être à un pas de temps fixe. Cela permet aux graphiques de lire la mémoire de la simulation en lecture seule et de configurer l'interpolation au lieu de l'extrapolation.
Étant donné que l'extrapolation tente de prédire où seront les valeurs futures, des changements soudains de mouvement peuvent vous donner d'énormes erreurs d'extrapolation. Il est préférable de rendre votre scène à la place d'une image derrière la simulation et d'interpoler entre des positions discrètes connues.
Si vous voulez voir quelques détails de mise en œuvre, j'ai déjà écrit une courte section sur ce sujet dans un article ici . Veuillez consulter la section intitulée "Timeste".
Voici le code psuedo important de l'article:
La
RenderGame
fonction présente le plus d'intérêt. L'idée est d'utiliser l'interpolation entre des positions de simulation discrètes. Le code de rendu peut créer ses propres copies des données de simulation en lecture seule et utiliser une valeur interpolée temporaire pour le rendu. Cela vous donnera un mouvement très fluide sans aucun problème stupide comme ce que vous semblez avoir!la source