Remarque : ce didacticiel est destiné aux utilisateurs avancés et expérimentés, et il ne couvre pas des sujets tels que l'ajout de composants, la création de nouveaux scripts GameObject et la syntaxe C #. Si vous avez besoin d'améliorer vos compétences Unity, consultez nos didacticiels Prise en main de Unity et Introduction à Unity Scripting .
Dans la
première partie du tutoriel, nous avons appris à créer un crochet pour chat avec la mécanique d'enrouler une corde autour des obstacles. Cependant, nous en voulons plus: la corde peut s'enrouler autour des objets au niveau, mais elle ne se détache pas à votre retour.
Se rendre au travail
Ouvrez le projet terminé à partir de la première partie dans Unity ou téléchargez le
brouillon de cette partie du didacticiel, puis ouvrez
2DGrapplingHook-Part2-Starter . Comme dans la première partie, nous utiliserons la version Unity 2017.1 ou supérieure.
Ouvrez la scène du
jeu dans l'éditeur à partir du dossier de projet
Scènes .
Lancez la scène du jeu et essayez d'accrocher le crochet de chat sur les pierres au-dessus du personnage, puis balancez-vous pour que la corde s'enroule autour d'une paire de bords de pierre.
Lorsque vous revenez en arrière, vous remarquerez que les points de la pierre à travers lesquels la corde utilisée pour se retourner ne se décrochent plus.
Pensez au point auquel la corde doit se dérouler. Pour simplifier la tâche, il est préférable d'utiliser l'étui lorsque la corde s'enroule autour des bords.
Si la limace, accrochée à une pierre au-dessus de sa tête, pivote vers la droite, la corde se pliera après le seuil auquel elle franchit le point d'angle de 180 degrés avec la nervure à laquelle la limace est actuellement attachée. Dans la figure ci-dessous, elle est représentée par un point vert en surbrillance.
Lorsque la limace retourne dans l'autre sens, la corde doit à nouveau se décrocher au même point (surligné en rouge sur la figure ci-dessus):
La logique de détorsion
Pour calculer le moment où vous devez détordre la corde aux points sur lesquels elle a été enroulée plus tôt, nous avons besoin de connaissances en géométrie. En particulier, nous utiliserons une comparaison des angles pour déterminer quand la corde doit se détacher du bord.
Cette tâche peut sembler un peu intimidante. Les mathématiques peuvent inspirer l'horreur et le désespoir même aux plus courageux.
Heureusement, Unity a d'excellentes fonctions d'aide mathématique qui peuvent nous faciliter un peu la vie.
Ouvrez le script
RopeSystem dans l'EDI et créez une nouvelle méthode appelée
HandleRopeUnwrap()
.
private void HandleRopeUnwrap() { }
Allez dans
Update()
et ajoutez à la fin un appel à notre nouvelle méthode.
HandleRopeUnwrap();
Alors que
HandleRopeUnwrap()
ne fait rien, mais maintenant nous pouvons traiter la logique associée à l'ensemble du processus de détachement des bords.
Comme vous vous en souvenez de la première partie du didacticiel, nous avons stocké les positions d'enroulement de la corde dans une collection appelée
ropePositions
, qui est une collection
List<Vector2>
. Chaque fois qu'une corde s'enroule autour d'un bord, nous gardons la position de ce point d'enroulement dans cette collection.
Pour rendre le processus plus efficace, nous n'exécuterons aucune logique dans
HandleRopeUnwrap()
si le nombre de positions stockées dans la collection est égal ou inférieur à 1.
En d'autres termes, lorsque la limace s'est accrochée au point de départ et que sa corde n'a pas encore enroulé autour des bords, le nombre de
ropePositions
de
ropePositions
sera de 1 et nous ne suivrons pas la logique de traitement de détorsion.
Ajoutez cette simple
return
en haut de
HandleRopeUnwrap()
pour enregistrer de précieux cycles CPU, car cette méthode est appelée à partir de
Update()
plusieurs fois par seconde.
if (ropePositions.Count <= 1) { return; }
Ajout de nouvelles variables
Dans le cadre de ce nouveau test, nous ajouterons quelques dimensions et références aux différents angles nécessaires pour mettre en œuvre la base de la logique de déroulement. Ajoutez le code suivant à
HandleRopeUnwrap()
:
Il y a beaucoup de variables ici, donc je vais expliquer chacune d'entre elles, ainsi que d'ajouter une illustration pratique qui aidera à comprendre leur objectif.
anchorIndex
est l'index de la collection ropePositions
à deux positions à partir de la fin de la collection. On peut le considérer comme un point en deux positions sur la corde à partir de la position de la limace. Dans la figure ci-dessous, il s'agit du premier point de fixation du crochet à la surface. Lors du remplissage de la collection ropePositions
nouveaux points d'emballage, ce point restera toujours le point d'emballage à une distance de deux positions de la limace.hingeIndex
est l'index de la collection qui stocke le point de la charnière actuelle; en d'autres termes, la position dans laquelle la corde s'enroule actuellement autour du point le plus proche de l'extrémité de la corde de la balle. Il est toujours à une distance d'une position de la limace, c'est pourquoi nous utilisons ropePositions.Count - 1
.anchorPosition
calculé en référençant la place anchorIndex
dans la collection ropePositions
et est la simple valeur Vector2 de cette position.hingePosition
calculé en référençant la place de hingeIndex
dans la collection ropePositions
et est la simple valeur Vector2 de cette position.hingeDir
est un vecteur dirigé de anchorPosition
vers hingePosition
. Il est utilisé dans la variable suivante pour obtenir l'angle.hingeAngle
- la fonction d'aide utile Vector2.Angle()
est utilisée ici pour calculer l'angle entre anchorPosition
et le point d'articulation.playerDir
est un vecteur dirigé de anchorPosition
vers la position actuelle du slug (playerPosition)- Ensuite, en utilisant l'angle entre le point d'ancrage et le joueur (limace),
playerAngle
calculé.

Toutes ces variables sont calculées en utilisant des positions stockées en tant que valeurs Vector2 dans la collection
ropePositions
et en comparant ces positions avec d'autres positions ou la position actuelle du joueur (slug).
Les deux variables importantes utilisées pour la comparaison sont
hingeAngle
et
hingeAngle
.
La valeur stockée dans
hingeAngle
doit rester statique car il s'agit toujours d'un angle constant entre le point situé aux deux «plis de la corde» par rapport à la limace et le «pli de la corde» actuel le plus proche de la limace qui ne bouge pas tant que la corde n'est pas torsadée ou après pliage. un nouveau point de pliage sera ajouté.
Lorsque la limace se
playerAngle
change. En comparant cet angle avec
hingeAngle
, et en vérifiant également si le slug est à gauche ou à droite de ce coin, nous pouvons déterminer si le point de pliage actuel le plus proche du slug doit être détaché.
Dans la première partie de ce didacticiel, nous avons enregistré les positions de pliage dans un dictionnaire appelé
wrapPointsLookup
. Chaque fois que nous enregistrons le point de pliage, nous l'avons ajouté au dictionnaire avec la position comme clé et avec 0 comme valeur. Cependant, cette valeur de 0 était plutôt mystérieuse, non?
Nous utiliserons cette valeur pour stocker la position du slug par rapport à son angle avec le point d'articulation (le point de pliage actuel le plus proche du slug).
Si vous affectez une valeur de
-1 , alors l'angle du slug (
playerAngle
) est inférieur à l'angle de la charnière (
hingeAngle
), et avec une valeur de
1, l' angle de
playerAngle
supérieur à
hingeAngle
.
Étant donné que nous enregistrons les valeurs dans le dictionnaire, chaque fois que nous comparons
hingeAngle
avec
hingeAngle
, nous pouvons comprendre si le slug vient de dépasser la limite après laquelle la corde doit se décrocher.
Cela peut s'expliquer différemment: si l'angle de la limace vient d'être vérifié et qu'il est plus petit que l'angle de la charnière, mais la dernière fois qu'il a été enregistré dans le dictionnaire des points de pliage, il a été marqué d'une valeur indiquant qu'il était de l'autre côté de ce coin, alors le point doit être supprimé immédiatement !
Corde de désaccouplement
Jetez un œil à la capture d'écran ci-dessous avec des notes. Notre limace s'accrochait au rocher, se balançait vers le haut, enroulant une corde autour du bord du rocher en montant.
Vous remarquerez peut-être qu'à la position de swing la plus haute, où la limace est opaque, son point de pliage le plus proche actuel (marqué d'un point blanc) sera stocké dans le dictionnaire
wrapPointsLookup
avec une valeur de
1 .
En descendant, lorsque
playerAngle
devient plus petit que
hingeAngle
(deux lignes vertes en pointillés), comme indiqué par la flèche bleue, une vérification est effectuée, et si la dernière valeur (actuelle) du point de pliage était
1 , alors le point de pliage doit être supprimé.
Maintenant, implémentons cette logique dans le code. Mais avant de commencer, créons un blanc de la méthode que nous utiliserons pour nous détendre. Pour cette raison, après avoir créé la logique, cela ne conduira pas à une erreur.
Ajoutez une nouvelle méthode
UnwrapRopePosition(anchorIndex, hingeIndex)
en insérant les lignes suivantes:
private void UnwrapRopePosition(int anchorIndex, int hingeIndex) { }
Cela fait, revenons à
HandleRopeUnwrap()
. Sous les variables nouvellement ajoutées, ajoutez la logique suivante, qui gérera deux cas:
playerAngle
moins que
hingeAngle
et
hingeAngle
plus que
hingeAngle
:
if (playerAngle < hingeAngle) {
Ce code doit correspondre à l'explication de la logique décrite ci-dessus pour le premier cas (lorsque
hingeAngle
<
hingeAngle
), mais gère également le second cas (lorsque
hingeAngle
>
hingeAngle
).
- Si le point de pliage actuel le plus proche du slug a une valeur de 1 au point où
hingeAngle
< hingeAngle
, alors nous hingeAngle
ce point et effectuons un retour afin que le reste de la méthode ne s'exécute pas. - Sinon, si le point de pliage n'a pas été marqué pour la dernière fois avec une valeur de 1 , mais que
hingeAngle
playerAngle
inférieur à hingeAngle
, alors -1 est affecté. - Si le point de pliage actuel le plus proche du slug est -1 au point où
hingeAngle
> hingeAngle
, supprimez le point et revenez. - Sinon, nous attribuons les entrées dans le dictionnaire des points de pliage à la position charnière à 1 .
Ce code garantit que le dictionnaire
wrapPointsLookup
toujours mis à jour, garantissant que la valeur du point de pliage actuel (le plus proche du slug) correspond à l'angle de slug actuel par rapport au point de pliage.
N'oubliez pas que la valeur est -1 lorsque l'angle de slug est inférieur à l'angle de charnière (par rapport au point de référence), et 1 lorsque l'angle de slug est supérieur à l'angle de charnière.
Nous allons maintenant
UnwrapRopePosition()
dans le script
RopeSystem avec un code qui va directement s'engager dans le découplage, déplacer la position de référence et attribuer une nouvelle valeur de distance à la valeur de distance de corde DistanceJoint2D. Ajoutez les lignes suivantes au disque de méthode créé précédemment:
- L'index du point d'ancrage actuel (la deuxième position de la corde par rapport à la limace) devient la nouvelle position de la charnière, et l'ancienne position de la charnière est supprimée (celle qui était auparavant la plus proche de la limace et que nous sommes maintenant en train de «détordre»). La variable
newAnchorPosition
attribuer la valeur anchorIndex
dans la liste des positions de corde. Il sera ensuite utilisé pour positionner la position mise à jour du point d'ancrage. - La corde-joint RigidBody2D (à laquelle la corde DistanceJoint2D est attachée) change sa position à la nouvelle position du point d'ancrage. Cela garantit un mouvement continu et en douceur de la balle sur la corde lorsqu'elle est connectée à DistanceJoint2D, et cette connexion devrait lui permettre de continuer à osciller par rapport à la nouvelle position, qui est devenue la référence - en d'autres termes, par rapport au point suivant vers le bas de la corde à partir de sa position.
- Ensuite, vous devez mettre à jour la valeur de distance distanceJoint2D pour prendre en compte un changement brusque de la distance entre la limace et le nouveau point de référence. Si ce n'est pas déjà fait, une vérification rapide de l'indicateur
distanceSet
est effectuée et la distance est affectée à la valeur de la distance calculée entre le slug et la nouvelle position du point d'ancrage.
Enregistrez le script et revenez à l'éditeur. Redémarrez le jeu et regardez comment la corde se détache des bords lorsque la balle dépasse les valeurs de seuil de chaque point de flexion!
Bien que la logique soit prête, nous ajouterons du code d'assistance à
HandleRopeUnwrap()
juste avant de comparer
hingeAngle
avec
hingeAngle
(
if (playerAngle < hingeAngle)
).
if (!wrapPointsLookup.ContainsKey(hingePosition)) { Debug.LogError("We were not tracking hingePosition (" + hingePosition + ") in the look up dictionary."); return; }
En fait, cela ne devrait pas se produire, car nous redéfinissons et déconnectons le crochet de chat lorsqu'il s'enroule deux fois autour d'une côte, mais si cela se produit toujours, nous pouvons facilement quitter cette méthode avec une simple
return
et un message d'erreur dans la console.
De plus, grâce à cela, nous traiterons plus facilement de tels cas limites; de plus, nous recevons notre propre message d'erreur dans le cas où quelque chose d'inutile se produit.
Où aller ensuite?
Voici un
lien vers le projet terminé de cette deuxième et dernière partie du tutoriel.
Félicitations pour avoir terminé cette série de didacticiels! En ce qui concerne la comparaison des angles et des positions, tout est devenu assez compliqué, mais nous y avons survécu et nous avons maintenant un merveilleux système de crochet et de chat qui peut se retrouver sur des objets dans le jeu.
Saviez-vous que notre équipe de développement Unity a écrit un livre? Sinon, consultez
Unity Games By Tutorials . Ce jeu vous apprendra à créer quatre jeux prêts à l'emploi à partir de zéro:
- Tireur à deux bâtons
- Tireur à la première personne
- Jeu de tower defense (avec support VR!)
- Plateforme 2D
Après avoir lu ce livre, vous apprendrez à créer vos propres jeux pour Windows, macOS, iOS et autres plateformes!
Ce livre est destiné aux débutants et à ceux qui souhaitent mettre à niveau leurs compétences Unity vers un niveau professionnel. Pour maîtriser le livre, vous devez avoir une expérience en programmation (dans n'importe quelle langue).