Mécanique de plateforme Plateformes de déménagement

Ce que vous allez créer

Dans ce tutoriel, vous apprendrez à créer des plates-formes mobiles et à vous assurer que les objets les chevauchant conserveront leur position relative. Nous allons également traiter le cas d'être écrasé entre une plate-forme et le sol.

Conditions préalables

Ce tutoriel est basé sur la série Basic Platformer Physics. Plus précisément, nous utiliserons le code basé sur la 8ème partie du didacticiel comme point de départ, avec quelques modifications. Découvrez la série de tutoriels, et en particulier la dernière partie. Les principes sous-jacents à la mise en œuvre resteront valables même si vous utilisez une solution physique différente, mais le code sera compatible avec la version présentée dans la série de tutoriels..

Démo

Vous pouvez télécharger la démo à partir des pièces jointes du didacticiel. Utilisez le WASD touches pour déplacer le personnage, Espace pour générer un personnage clone, et P pour engendrer une plate-forme en mouvement. Le bouton droit de la souris crée une tuile. Vous pouvez utiliser la molette de défilement ou les touches fléchées pour sélectionner la mosaïque que vous souhaitez placer. Les curseurs changent la taille du personnage du joueur.

La démo a été publiée sous Unité 2017.2b4, et le code source est également compatible avec cette version de Unity.

la mise en oeuvre

Plateformes de déménagement

Tout d'abord, créons un script pour une plateforme en mouvement.

Initialisation

Commençons par créer la classe de l'objet.

Classe publique MovingPlatform: MovingObject 

Maintenant initialisons quelques paramètres de base de l'objet dans la fonction init.

public void Init () mAABB.HalfSize = new Vector2 (32.0f, 8.0f); mSlopeWallHeight = 0; mMovingSpeed ​​= 100.0f; mISKinematic = true; mSpeed.x = mMovingSpeed; 

Nous définissons la taille et la vitesse, et nous créons la cinématique du collisionneur, ce qui signifie qu’il ne sera pas déplacé par des objets ordinaires. Nous avons également mis le mSlopeWallHeight à 0, ce qui signifie que la plate-forme ne montera pas sur les pentes - elle les traitera toujours comme des murs.

Comportement

Le comportement de cette plateforme en mouvement sera le suivant: commencez le mouvement correctement et, chaque fois que vous rencontrez un obstacle, changez la direction de 90 degrés dans le sens des aiguilles d'une montre..

public void CustomUpdate () if (mPS.pushesRightTile &&! mPS.pushesBottomTile) mSpeed.y = -mMovingSpeed; else if (mPS.pushesBottomTile &&! mPS.pushesLeftTile) mSpeed.x = -mMovingSpeed; else if (mPS.pushesLeftTile &&! mPS.pushesTopTile) mSpeed.y = mMovingSpeed; else if (mPS.pushesTopTile &&! mPS.pushesRightTile) mSpeed.x = mMovingSpeed; UpdatePhysics (); 

Voici le motif visualisé:

Coller le personnage à la plate-forme

Pour le moment, si un personnage se tient sur une plate-forme, celle-ci glissera simplement de dessous, comme s'il n'y avait pas de frottement entre les objets. Nous allons essayer d'y remédier en copiant l'offset de la plateforme.

Déterminer l'objet parent

Tout d'abord, nous voulons savoir sur quel objet, le cas échéant, notre personnage se tient. Déclarons une référence à cet objet dans le MovingObject classe.

public MovingObject mMountParent = null;

Maintenant, dans le UpdatePhysicsResponse, si nous détectons que nous entrons en collision avec un objet situé au-dessous de nous, nous pouvons attribuer cette référence. Créons une fonction qui assignera d'abord la référence.

public void TryAutoMount (plateforme MovingObject) if (mMountParent == null) mMountParent = plateforme; 

Maintenant, utilisons-le dans des endroits appropriés, c’est-à-dire partout où nous disons que notre objet entre en collision avec un autre objet situé en dessous..

else if (overlap.y == 0.0f) if (other.mAABB.Center.y> mAABB.Center.y) mPS.pushesTopObject = true; mSpeed.y = Mathf.Min (mSpeed.y, 0.0f);  else TryAutoMount (other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max (mSpeed.y, 0.0f);  continuer; 

La première place est lorsque nous vérifions si les objets se touchent.

si (chevauchement < 0.0f)  mPS.pushesTopObject = true; mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);  else  TryAutoMount(other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); 

La deuxième place est quand ils se chevauchent.

Maintenant que nous avons couvert cela, gérons le mouvement de notre objet. Modifions le UpdatePhysics fonction du tutoriel précédent.

Déclarons une variable de classe pour le décalage dont nous avons besoin pour déplacer notre personnage.

public Vector2 mOffset;

Remplaçons maintenant l'ancien offset local par le premier.

mOffset = mSpeed ​​* Time.deltaTime;

Si l'objet se trouve sur une plate-forme, ajoutons le mouvement de la plate-forme à l'offset.

mOffset = mSpeed ​​* Time.deltaTime; if (mMountParent! = null) if (HasCollisionDataFor (mMountParent)) mOffset + = mMountParent.mPosition - mMountParent.mOldPosition; else mMountParent = null; 

Notez que nous vérifions également ici si nous sommes toujours en contact avec l'objet. Si ce n'est pas le cas, nous définissons le mMountParent à nul, marquer que cet objet ne monte plus sur aucun autre.

Ensuite, déplaçons la position de notre objet de ce décalage. Nous n'allons pas utiliser notre Bouge toi fonction, mais changez simplement la position. Donc, dans la vérification de collision entre les objets, qui a lieu juste après la UpdatePhysics, nous aurons le résultat pour les positions dans ce cadre au lieu du précédent.

mOffset = mSpeed ​​* Time.deltaTime; if (mMountParent! = null) if (HasCollisionDataFor (mMountParent)) mOffset + = mMountParent.mPosition - mMountParent.mOldPosition; else mMountParent = null;  mPosition + = RoundVector (mOffset + mReminder); mAABB.Center = mPosition;

Passons maintenant au UpdatePhysicsP2, qui est appelé après la résolution des conflits entre les objets. Ici, nous annulons notre mouvement précédent, qui n'a pas été vérifié pour savoir s'il est valide ou non..

public void UpdatePhysicsP2 () mPosition - = RoundVector (mOffset + mReminder); mAABB.Center = mPosition;

Ensuite, nous passons à UpdatePhysicsResponse appliquer un mouvement de chevauchement avec d'autres objets. Ici, auparavant, nous modifions la position directement, mais maintenant modifions le mOffset, donc ce changement de position est résolu plus tard lorsque nous utilisons notre Bouge toi une fonction.

if (smallestOverlap == Mathf.Abs (overlap.x)) float offsetX = overlap.x * speedRatioX; mOffset.x + = offsetX; offsetSum.x + = offsetX; si (overlap.x < 0.0f)  mPS.pushesRightObject = true; mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);  else  mPS.pushesLeftObject = true; mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);   else  float offsetY = overlap.y * speedRatioY; mOffset.y += offsetY; offsetSum.y += offsetY; if (overlap.y < 0.0f)  mPS.pushesTopObject = true; mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);  else  TryAutoMount(other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max(mSpeed.y, 0.0f);  

Maintenant, nous pouvons revenir à la UpdatePhysicsP2, où nous appelons simplement le UpdatePhysicsResponse et Bouge toi fonctionne comme nous l'avons fait précédemment, pour obtenir l'état de position correct.

mPosition - = RoundVector (mOffset + mReminder); mAABB.Center = mPosition; UpdatePhysicsResponse (); if (mOffset! = Vector2.zero) Déplacer (mOffset, mSpeed, ref mPosition, ref mReminder, mAABB, ref mPS);

Fixer la commande de mise à jour

En raison de la façon dont nous commandons les mises à jour physiques, si l'objet enfant est mis à jour avant le parent, l'enfant perd constamment le contact avec la plate-forme lorsqu'il monte / descend.

Pour résoudre ce problème, chaque fois que nous définissons la mMountParent, si la plate-forme se trouve derrière l'enfant dans la file d'attente de mise à jour, nous échangeons ces deux éléments afin que l'objet parent soit toujours mis à jour en premier. Faisons cette modification dans le TryAutoMount une fonction.

public void TryAutoMount (plateforme MovingObject) if (mMountParent == null) mMountParent = plateforme; if (platform.mUpdateId> mUpdateId) mGame.SwapUpdateIds (this, plateforme); 

Comme vous pouvez le constater, si l'ID de mise à jour de l'objet de plate-forme est supérieur à celui de l'enfant, l'ordre de mise à jour des objets est échangé, ce qui élimine le problème..

C'est à peu près tout quand il s'agit de coller le personnage sur la plate-forme en mouvement.

Détecter être écrasé

Détecter être écrasé est assez simple. dans le UpdatePhysicsResponse, nous devons voir si le chevauchement avec un objet cinématique nous déplace dans un mur. 

Prenons d'abord soin de l'axe X:

if (smallestOverlap == Mathf.Abs (overlap.x)) float offsetX = overlap.x * speedRatioX; mOffset.x + = offsetX; offsetSum.x + = offsetX; si (overlap.x < 0.0f)  mPS.pushesRightObject = true; mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);  else  mPS.pushesLeftObject = true; mSpeed.x = Mathf.Max(mSpeed.x, 0.0f);  

Si l’objet est à notre droite et que nous poussons déjà contre un mur de gauche, appelons un Écraser fonction, que nous mettrons en œuvre plus tard. Faites la même chose de l'autre côté.

si (overlap.x < 0.0f)  if (other.mIsKinematic && mPS.pushesLeftTile) Crush(); mPS.pushesRightObject = true; mSpeed.x = Mathf.Min(mSpeed.x, 0.0f);  else  if (other.mIsKinematic && mPS.pushesRightTile) Crush(); mPS.pushesLeftObject = true; mSpeed.x = Mathf.Max(mSpeed.x, 0.0f); 

Répétons cela pour l'axe Y.

si (chevauchement < 0.0f)  if (other.mIsKinematic && mPS.pushesBottomTile) Crush(); mPS.pushesTopObject = true; mSpeed.y = Mathf.Min(mSpeed.y, 0.0f);  else  if (other.mIsKinematic && mPS.pushesTopTile) Crush(); TryAutoMount(other); mPS.pushesBottomObject = true; mSpeed.y = Mathf.Max(mSpeed.y, 0.0f); 

le Écraser la fonction déplacera simplement le personnage au centre de la carte pour la démonstration.

public void Crush () mPosition = mMap.mPosition + nouveau vecteur3 (mMap.mWidth / 2 * Map.cTileSize, mMap.mHeight / 2 * Map.cTileSize); 

Le résultat est le personnage téléporté quand il est écrasé par une plateforme.

Résumé

Il s’agissait d’un bref tutoriel car l’ajout de plates-formes mobiles n’était pas un gros problème, surtout si vous connaissez bien le système de physique. Empruntant à tout le code de la série de tutoriels de physique, c’était en fait un processus très fluide. 

Ce tutoriel a été demandé à quelques reprises, j'espère que vous le trouverez utile! Merci d'avoir lu et à la prochaine fois!