[Résolu][DB-MY] Résoudre les collisions : glissement le long d'une paroi

Pour les scripts écrits en C#
Règles du forum
Merci de respecter la NOMENCLATURE suivante pour vos TITRES de messages :

Commencez par le niveau de vos scripts
DB = Débutant
MY = Moyen
CF = Confirmé

Puis le domaine d'application
-RS = Réseau
-AL = Algorithmie

Exemple :

[DB-RS] Mouvement perso multijoueur
ticoel
Messages : 20
Inscription : 21 Juin 2017 13:31

[Résolu][DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par ticoel » 01 Août 2017 21:43

Bonsoir,

Je continue mes recherches sur les Characters Controller, et notamment ceux sans Rigidbody, et je cherche plus ou moins à reproduire la fonction move du character controller, notamment sa gestion des collisions où le personnage se bloque s'il est face à un mur, sinon il glisse à droite ou à gauche le long de celui-ci.

Je trouve pas mal choses à propos de la détection des collisions, mais presque rien sur leur résolution, et le problème me semble bien compliqué. Après quelques essais, j'ai trouvé comme solution de réinitialiser la vélocité à zéro en cas de contact, cela ignore l'angle de contact et bloque le personnage pendant que la direction forward ne pointe plus vers le mur. J'aimerais pouvoir en fonction de l'angle de contact, glissé le long du mur comme cela se produit avec le character controller de Unity.

J'ai trouvé une demi solution en calculant deux vectors à partir de la normale renvoyer par le raycasthit, mais le glissement s'effectue que dans un sens, parfois avec des sautillements, et cela ne fonctionne pas dans toutes les directions.

Voici le code de ma fonction update :
void Update()
{
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));

if (input.magnitude > 1)
input.Normalize();

if (input != Vector2.zero)
{
angle = Mathf.Atan2(input.x, input.y) * Mathf.Rad2Deg;
targetRotation = Quaternion.AngleAxis(angle, Vector3.up);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, smoothRotationSpeed);
}

direction = Vector3.forward * input.magnitude * walkSpeed * Time.deltaTime;

HandleHorizontalCollisions(ref direction);

transform.Translate(direction);
}
Voici le code de ma fonction qui détectent les collisions avant d'appliquer le nouveau déplacement :
void HandleHorizontalCollisions(ref Vector3 velocity)
{
RaycastHit hit;
Vector3 p1 = transform.position + CapColl.center + transform.up * (CapColl.height/2 - CapColl.radius);
Vector3 p2 = transform.position + CapColl.center - transform.up * (CapColl.height / 2 - CapColl.radius);
Vector3 dir = Vector3.forward;
dir = transform.TransformDirection(dir);
float distance = Mathf.Abs(velocity.magnitude);
bool collision = false;

collision = Physics.CapsuleCast(p1, p2, CapColl.radius - skinWidth, dir, out hit, distance);
if (collision)
{
Debug.DrawRay(hit.point, hit.normal, Color.blue);

float theta = Vector3.Angle(hit.normal, Vector3.up) * Mathf.Deg2Rad;

Vector3 parallel = Vector3.forward * Mathf.Cos(theta) + Vector3.up * Mathf.Sin(theta);
Debug.DrawRay(hit.point, parallel, Color.cyan);

Vector3 perpendicular = Vector3.Cross(hit.normal, parallel);
perpendicular *= Mathf.Sign(Input.GetAxisRaw("Horizontal"));
Debug.DrawRay(hit.point, perpendicular, Color.magenta);

perpendicular = transform.TransformDirection(perpendicular);

velocity = perpendicular * velocity.z;
//velocity += Vector3.back * velocity.z;
}
}
Si vous avez des pistes de réflexions, des solutions, des suggestions, c'est à vous !! :)
Dernière édition par ticoel le 15 Août 2017 16:15, édité 1 fois.

Avatar de l’utilisateur
Greg
Messages : 156
Inscription : 08 Mai 2017 15:22

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par Greg » 02 Août 2017 07:44

Bonjour,

peut-être que le triptyque OnCollisionEnter, OnCollisionStay et OnCollisionExit serait plus approprié...

https://www.binpress.com/tutorial/Collisions-basics

Ensuite, je tenterais un truc genre :
ontriggerenter :
si collision == mur
définir d'après la rotation du personnage si celui-ci regarde vers la gauche ou la droite du mur

ontriggerstay :
si y regardait a gauche, lerp puis lock sa rotation à +45°
si y regardait a droite, lerp puis lock sa rotation à -45°

ontriggerexit :
unlock la rotation

:merci:
Mon jeu de développement cellulaire : MICROBIOME (encore quelques bugs...)
(merci bien à ceux qui passent mettre des étoiles ! ^^)

ticoel
Messages : 20
Inscription : 21 Juin 2017 13:31

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par ticoel » 02 Août 2017 18:07

Comment est-ce que tu détectes si le personnage regarde à droite ou à gauche ?

J'ai essayé de regarder via son transform.eulerAngles.y, mais l'angle tourne en fonction du monde, localTransformAngles.y me donne les mêmes résultats.

J'ai aussi essayé de déterminer l'angle via ce code, mais l'ange est toujours positif, peu importe l'angle de collision. Il est donc impossible de récupérer le sens pour changer la direction du vecteur perpendicular.

Code : Tout sélectionner

angle = Vector3.Angle(Vector3.forward, perpendicular);
Concernant l'ajout d'un Rigidbody, j'essaie d'éviter afin de recréer un Character Controller à ma sauce, mais s'il le faut j'en ajouterai un.

ticoel
Messages : 20
Inscription : 21 Juin 2017 13:31

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par ticoel » 03 Août 2017 13:58

Bonjour,

J'ai trouvé une solution pour trouver le sens du personnage en envoyant deux rayons l'un à droite et l'autre à gauche, et en fonction, cela modifie le sens de la direction perpendiculaire. J'aurais aimé trouver une solution peut-être plus élégante sans rayon (CapusleCast ou Raycast). Si vous avez des idées !! :)

En attendant voici une base fonctionnelle.

La fonction de mise à jours.
void FixedUpdate()
{
input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));

if (input.magnitude > 1)
input.Normalize();

if (input != Vector2.zero)
{
angle = 90 - Mathf.Atan2(input.y, input.x) * Mathf.Rad2Deg;
targetRotation = Quaternion.AngleAxis(angle, Vector3.up);
transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, smoothRotationSpeed);
}

velocity = transform.forward * input.magnitude * walkSpeed * Time.fixedDeltaTime;

HandleHorizontalCollisions();

transform.Translate(velocity, Space.World);
}

La fonction qui s'occupe de gérer les collisions.
void HandleHorizontalCollisions()
{
RaycastHit hit;
Vector3 p1 = transform.position + CapColl.center + transform.up * (CapColl.height / 2 - CapColl.radius);
Vector3 p2 = transform.position + CapColl.center - transform.up * (CapColl.height / 2 - CapColl.radius);
float distance = Mathf.Abs(velocity.magnitude);

Vector3 dirL = transform.right * -1;
bool left = Physics.CapsuleCast(p1, p2, CapColl.radius, dirL, out hit, distance);

Vector3 dirR = transform.right;
bool right = Physics.CapsuleCast(p1, p2, CapColl.radius, dirR, out hit, distance);

Vector3 dirF = transform.forward;
Debug.DrawRay(p1, dirF, Color.blue);
bool forward = Physics.CapsuleCast(p1, p2, CapColl.radius, dirF, out hit, distance);
if (forward)
{
float theta = Vector3.Angle(hit.normal, Vector3.up) * Mathf.Deg2Rad;

Vector3 parallel = transform.forward * Mathf.Cos(theta) + transform.up * Mathf.Sin(theta);

Vector3 perpendicular = Vector3.Cross(hit.normal, parallel);

if (right) perpendicular *= -1;
else if (left) perpendicular *= 1;
else perpendicular *= 0;

Debug.Log(perpendicular);

velocity = perpendicular * input.magnitude * walkSpeed * friction * Time.fixedDeltaTime;
}
}

Avatar de l’utilisateur
Greg
Messages : 156
Inscription : 08 Mai 2017 15:22

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par Greg » 06 Août 2017 07:22

Mon jeu de développement cellulaire : MICROBIOME (encore quelques bugs...)
(merci bien à ceux qui passent mettre des étoiles ! ^^)

ticoel
Messages : 20
Inscription : 21 Juin 2017 13:31

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par ticoel » 11 Août 2017 23:18

Le problème que j'ai en utilisant Vector3.Angle est que ça donne aucune information de sens, seulement l'angle, alors comment savoir si on est à gauche ou à droite ? :)

Avatar de l’utilisateur
F@B
Messages : 1844
Inscription : 01 Août 2013 10:41
Contact :

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par F@B » 13 Août 2017 11:31

vas falloir faire un peu de géométrie pour trouver la gauche de la droite ;)

le Dot Product est bien utile pour ça :
https://forum.unity3d.com/threads/left- ... ion.31420/
ʕ·͡ᴥ·ʔ ==> Mon Portfolio <== ʕ·͡ᴥ·ʔ

Merci de lire et de prendre en considération la Nétiquette des Forums avant de poster un sujet !

ticoel
Messages : 20
Inscription : 21 Juin 2017 13:31

Re: [DB-MY] Résoudre les collisions : glissement le long d'une paroi

Message par ticoel » 14 Août 2017 23:07

Merci à vous deux. Je connaissais le dot product seulement de nom, et effectivement après quelques essais ça marche mieux que les raycasts. Mais je viens de m’apercevoir, alors que j'avais déjà cherché sans le voir, qu'il existe une fonction Vector3.SignedAngle qui renvoie un angle et un sens.

Répondre

Revenir vers « (C#) CSharp »