C# UnityEvent birden fazla tetikleniyor

706111

Hectopat
Katılım
28 Ağustos 2023
Mesajlar
6.020
Makaleler
1
Çözümler
29
Arkadaşlar merhaba.

Unity3D'de Event Sistemi yaptım. Kodlarım böyle;

C#:
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;

public class FishManager : MonoBehaviour
{


    // Instance
    public static FishManager Instance;

    // Fish List
    [SerializeField] List<GameObject> fishes;
    [SerializeField] int activeFish;

    // FishPool
    public Queue<GameObject> fishPool = new Queue<GameObject>();
    [SerializeField] public int poolSize;


    // RayCast
    RaycastHit2D hit;
    [SerializeField] Camera cam;



    // Action List Fish

    [System.Serializable] public class FishTriggerEvent: UnityEvent<GameObject>{}

    public FishTriggerEvent fishTriggerEvent;






    System.Random rand = new System.Random();
    GameObject fish;
    int random = 0;





    public void FillPool()
    {


        for (int i = 0; i < poolSize; i++)
        {
            random = rand.Next(0, fishes.Count);
            fish = Instantiate(fishes[random]);
            fish.SetActive(false);

            fishPool.Enqueue(fish);
        }

        for (int i = 0; i < activeFish; i++)
        {
            SpawnFish();
        }
    }


    public void SpawnFish()
    {

        if (fishPool.Count <= 0)
        {
            random = rand.Next(0, fishes.Count);
            fish = Instantiate(fishes[random]);
            fish.SetActive(false);
            fishPool.Enqueue(fish);
        }

        fish = fishPool.Dequeue();

        fish.SetActive(true);


    }



    private void Awake()
    {
        if (!Instance)
        {
            Instance = this;
        
        
            FillPool();
        }
        else
        {
            Destroy(gameObject);
        }
    }



    //
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Click();
        }
    }


    public void Click()
    {
        hit = Physics2D.Raycast(cam.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
        if (hit.collider)
        {
      
            TapFish(hit.collider.gameObject);

        }
    }

 
    bool oneTime = false;
    public void TapFish(GameObject go)
    {

        fishTriggerEvent?.Invoke(go);
        SpawnFish();
    }
}


C#:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using TMPro;
using UnityEngine.Events;


public class FishMove : MonoBehaviour
{


 

    // Screen Cam Location;
    float x = 0f;
    float y = 0f;

    // Finish;
    Vector2 finish;

    // GameObject Fish
    [SerializeField] GameObject fish;


    // Fish Speed;
    [SerializeField] float speed;

    // Fish point;
    [SerializeField] GameObject pointObject;
    [SerializeField] TextMeshPro pointText;
    [SerializeField] int point;

    // Score Pos;
    Vector2 scorePos;

    // Move Point or Fish
    bool pointMove = false;
    bool isPointAdd = false;


    // Particle System

    [SerializeField] ParticleSystem bubbleEffect;



    public void Start()
    {
    
        FishManager.Instance.fishTriggerEvent.AddListener(GetPoint);

        x = ScreenManager.instace.x / 2;
        y = ScreenManager.instace.y / 2;

        pointText.text = $"{point}";
        pointObject.SetActive(false);

        scorePos = PointManager.Instance.scoreObject.transform.position;


        Init();




    }


 


 

    void GetPoint(GameObject go)
    {
        if (fish == go)
        {
            Debug.Log("Çalışt");
            pointObject.SetActive(true);
            pointObject.transform.position = fish.transform.position;
            pointText.text = $"{point}";
            fish.SetActive(false);
            bubbleEffect.transform.position = fish.transform.position;
            bubbleEffect.Play();



            pointMove = true;






        }
    }









    void Update()
    {


        if (pointMove)
        {
            MovePoint();

        }
        else
        {
            MoveFish();
        }





    }


    void MoveFish()
    {
        if ((finish - (Vector2)fish.transform.position).sqrMagnitude != 0f)
        {

            fish.transform.position = Vector2.MoveTowards(fish.transform.position,
                                            finish, speed * Time.deltaTime);




        }
        else
        {

            FishManager.Instance.SpawnFish();
            ReturnPool();

        }
    }



    void MovePoint()
    {
        if ((scorePos - (Vector2)pointObject.transform.position).sqrMagnitude != 0f)
        {

            pointObject.transform.position = Vector2.MoveTowards(pointObject.transform.position,
                                            scorePos, 7f * Time.deltaTime);




        }
        else
        {

      

            if (!bubbleEffect.isPlaying)
            {
          
                ReturnPool();
            }

            if (!isPointAdd)
            {
                PointManager.Instance.addPoint(point);
                pointText.text = "";
                isPointAdd = true;
            }



        }
    }



    void ReturnPool()
    {

        FishManager.Instance.fishPool.Enqueue(gameObject);
        Init();
        gameObject.SetActive(false);
    }



    public void Init()
    {





        //Point
        pointObject.SetActive(false);
        pointMove = false;
        isPointAdd = false;
  


        // Fish Area
        fish.SetActive(true);

        fish.transform.localScale = new Vector3(1, 1, 1);

        if (UnityEngine.Random.Range(0, 2) == 0)
        {

            fish.transform.position = new Vector2(-x - 1f, UnityEngine.Random.Range(y, -y));

            finish = new Vector2(x + 1f, UnityEngine.Random.Range(y, -y));

        }
        else
        {
            fish.transform.position = new Vector2(x + 1f, UnityEngine.Random.Range(y, -y));
            finish = new Vector2(-x - 1f, UnityEngine.Random.Range(y, -y));
            fish.transform.localScale = new Vector3(-1, 1, 1);
        }




    }




}


Sorunum şu.

Şimdi diyelim balık nesnesinde BoxCollider2D var. FishManager'daki if ile fare dinlemesi olayı gerçekleştiği zaman, FishMove içindeki GetPoint metodu 3-4 kere tetikleniyor yani.

1 kere tetiklenmesi lazım ama olmuyor.

Nedeni anlamadım yani. Input.GetMousePositon(0) şartı, 3-4 kere mi tetikletiyor. Fazla fazla puan veriyor.
 
Son düzenleme:
Kodunuzu göz ucuyla inceledim. Sorun büyük ihtimalle update() içinde fare tıklama kontrolü ile ilgili.

Input.GetMouseButtonDown(0)
ile fare tıklaması algılandığında, o karede birden fazla kez balığın TapFish metodu çağrılıyor olabilir, çünkü Update()her karede çalışır ve çok hızlı bir şekilde birden fazla kez tıklama algılanıyor olabilir. Bu da GetPoint metodunun 3-4 kez tetiklenmesine yol açıyor.

Çözüm için zamanlama kontrolü eklemeyi dene. Yapamazsan yardımcı olmaya çalışırım.
 
Kodunuzu göz ucuyla inceledim. Sorun büyük ihtimalle update() içinde fare tıklama kontrolü ile ilgili.

Input.GetMouseButtonDown(0)
ile fare tıklaması algılandığında, o karede birden fazla kez balığın TapFish metodu çağrılıyor olabilir, çünkü Update()her karede çalışır ve çok hızlı bir şekilde birden fazla kez tıklama algılanıyor olabilir. Bu da GetPoint metodunun 3-4 kez tetiklenmesine yol açıyor.

Çözüm için zamanlama kontrolü eklemeyi dene. Yapamazsan yardımcı olmaya çalışırım.
Tam olarak o nedir hocam? Yapayım hemen.
 
Kod:
bool isTapped = false;
float tapCooldown = 0.2f; // burada süreyi siz belirleyin isterseniz
float tapCooldownTimer = 0f;

void Update()
{
    tapCooldownTimer -= Time.deltaTime; // süreyi korusun

    if (Input.GetMouseButtonDown(0) && tapCooldownTimer <= 0f)
    {
        Click();
        tapCooldownTimer = tapCooldown; // süreyi resetlesin
    }
}

public void TapFish(GameObject go)
{
    if (isTapped) return;

    isTapped = true; // ilk seferde true yap
    fishTriggerEvent?.Invoke(go); // balığı tetikle
    SpawnFish(); // yeni balık yap
}

Kod:
bool isTapped = false;
float tapCooldown = 0.2f; // burada süreyi siz belirleyin isterseniz
float tapCooldownTimer = 0f;

void Update()
{
    tapCooldownTimer -= Time.deltaTime; // süreyi korusun

    if (Input.GetMouseButtonDown(0) && tapCooldownTimer <= 0f)
    {
        Click();
        tapCooldownTimer = tapCooldown; // süreyi resetlesin
    }
}

public void TapFish(GameObject go)
{
    if (isTapped) return;

    isTapped = true; // ilk seferde true yap
    fishTriggerEvent?.Invoke(go); // balığı tetikle
    SpawnFish(); // yeni balık yap
}
Bunu direkt en sona eklemeniz sorun oluşturmuyordu sanırım. Unity de metot sırası önemli değildi diye hatırlıyorum.
 
Son düzenleme:
Kod:
bool isTapped = false;
float tapCooldown = 0.2f; // burada süreyi siz belirleyin isterseniz
float tapCooldownTimer = 0f;

void Update()
{
    tapCooldownTimer -= Time.deltaTime; // süreyi korusun

    if (Input.GetMouseButtonDown(0) && tapCooldownTimer <= 0f)
    {
        Click();
        tapCooldownTimer = tapCooldown; // süreyi resetlesin
    }
}

public void TapFish(GameObject go)
{
    if (isTapped) return;

    isTapped = true; // ilk seferde true yap
    fishTriggerEvent?.Invoke(go); // balığı tetikle
    SpawnFish(); // yeni balık yap
}


Bunu direkt en sona eklemeniz sorun oluşturmuyordu sanırım. Unity de metot sırası önemli değildi diye hatırlıyorum.
Hocam if(is trapped) return; satırını kaldırmayınca tetiklenme olmuyor. Onu yorum satırına alınca yine çokça tetikleniyor.
 
O zaman if (isTapped) return balık tıklandıktan sonra bir daha tıklanmayı engelliyor. Tıklama sonrasında isTapped durumunu sıfırlamadığın için bu kontrol sürekli balık tıklandı kalıyor.

Balık tıklandığında durum isTapped = true. Balığın puan kazanma işlemi tamamlandıktan sonra tekrar false yapalım bu değişkeni.
Kod:
bool isTapped = false;
float tapCooldown = 0.2f;
float tapCooldownTimer = 0f;

void Update()
{
    tapCooldownTimer -= Time.deltaTime;

    if (Input.GetMouseButtonDown(0) && tapCooldownTimer <= 0f)
    {
        Click();
        tapCooldownTimer = tapCooldown;
    }
}

public void TapFish(GameObject go)
{
    if (isTapped) return;

    isTapped = true;
    fishTriggerEvent?.Invoke(go);
    SpawnFish();
}

void MovePoint()
{
    if ((scorePos - (Vector2)pointObject.transform.position).sqrMagnitude != 0f)
    {
        pointObject.transform.position = Vector2.MoveTowards(pointObject.transform.position, scorePos, 7f * Time.deltaTime);
    }
    else
    {
        if (!bubbleEffect.isPlaying)
        {
            ReturnPool();
        }

        if (!isPointAdd)
        {
            PointManager.Instance.addPoint(point);
            pointText.text = "";
            isPointAdd = true;
            isTapped = false;
        }
    }
}

Kafanızın karışmaması için açıklamaları sildim.

Az önceki kodu silip yerine bunu koyun.
 

Technopat Haberler

Geri
Yukarı