OnTriggerEnter2D() 多次触发 TakeDamage()

问题描述 投票:0回答:1

我正在尝试使用 Network For Gameobjects 创建多人游戏 在主机上我只造成一次伤害,而在客户端我每次命中造成大约 3-5 次伤害。 这是我的 enemyStats 脚本:

public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();
        singleton = this;
        health.Value = enemyData.HP;
        damage.Value = enemyData.Damage;

        // event
        MeleeCollision.onDamaged += TakeDamageServerRpc;

        health.OnValueChanged += (int previousHealth, int newHealth) =>
        {
            health.Value = newHealth;
        };
    }

    public override void OnNetworkDespawn()
    {
        base.OnNetworkDespawn();

        // event
        MeleeCollision.onDamaged -= TakeDamageServerRpc;
    }

    private void TakeDamage(int damageAmount)
    {
        health.Value -= damageAmount;
        Debug.Log("enemystats message: hit");
    }

    [ServerRpc]
    private void TakeDamageServerRpc(int damageAmount)
    {
        TakeDamage(damageAmount);
    }

和混战Cillision脚本:

public static Action<int> onDamaged;

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Enemy"))
        {
            onDamaged?.Invoke(PlayerStats.singleton.damage.Value);
            Debug.Log("MeleeCollision message: hit");
        }
    }

有什么解决办法吗?

我试图在 onTrigger 函数中添加布尔状态,但这没有用

附言我发现问题是客户端每次点击实例化了大约 5 个斜杠预制件。这是负责此的代码:

[Header("Attack")]
    [SerializeField] private GameObject slashPrefab;
    [SerializeField] private Transform spawnPoint;
    [SerializeField] private float attackDelay = 0.5f;
    private NetworkVariable<bool> isAttacked = new NetworkVariable<bool>(false);
    private Quaternion fixRotation = Quaternion.Euler(90, 0, 0);


    public override void OnNetworkSpawn()
    {
        base.OnNetworkSpawn();
        isAttacked.OnValueChanged += (bool previousValue, bool newValue) =>
        {
            isAttacked.Value = newValue;
            Debug.Log(isAttacked.Value);
        };
    }

    private void Update()
    {
        if (!IsOwner) return;
        if (Input.GetMouseButton(0) && !isAttacked.Value) AttackServerRpc(spawnPoint.position, spawnPoint.rotation, attackDelay);
    }

    private IEnumerator Attack(Vector3 position, Quaternion rotation, float delay)
    {
        isAttacked.Value = true;
        var prefab = Instantiate(slashPrefab, position, rotation * fixRotation);
        prefab.GetComponent<NetworkObject>().Spawn(true);
        yield return new WaitForSeconds(delay);
        isAttacked.Value = false;
    }

    [ServerRpc]
    private void AttackServerRpc(Vector3 position, Quaternion rotation, float delay)
    {
        StartCoroutine(Attack(position, rotation, delay));
    }
unity3d multiplayer
1个回答
0
投票

@derHugo 在他的评论中是正确的。我认为同一个碰撞被处理了多次。我添加了 float damageCooldown 来存储冷却时间,并添加了一个字典来存储每个敌人的最后一次碰撞时间。

试试看它是否能解决您的问题

public class MeleeCollision : MonoBehaviour
{
    public static Action<int> onDamaged;

    
    public float damageCooldown = 0.5f;
    private Dictionary<GameObject, float> lastHitTime;

    private void Awake()
    {
        lastHitTime = new Dictionary<GameObject, float>();
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Enemy"))
        {
            if (!lastHitTime.ContainsKey(other.gameObject) || Time.time - lastHitTime[other.gameObject] > damageCooldown)
            {
                onDamaged?.Invoke(PlayerStats.singleton.damage.Value);
                lastHitTime[other.gameObject] = Time.time;
                Debug.Log("MeleeCollision message: hit");
            }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.