Trigger wykonuje się czasem, a czasem nie

Ogólne pytania na temat Unity3D

Trigger wykonuje się czasem, a czasem nie

Postprzez Owczarek » 26 Lip 2019, 07:45

Piszę grę o kocie, który atakuje szczura.Kot ma dodany collider i trigger, który jest wyłączony, a włączany jest tylko na jedną klatkę gdy kot zaczyna atakować.Szczur ma również collider.Oba mają skrypty i rigidbody.OnTriggerEnter (zadawanie obrażeń, wykrywanie kolizji) nie zawsze działa.Animacja ataku się wykonuje ale metoda nie wykrywa żadnej kolizji.Czasem działa czasem nie, nie mam pojęcia dlaczego.
To skrypt kota:
Kod: Zaznacz wszystko
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class KittyScript : MonoBehaviour
{
    public BoxCollider trigger;

    private float moveVertical;
    private float moveHorizontal;
    private Animator anim;
    public float attackwait=0;
    private bool attack=false;

    // Start is called before the first frame update
    void Start()
    {
        anim = GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        attack = false;
        transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
        moveVertical = Input.GetAxis("Vertical");
        moveHorizontal = Input.GetAxis("Horizontal");
        anim.SetFloat("MoveVertical", moveVertical);
        anim.SetFloat("MoveHorizontal", moveHorizontal);
        trigger.enabled = false;
        if (moveVertical > 0 && Input.GetKey(KeyCode.LeftShift)) //run
        {
            anim.SetBool("Run", true);
            transform.Translate(new Vector3(0, 0, 3) * Time.deltaTime);
            if (Input.GetKeyDown(KeyCode.Space)) //jump
            {
                anim.SetTrigger("Jump");
            }
        }
        else if(moveVertical>0) //walk
        {
            transform.Translate(new Vector3(0, 0, 1) * Time.deltaTime);
            anim.SetBool("Run", false);
        }
        else if(moveVertical<0) //walk back
        {
            transform.Translate(new Vector3(0, 0, -1) * Time.deltaTime);
            anim.SetBool("Run", false);
        }
        else
        {
            anim.SetBool("Run", false);
        }
        if (moveHorizontal>0) //turn right
        {
            transform.Rotate(new Vector3(0, 70, 0) * Time.deltaTime);
        }
        else if(moveHorizontal<0)//turn left
        {
            transform.Rotate(new Vector3(0, -70, 0) * Time.deltaTime);
        }
        if (attackwait <= 0) //wait for attack
        {
            if(attackwait<0)
            {
                attackwait = 0;
            }

            if (Input.GetMouseButtonDown(0))
            {
                anim.SetTrigger("Attack");
                trigger.enabled = true;
                attack = true;
                attackwait = 1; //wait 1 sec after attack
               
            }
           
        }
        else
        {
 
            attackwait = attackwait - (1 * Time.deltaTime);
        }
       
       
    }

    private void OnTriggerEnter(Collider other)
    {
        Debug.Log("Trigger");
        if (other.CompareTag("Rat") && attack == true)
        {
            other.gameObject.GetComponent<Health>().health = other.gameObject.GetComponent<Health>().health - 5;
            Debug.Log("I did damage");
        }
       
    }

}
Owczarek
 
Posty: 2
Rejestracja: 26 Lip 2019, 07:32
Has thanked: 0 time
Been thanked: 0 time

Re: Trigger wykonuje się czasem, a czasem nie

Postprzez Hostur » 26 Lip 2019, 08:25

No jeśli nie zdąży w tej samej klatce się wywołać trigger to nie zadziała.
Nie znam zawiłości Twojej gry ale czy trigger.enabled = false; nie może zostać przeniesiony na koniec ataku tzn wywołany z OnTriggerEnter?

Edit:
Nie uważasz tego za nazbyt przekombinowane?
Czy musisz wyłączać trigger? Przecież sam trigger może sprawdzać warunki co już robisz sprawdzając czy występuje atak.
Dodałbym jako dziecko obiekt z triggerem (delikatnie większym niż collider) tak aby mogły oba działać cały czas
Hostur
 
Posty: 726
Rejestracja: 05 Sie 2015, 07:36
Has thanked: 0 time
Been thanked: 0 time

Re: Trigger wykonuje się czasem, a czasem nie

Postprzez Owczarek » 26 Lip 2019, 08:48

Hostur napisał(a):No jeśli nie zdąży w tej samej klatce się wywołać trigger to nie zadziała.
Nie znam zawiłości Twojej gry ale czy trigger.enabled = false; nie może zostać przeniesiony na koniec ataku tzn wywołany z OnTriggerEnter?

Edit:
Nie uważasz tego za nazbyt przekombinowane?
Czy musisz wyłączać trigger? Przecież sam trigger może sprawdzać warunki co już robisz sprawdzając czy występuje atak.
Dodałbym jako dziecko obiekt z triggerem (delikatnie większym niż collider) tak aby mogły oba działać cały czas

Zmieniłam jednak nadal tak jest.Tzn zaznaczyłam, żeby cały czas działał trigger.Czy to pokazuje "problemy" silnika czy ze mną coś jest nie tak?
Już działa! Dziękuje!
Ale według mnie to nie logiczne, że nie zdąża się wykonać funkcja...
Owczarek
 
Posty: 2
Rejestracja: 26 Lip 2019, 07:32
Has thanked: 0 time
Been thanked: 0 time

Re: Trigger wykonuje się czasem, a czasem nie

Postprzez Hostur » 26 Lip 2019, 11:12

Logiczne, musi wystąpić trigger w tej samej klatce jeśli wystąpił w kolejnej to nie doszedł do skutku bo już update go wyłączał więc to mogło zadziałać tylko w określonej sytuacji w której atak nastąpił w tej samej klatce co wejście w trigger jako że jak mi wiadomo triggery sprawdzane są w fixed update to trigger musiał zostać złapany w którymś fixupdacie wykonanym pomiędzy włączeniem triggera a rozpoczęciem kolejnej klatki na co szansa jest mała. Działało by inaczej z użyciem OnTriggerStay ale nie polecam jest to bardzo niewydajne
Hostur
 
Posty: 726
Rejestracja: 05 Sie 2015, 07:36
Has thanked: 0 time
Been thanked: 0 time

Re: Trigger wykonuje się czasem, a czasem nie

Postprzez patrykas1000 » 01 Sie 2019, 15:37

https://docs.unity3d.com/Manual/ExecutionOrder.html

Silnik fizyki działa przed twoimi skryptami.
Każda klatka: ... -> OnTriggerEnter -> ... -> Update -> ...
Co sprawia że włączenie kolizji będzie miało efekt najwcześniej w następnej klatce.

Ponad to kolizje (czyli między innymi OnTriggerEnter) są wykonywane jako fizyka co sprawia że jeżeli gra działa z dużą ilością FPS to nie w każdej klatce są wykonywane obliczenia fizyki i w drugą stronę - jeżeli gra chodzi z mniejszą ilością FPS to może się okazać że na jeden Update przypadnie kilka FixedUpdate (tym samym OnTriggerStay) - krytyczna sytuacja to ta w której na jeden Update wypadło OnTriggerEnter i OnTriggerExit.

Jak już o kolejności wykonywania to jeszcze jedna rada. Destroy (z delay=0) działa dopiero przed kolejnym wywołaniem Update. Co oznacza że w klatce w której wywołujesz Destroy (nawet jeżeli Destroy będzie pierwszą rzeczą w twoim kodzie) to i tak do końca jej trwania ten obiekt będzie istnieć i prawidłowo działać. Przestaje istnień dopiero w następnej klatce.
patrykas1000
 
Posty: 344
Rejestracja: 16 Sie 2013, 21:35
Has thanked: 0 time
Been thanked: 0 time


Wróć do Wsparcie Unity

Kto jest na forum

Użytkownicy przeglądający to forum: Brak zarejestrowanych użytkowników oraz 2 gości