当 Unity 中的生命被移除时,游戏会冻结 [重复]

Posted

技术标签:

【中文标题】当 Unity 中的生命被移除时,游戏会冻结 [重复]【英文标题】:Game Freezes When Ever Lives Get Removed In Unity [duplicate] 【发布时间】:2021-11-15 04:06:25 【问题描述】:

每当我的游戏中的敌人在团结中夺走生命时,游戏就会暂时冻结。我认为这与“Thread.Sleep(3000);”行有关但我不确定是否有一个不会暂时冻结整个游戏的替代等待。 如果您能帮助我,我将不胜感激!

谢谢。

using System.Collections;
using System.Collections.Generic;
using System;
using System.Threading;
using UnityEngine;

public class Enemy : MonoBehaviour


    public Transform attackPoint;
    public float attackrange = 0.5f;
    public LayerMask playerlayers;
    public float speed = 3f;
    private Transform target;

    bool hitID = false;


    private void Update()
    
        if (target != null)
        
            float step = speed * Time.deltaTime;
            transform.position = Vector2.MoveTowards(transform.position, target.position, step);
            Collider2D[] hitplayers = Physics2D.OverlapCircleAll(attackPoint.position, attackrange, playerlayers);
            foreach (Collider2D player in hitplayers)
            
                if (hitID == false)
                
                    hitID = true;
                    player.GetComponent<HeartSystem>().TakeDamage(1);
                    Thread.Sleep(3000);
                    hitID = false;
                

            
                    
        
    


    private void OnTriggerEnter2D(Collider2D other)
    
        if (other.gameObject.tag == "Player")
        
            target = other.transform;


        
    

    private void OnTriggerExit2D(Collider2D other)
    

        if (other.gameObject.tag == "Player")
        
            target = null;

        
    

    void OnDrawGizmosSelected()
    
        if (attackPoint == null)
            return;

        Gizmos.DrawWireSphere(attackPoint.position, attackrange);
    

【问题讨论】:

【参考方案1】:

Enemy.cs

using System.Collections;
using UnityEngine;

public class Enemy : MonoBehaviour

    public Transform attackPoint;
    public float attackrange = 0.5f;
    public LayerMask playerlayers;
    public float speed = 3f;

    private Transform _target;
    private bool _hitID;

    private void Update()
    
        if (_target != null)
        
            var step = speed * Time.deltaTime;
            transform.position = Vector2.MoveTowards(transform.position, _target.position, step);
            var hitPlayers = new Collider2D[10];
            Physics2D.OverlapCircleNonAlloc(attackPoint.position, attackrange, hitPlayers, playerlayers);
            foreach (var player in hitPlayers)
            
                if (_hitID == false)
                
                    StartCoroutine(HitCoroutine(player));
                
            
        
    

    private IEnumerator HitCoroutine(Collider2D player)
    
        _hitID = true;
        player.GetComponent<HeartSystem>().TakeDamage(1);
        yield return new WaitForSeconds(3);
        _hitID = false;
    

    private void OnTriggerEnter2D(Collider2D other)
    
        if (other.gameObject.CompareTag("Player"))
        
            _target = other.transform;
        
    

    private void OnTriggerExit2D(Collider2D other)
    
        if (other.gameObject.CompareTag("Player"))
        
            _target = null;
        
    

    private void OnDrawGizmosSelected()
    
        if (attackPoint == null)
            return;

        Gizmos.DrawWireSphere(attackPoint.position, attackrange);
    

试试这个。

在这种情况下,您想使用协程。

您可以在此处阅读有关协程的信息: https://docs.unity3d.com/Manual/Coroutines.html

【讨论】:

【参考方案2】:

Unity 是单线程的,因此您实际上是在暂停运行游戏的整个线程。由于帧是在这个线程上更新的,你甚至会冻结视觉帧更新。

您有几种方法可以管理游戏中的“等待”。

协程:

可以暂停的进程,直到满足以后的条件(包括时间)


void Update()

    //Your other code goes here
    if (hitID == false)
    
        hitID = true;
        player.GetComponent<HeartSystem>().TakeDamage(1);
        StartCoroutine(ResetHitIDAfterSeconds(3))
    


IEnumerator ResetHitIDAfterSeconds(float seconds) 

    yield return new WaitForSeconds(seconds);
    hitID = false;

上面的代码允许你有同样的逻辑,并且会启动一个协程,等待 3 秒再将 hitID 设置回 false。

时间.deltaTime:

您还可以在 Update 方法中跟踪经过的时间,并根据经过的时间主动管理变量。 Time.deltaTime 返回自上一帧以来经过的时间量。

public class ConstantRotation : MonoBehaviour

    public float timeElapsed = 0f;
    void Update()
    
        //Your other code goes here
        if (hitID == false)
        
            hitID = true;
            player.GetComponent<HeartSystem>().TakeDamage(1);
            timeElapsed = 0f;
        
        else 
        
            timeElapsed += Time.deltaTime
            if(timeElapsed >= 3.0f)
            
                hitId = false;
            
        
    

您可能希望稍微修改上述代码以避免在每一帧上运行逻辑,并且只在命中时运行它。

【讨论】:

以上是关于当 Unity 中的生命被移除时,游戏会冻结 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

四大域总结

JAVA 四大域对象总结

onactivitycreated啥时候执行

java-四大域对象总结

Java 四大作用域总结

JavaWeb之Servlet的生命周期