Bouger un personnage au click de la souris

Le problème exposé dans ce sujet a été résolu.

Bonjour,
J’essaye de jouer un peu avec Unity 3D. J’ai un personnage que j’aimerais déplacer sur un plan à l’aide de la souris (un peu à la Age Of Empire). Voici le script que j’ai pondu :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{

    public float rotateSpeed = 20f;
    public float walkSpeed = 0.5f;

    void Update ()
    {
        MovePlayer();
    }

    private void MovePlayer ()
    {
        Plane playerPlane = new Plane(Vector3.up, transform.position);
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float hitdist = 0.0f;

        if (playerPlane.Raycast(ray, out hitdist))
        {
            Vector3 targetPoint = ray.GetPoint(hitdist);
            Quaternion targetRotation = Quaternion.LookRotation(targetPoint - transform.position);

            transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotateSpeed * Time.deltaTime);

            if (Input.GetMouseButtonDown(0))
            {
                while (transform.position != targetPoint)
                {
                    transform.position = Vector3.MoveTowards(transform.position, targetPoint, walkSpeed * Time.deltaTime);
                }
            }
        }
    }
}

Le joueur regarde constamment dans la direction du curseur. J’ai actuellement deux problèmes :

  • Le personnage se téléporte à la position cliqué, il n’y a pas de mouvement.
  • J’ai placé un cube sur mon plan afin de simuler une hauteur. Impossible de placer le personnage dessus, il ne veut bien se déplacer que sur quelque chose qui se trouve a la même hauteur que lui.

Comment faire pour résoudre mes deux problèmes ?
Merci à vous !

Salut !
Le coté "cranté" vient surement du fait que tu appliques le Vector3.MoveTowards que lorsque Input.GetMouseButtonDown(0) est à True, donc à chaque clique. (au lieu de chaque frame)

A mon avis tu devrais revoir ta manière de procéder.
Tu commences par faire du Raycast, puis un test de clique puis un déplacement. Essaye de mieux séparer les choses en ayant d’un coté la récupération des inputs (action du joueur) et de l’autre son application (le mouvement).

Essaye quelque chose comme ça :

  • Input.GetMouseButtonDown(0) pour détecter le clique.
  • Si l’utilisateur a cliqué, on fait un raycast. (on évite le spam, on a bien un raycast pour un clique)
  • Si ton raycast est bon, stocke les coordonnées finale et fait le déplacement en dehors de ce test d’input.
+3 -0

Ça fonctionne super bien merci ! Voici ce que j’ai fait :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{

    public float rotateSpeed = 20f;
    public float walkSpeed = 0.5f;

    private Vector3 targetPosition;
    private bool isMoving;


    void Update ()
    {
        if (Input.GetMouseButtonDown(0))
        {
            isMoving = true;
            SetTargetPosition();
        }

        if (isMoving)
            MovePlayer();
    }

    private void MovePlayer ()
    {
        Quaternion targetRotation = Quaternion.LookRotation(targetPosition - transform.position);

        transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotateSpeed * Time.deltaTime);
        transform.position = Vector3.MoveTowards(transform.position, targetPosition, walkSpeed * Time.deltaTime);

        if (transform.position == targetPosition)
            isMoving = false;
    }

    private void SetTargetPosition ()
    {
        Plane playerPlane = new Plane(Vector3.up, transform.position);
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        float hitdist = 0.0f;

        if (playerPlane.Raycast(ray, out hitdist))
            targetPosition = ray.GetPoint(hitdist);
    }
}

J’ai une question, la doc de la méthode Plane.Raycast() me dit que ça me donne dans la variable donnée en argument la distance le long du ray, où il intersecte avec le plan. La distance par rapport à quoi ? Il me faut deux points, l’un est le point formé par l’intersection entre le plan et la droite mais quel est l’autre ?

Merci pour ton aide ! :)

Ah c’est presque parfait !
Fait juste attention au isMoving = true; (ligne 17), tu le fais un poil trop tôt. Tu devrais le mettre à coté de l’assignation de la targetPosition (ligne 43). Comme ça il passe à True que si le Raycast fonctionne. ;)

Sinon pour répondre à ta question, je dirais que c’est tout simplement la distance entre ray.origin et le point de collision / d’intersection. (dans ton cas ray.origin correspond à ta camera)


Ah et maintenant qu’on parle de Raycast, ça me fait penser à ton autre problème de "hauteur".
Avec un Plane.Raycast tu ne récupéras que les collisions avec ton plan et rien d’autre.

Tu devrais jeter un oeil au Physics.Raycast, ça te permettra d’utiliser ton ray sur tout ce qui possède un collider (donc ton sol mais pas que).

Pour éviter de collide avec tout et n’importe quoi regarde du coté des layers.


Bon courage pour la suite. :P

+2 -0

Merci beaucoup pour tes conseils, je vais regarder du côté de Physics.Raycast du coup. Mais c’est là où j’ai du mal avec Unity, c’est qu’il y a plein de façon de faire quelque chose… Par exemple rien que pour bouger un personnage, on peut soit modifier directement le transform.position ou alors appliquer une force au Rigidbody, de même pour le Raucast du coup, on peut passer par Plane.Raycast ou Physics.Raycast…
C’est un peu déstabilisant pour un debutant. ;)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte