[vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Questions à propos du scripting. Hors Shader, GUI, Audio et Mobile.
Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 18 Déc 2022 14:59

Je vais devoir te contredir, j'ai fait le test pour être sur de ce que je dis, preuve a l'appuie.

Il faut un rigidbody pour détecter une collision.

pour prouvez mes dire, j'ai mis deux pnj créer pour l'occasion,
Rick Astley et un sanglier.

Image

Sur Rick Astley, j'ai mis le script que j'utilise actuellement et dont on parle dans les messages précédents.

Sur le sanglier j'ai mis le script présenter dans la vidéo "Créer un jeu en 2D facilement avec Unity (#4 : Premier ennemi)"
qui fonctionne donc sans rigidBody
(voici le script)

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestPnjMove : MonoBehaviour
{
    public float speed;
    public Transform[] waypoints;

    private Transform target;
    public int destPoint = 0;

    void Start()
    {
        target = waypoints[0];
    }

    void Update()
    {
        Vector3 dir = target.position - transform.position;
        transform.Translate(dir.normalized * speed * Time.deltaTime, Space.World);

        if (Vector3.Distance(transform.position, target.position) < 1.2f)
        {
            destPoint = (destPoint + 1) % waypoints.Length;
            target = waypoints[destPoint];
        }
    }
}
Sur le waypoint vert et le waypoint jaune, j'ai mis un script basic de détection de colision avec une différence pour le Debug.Log.

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class testCollisionJaune : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("PNJ"))
        {
            Debug.Log("le pnj a toucher le waypoint Jaune");
        }
    }
}

Code : Tout sélectionner

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class testcollisionVert : MonoBehaviour
{
    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("PNJ"))
        {
            Debug.Log("le pnj a toucher le waypoint vert");
        }
    }
}
les deux waypoint on une box collider2d et j'ai bien coché "istrigger" chez les deux.
je précise également que les deux pnj ont le tag "pnj".

https://www.youtube.com/watch?v=7ByEoz7E09Q

même si la vitesse est différente, on voit bien que Rick Astley avec son rigidbody arrive a activé le waypoint vert mais pas le sanglier sans rigidBody

J'ai tester en mettant "istrigger" ou pas sur la box collider du sanglier ça ne change rien.

Donc conclusion, le rigidbody est indispensable .

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 18 Déc 2022 15:22

jmhoubre a écrit :
18 Déc 2022 10:27
Je ne dis pas qu'il faut enlever le rigidbody du PNJ, mais peut-être modifier son type.

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 18 Déc 2022 15:46

c'est a dire ?
qu'est ce que ça changerais de modifier le type du rigidbody ?

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 18 Déc 2022 18:06

Le body type d'un rigidbody 2D peut être de 3 types : dynamic, kinematic, static.

Le type dynamic est le type par défaut, le plus consommateur de ressources. Il faut donc bien réfléchir s'il est nécessaire de l'utiliser. Il est affecté par les forces, dont la gravité, il a une masse finie. On ne doit pas utiliser son Transform pour modifier sa position/rotation, mais les forces et la vélocité.

Le type kinematic n'est pas affecté par les forces, et utilise donc moins de ressources. Sa position est normalement gérée via Rigidbody2D.MovePosition ou Rigidbody2D.MoveRotation. La détection des collisions se fait avec des body dynamic. Dans les autres cas, la case "Use Full Kinematic Contacts" est à cocher si on veut des collisions avec des body kinematic ou static.

Le type static est conçu pour ne pas être affecté par la simulation physique et se comporte comme un objet fixe de masse infinie (le sol, les murs, un gros rocher, ...). C'est le type le plus économe en ressources. Un Rigidbody 2D statique ne provoque une collision qu'avec un Rigidbody 2D dynamic (plus précisément un collider attaché à un Rigidbody...).

Pour ton projet, je ne vois pas (pour l'instant) d'endroit où tu utilises des forces, donc j'utiliserais des body kinematic pour tous les gameobjets mobiles (poupoule, PNJ, ...) avec la case "Use Full Kinematic Contacts" cochée, et des body static (si besoin) pour les objets fixes (décors, items, ...)

Pour plus d'info, la doc est là.

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 18 Déc 2022 18:24

oui je comprend mieux, en effet je vais changer ça, je ne garderais les rigidBody dynamiques que sur les mottes de terres (projectile du joueurs) et les pierres qui tombes des arbres à cailloux (un "ennemis") .

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 19 Déc 2022 20:58

jmhoubre a écrit :
18 Déc 2022 10:27

- suivre le personnage principal : si tu as déjà mis en place un navigation mesh, c'est assez facile. Le PNJ met sa destination sur poupoule, puis régulièrement (2 ou 3 fois par seconde), teste la distance PNJ-Poupoule et règle sa vitesse en fonction. Tu peux même ajouter au PNJ un champ distanceToPlayer, et le régler sur une certaine distance :

Code : Tout sélectionner

using UnityEngine;

public class FollowPlayer : MonoBehaviour
{
	private enum DistanceToPlayer { NEAR = 5, MEDIUM = 10, FAR = 20 }

	[SerializeField] private DistanceToPlayer distanceToPlayer = DistanceToPlayer.MEDIUM;
	[SerializeField] private bool MustFloowPlayer = false;

	private float minDistance;
	private float maxDistance;
	private Vector3 playerPosition;

	private void Awake ()
	{
		// Lance la méthode de vérification de distance toutes les 1/2 secondes.
		InvokeRepeating (nameof (Move), 0f, 0.5f);

		// On souhaite que le PNJ soit à +/- 10% de la distance programmée.
		minDistance = 0.9f * (float) distanceToPlayer;
		maxDistance = 1.1f * (float) distanceToPlayer;
	}

	private void Move ()
	{
		if (MustFloowPlayer == false) { return; }

		// Contrôle la distance.
		playerPosition = PoupouleControle.Instance.transform.position;
		float currentDistance = (playerPosition - transform.position).magnitude;

		// Si le PNJ est dans l'intervalle de distance, on ne fait rien.
		if (currentDistance > minDistance && currentDistance < maxDistance) { return; }

		// Modifie la vitesse.
		float modifier = 1f;
		if (currentDistance <= minDistance)
		{
			modifier = minDistance / currentDistance;
		}
		else if (currentDistance>=maxDistance)
		{
			modifier = currentDistance / maxDistance;
		}
		PoupouleControle.Instance.PlayerSpeed *= modifier;
	}
}
Remarque : pour accéder à la vitesse, j'ai ajouté dans PoupouleControle :

Code : Tout sélectionner

public float PlayerSpeed { get=>speed; set { speed = value; }}
J'ai testé ton code, je l'ai mis sur un mouton et j'ai intégrer un item de corde a atacher au mouton.
et ...
Bin dés que le mouton est censé suivre la perso, elle est propulsée a l'autre bout de la map, en déclenchant au passage quelques erreurs du aux scriptes qui arrivent plus a suivre.
Je me demandais, c'est normale que le script modifie la vitesse du joueur ?
j'ai mal implémenter le truc ?
(je n'ai jamais mis en place un navigation mesh)

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 19 Déc 2022 22:52

Effectivement, j'ai dit une bêtise. J'avais commencé à rédiger sans NavMesh, et je me suis emmêlé les pinceaux. Je ne peux pas tester cette partie, il faudrait que je fasse une scène avec une TileMap.

Nouvelle version : dans le NavMeshAgent du mouton, je pense qu'il faut placer la distance de suivi dans StoppingDistance.

Je vais regarder ce que cela donne en 3D.

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 20 Déc 2022 00:10

En 3D, cela fonctionne bien.
Voici les scripts, j'ai adapté PoupouleControle à la 3D :

Code : Tout sélectionner

using UnityEngine;

public class PoupouleControle3D : MonoBehaviour
{
	public static PoupouleControle3D Instance;

	[SerializeField] private float speed = 3.0f;

	private Rigidbody _rigidbody;

	private float _horizontal;
	private float _vertical;

	private void Awake ()
	{
		// Singleton.
		if (Instance != null)
		{
			Debug.LogWarning ("Il y a déjà une instance de PoupouleControle3D dans la scène");
			return;
		}
		Instance = this;

		// Récupère les références.
		_rigidbody = GetComponent<Rigidbody> ();
	}

	private void Update ()
	{
		PlayerMove ();
	}

	private void PlayerMove ()
	{
		_horizontal = Input.GetAxis ("Horizontal");
		_vertical = Input.GetAxis ("Vertical");
	}

	private void FixedUpdate ()
	{
		Vector3 position = _rigidbody.position;
		position.x += speed * _horizontal * Time.deltaTime;
		position.y = 0f;
		position.z += speed * _vertical * Time.deltaTime;
		_rigidbody.MovePosition (position);
	}

	public float PlayerSpeed { get => speed; }
}
Le mouton est une capsule avec NavMeshAgent et ce script. L'enum DistanceToPlayer permet de modifier la distance dans l'inspecteur.
Pour avoir un comportement moins mécanique, j'ai pris soin de fixer une distance mini et maxi : le mouton doit se trouver dans cet intervalle. Si c'est le cas, il broute. Sinon il galope. De plus le modificateur de vitesse tient compte de la distance. Plus il est loin du joueur, plus le mouton accélère. On peut bien sûr améliorer en ajoutant un peu d'aléa, fixer une vitesse maxi selon le type de PNJ ...

Code : Tout sélectionner

using UnityEngine;
using UnityEngine.AI;

public class SheepBehaviour : MonoBehaviour
{
	private enum DistanceToPlayer { NEAR = 5, MEDIUM = 10, FAR = 20 }

	[SerializeField] private DistanceToPlayer _distanceToPlayer = DistanceToPlayer.MEDIUM;
	[SerializeField] private bool _mustFollowPlayer = false;

	private float _minDistance;
	private float _maxDistance;
	private Vector3 _playerPosition;

	private NavMeshAgent _agent;

	private void Awake ()
	{
		_agent = GetComponent<NavMeshAgent> ();
		_agent.stoppingDistance = (float)_distanceToPlayer;

		// On souhaite que le PNJ soit à +/- 10% de la distance programmée.
		_minDistance = 0.9f * (float) _distanceToPlayer;
		_maxDistance = 1.1f * (float) _distanceToPlayer;
	}

	private void Start ()
	{
		// Lance la méthode de vérification de distance toutes les 1/2 secondes.
		InvokeRepeating (nameof (CheckDistancePnjToPlayer), 0f, 0.5f);
	}

	private void CheckDistancePnjToPlayer ()
	{
		if (_mustFollowPlayer == false) { return; }

		// Contrôle la distance.
		_playerPosition = PoupouleControle3D.Instance.transform.position;
		float currentDistance = (_playerPosition - transform.position).magnitude;

		// Met à jour la destination.
		_ = _agent.SetDestination (_playerPosition);

		// Si le PNJ est dans l'intervalle de distance, on ne fait rien.
		if (currentDistance > _minDistance && currentDistance < _maxDistance) { return; }

		// Ajuste la vitesse.
		float modifier = 1f;
		if (currentDistance <= _minDistance)
		{
			modifier = _minDistance / currentDistance;
		}
		else if (currentDistance >= _maxDistance)
		{
			modifier = currentDistance / _maxDistance;
		}
		_agent.speed = PoupouleControle3D.Instance.PlayerSpeed * modifier;
	}
}

Avatar de l’utilisateur
jmhoubre
Messages : 856
Inscription : 05 Oct 2019 22:05

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par jmhoubre » 20 Déc 2022 20:55

J'ai modifié le script du mouton :
  • On peut désigner la cible à suivre dans l'inspecteur : cela permet par exemple de mettre plusieurs moutons en file indienne.
  • J'ai réduit (un peu) le phénomène d'accordéon en ajoutant un Lerp de la vitesse.
  • La vitesse initiale (~marche) et la vitesse maximale (course) sont modifiables dans l'inspecteur.
  • La plage de distance cible pour le PNJ est plus large (20% au lieu de 10%).

Code : Tout sélectionner

using UnityEngine;
using UnityEngine.AI;

public class SheepBehaviour : MonoBehaviour
{
	private const float CHECK_RATE = 0.25f;
	private enum DistanceToPlayer { NEAR = 5, MEDIUM = 10, FAR = 20 }

	[SerializeField] private Transform _targetToFollow;
	[SerializeField] private DistanceToPlayer _distanceToTarget = DistanceToPlayer.MEDIUM;
	[SerializeField] private float _initialSpeed = 1f;
	[SerializeField] private float _maxSpeed = 6.67f; // Pour un mouton...
	[SerializeField] private bool _mustFollowTarget = false;

	private float _minDistance;
	private float _maxDistance;
	//private Vector3 _playerPosition;	

	private NavMeshAgent _agent;

	private void Awake ()
	{
		_agent = GetComponent<NavMeshAgent> ();
		_agent.stoppingDistance = (float) _distanceToTarget;
		_agent.speed = _initialSpeed;

		// On souhaite que le PNJ soit à +/- 20% de la distance programmée.
		_minDistance = 0.8f * (float) _distanceToTarget;
		_maxDistance = 1.2f * (float) _distanceToTarget;
	}

	private void Start ()
	{
		// Lance la méthode de vérification de distance toutes les  secondes.
		InvokeRepeating (nameof (CheckDistancePnjToPlayer), 0f, CHECK_RATE);
	}

	private void CheckDistancePnjToPlayer ()
	{
		if (_mustFollowTarget == false || _targetToFollow == null) { return; }

		// Contrôle la distance.
		float currentDistance = (_targetToFollow.position - transform.position).magnitude;

		// Met à jour la destination.
		_ = _agent.SetDestination (_targetToFollow.position);

		// Si le PNJ est dans l'intervalle de distance, on ne modifie pas la vitesse.
		if (_minDistance < currentDistance && currentDistance < _maxDistance) { print ("Speed constant."); return; }

		// Ajuste la vitesse.
		float modifier = 1f;
		if (currentDistance <= _minDistance)
		{
			modifier = _minDistance / currentDistance;
		}
		else if (currentDistance >= _maxDistance)
		{
			modifier = currentDistance / _maxDistance;
		}

		// Calcul de la vitesse selon que l'on suit le joueur ou un mouton.
		float sheepSpeed;
		SheepBehaviour sheep = _targetToFollow.GetComponent<SheepBehaviour> ();
		if (sheep != null)
		{
			// Mouton.
			sheepSpeed = sheep.GetComponent<NavMeshAgent> ().speed;
		}
		else
		{
			// Joueur.
			sheepSpeed = PoupouleControle3D.Instance.PlayerSpeed * modifier;
		}

		float currentSpeed = Mathf.Lerp (_agent.speed, sheepSpeed, CHECK_RATE);
		currentSpeed = Mathf.Clamp (currentSpeed, 0f, _maxSpeed);
		_agent.speed = currentSpeed;
	}
}

Avatar de l’utilisateur
poupoule_h5n1
Messages : 48
Inscription : 28 Nov 2022 20:24

Re: [vraiment résolu]Déplacer le joueur avec un script puis lui rendre le contrôle des mouvements

Message par poupoule_h5n1 » 21 Déc 2022 00:49

ça va me demander pas mal de bidouillage pour pouvoir tester ton code.
je ne connais pas les Navmeshs, donc je vais chercher a apprendre comment en mettre une en place.
J'ai crus voire entre deux ligne que les Navmeshs de base de unity ne fonctionnent pas en 2d.
j'ai trouver une Navmesh en 2d mais reste a voir si ça peut s’implémenter sur mon projet sans tout casser.
sI oui reste a voir si ton code peut fonctionné avec.

Je vais aussi chercher a créer un truc de mon coté, plus simple.

Répondre

Revenir vers « Scripting »