3
votes

La vitesse du corps rigide est parfois nulle lorsque le corps rigide est en mouvement

J'essaye d'ajouter du son à mon objet poussable et j'ai juste une simple instruction if pour vérifier si l'objet poussable bouge. Le concept est assez simple, si l'objet bouge, le son doit jouer et quand il ne bouge pas, il ne doit pas. Le problème est cependant que lorsque je débogue la valeur, il y a un 0 toutes les 5 images environ. Cela fait que le son fonctionne de manière incohérente. Le script que j'ai est vraiment simple, et j'ai essayé de passer à fixedupdate, mais cela n'a pas fonctionné. J'avais lu quelque part que les calculs physiques sont effectués dans fixedUpdate.

public class PushableObject : MonoBehaviour
{
    Rigidbody rb;
    AudioSource audioS;

    bool rbIsMoving = false;

    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        audioS = GetComponent<AudioSource>();
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        if (rb.velocity == Vector3.zero)
        {
            Debug.Log("Not moving");
            audioS.volume = 0f;
        }
        else
        {
            Debug.Log("Moving");
            audioS.volume = 0.1f;
        }
    }
}

Edit: Je viens de comprendre que si le joueur pousse l'objet poussable dans le mur, le son continue de jouer, pour cette raison Je pense que je dois aussi changer la manière de déterminer si l'objet bouge ou non.


0 commentaires

3 Réponses :


2
votes

Vous pouvez vérifier si le RigidBody est en veille:

Vector3 lastposition;
Gameobject go = somegameobject; 

function Update()
{
    if (lastposition == go.transform.position)
    {
     //not moving
    }
    else
    {
     //moving
    }
    lastposition = go.transform.position;
}

Ou vérifier si la position de la transformation a bougé depuis la dernière image:

if (!rb.IsSleeping()
{
//it's moving
}
else
{
//it's not
}

p >


5 commentaires

Ha, je ne le savais pas, mais ça enregistre quand même quand le joueur entre en collision. Dans mon jeu, le joueur doit appuyer sur un bouton pour appuyer, donc cela ne fonctionne pas encore.


Vous pouvez également stocker les coordonnées de la transformation dans des variables et vérifier si elles changent dans Update / FixedUpdate. S'ils sont identiques à la dernière image, l'objet ne bouge pas, sinon il bouge.


J'ai actuellement légèrement modifié l'instruction if pour vérifier également si le joueur maintient le bouton poussoir. Quand je pousse l'objet dans un mur, l'objet poussable ne bouge pas mais le son est toujours joueur, je pense que c'est parce que je maintiens le bouton poussoir et parce que le corps rigide ne dort plus. Comment vérifier si la position a changé comme dans votre commentaire?


J'ai mis à jour ma réponse avec une comparaison de position.


Les deux réponses concernent la même technique maintenant, merci pour les informations utiles!



3
votes

Cela se produit en raison de virgule flottante simple précision .

Vous ne devez jamais (ne devriez) comparer directement deux valeurs float car elles peuvent logiquement être égales (par exemple 1 = 5 * 0.2 ) mais pour l'ordinateur, elles peuvent être différentes d'un petit "epsilon"

Unity décide donc que Vector3 utilise simplement une précision de 0,00001 pour l'égalité pour ==


Utilisez plutôt Mathf.Approximately qui utilise un très petit Epsilon à la place.


Plus facile que de comparer chaque composant du code rb.velocity > contre 0 cod e> ce que vous voulez réellement, c'est rb.velocity.magnitude qui est en fait la vitesse globale.

if(lastPosition == transform.position)

Mettre à jour

Vous pouvez également stocker la dernière position et comparez-le à l'actuel en utilisant Vector3.Distance soit à nouveau avec Mathf.Environ

if(Vector3.Distance(lastPosition, transform.position) <= someThreshold)

Ou avec un seuil personnalisé

private Vector3 lastPosition;

private void LateUpdate()
{
    if(Mathf.Approximately(Vector3.Distance(lastPosition, transform.position), 0))
    {
        //...
    }
    else
    {
        //...
        lastPosition = transform.positiom;
    }
}

ou cette fois, vous pouvez réellement utiliser == si un seuil de 0,00001 est ce que vous voulez

if (Mathf.Approximately(rb.velocity.magnitude, 0))


8 commentaires

Pour une raison quelconque, le bégaiement du son se produit toujours, mais j'ai l'idée derrière cela. Est-il possible de changer la gamme? c'est-à-dire quelque chose comme entre -0,1 et 0,1?


Voir ma mise à jour pour comparer à la dernière position à la place. Là, vous pouvez ajouter un seuil


Merci pour l'explication approfondie, mais pour une raison quelconque, le bégaiement sonore persiste. C'est bizarre comme si la position était vérifiée plusieurs fois par image ou quelque chose comme ça.


Vous pouvez essayer de l'utiliser à la place dans LateUpdate . De cette façon, il serait assuré que cela est toujours fait après que toutes les interactions physiques et utilisateur sont déjà terminées


Je viens d'essayer d'utiliser LateUpdate, mais malheureusement sans aucun succès. Ce qui est étrange, c'est que pendant que l'objet poussable est en mouvement, il revient toujours de temps en temps comme s'il ne bougeait pas. c'est-à-dire que lastPosition et currentPosition sont identiques. Serait-il possible de faire quelque chose comme quand les lastPos et currentPos sont les mêmes pour x images alors que le volume devrait être 0?


bien sûr que vous pouvez le faire en ayant simplement un compteur int privé et en le comptant sans bouger. Mais il est difficile de dire exactement ce qui ne fonctionne pas correctement là-bas sans avoir votre projet. On dirait que le problème d'origine vient du fait que l'objet a été déplacé vers une position "invalide" et "sautant" d'un collisionneur. Vous devriez plutôt essayer d'éviter que cela bouge complètement si cela entraînerait une position invalide


Ouais, je peux imaginer, pour être honnête, il ne se passe pas grand-chose de spécial jusqu'ici. C'est juste un cube avec un corps rigide, mais je pense savoir quel est le problème. Le lecteur est basé sur characterController et n'utilise pas de corps rigide. Je pense que pour cette raison, la poussée fonctionne un peu instable. Comment fonctionnerait quelque chose avec le compteur int? Je n'ai pas encore utilisé quelque chose comme ça.


Après quelques essais, j'ai trouvé quelque chose: le script fonctionne correctement, mais comme l'objet poussable se déplace si lentement, il est parfois immobile comme un cadre si cela a du sens.



0
votes

Vous pouvez utiliser Transform.hasChanged pour vérifier si la position du joueur a modifié lors de la dernière mise à jour

        if (!this.transform.hasChanged)
        {
            print("Player is not moving");
        }
        transform.hasChanged = false;


0 commentaires