【问题标题】:(2D) Make a GameObject Shake using script in Unity(2D) 在 Unity 中使用脚本制作 GameObject Shake
【发布时间】:2020-12-10 20:59:42
【问题描述】:

当玩家进入危险区域(由对撞机触发)时,我有以下游戏对象(盒子)掉落,但我想要的是盒子在掉落前晃动半秒钟。我认为协程是实现这一点的最佳方式,并且我有让盒子掉落的代码,但我不确定如何让盒子在我的脚本中摇晃。

screenshot

这是我的代码,以防它有助于理解:

public class FallingBox : MonoBehaviour
{    
    [SerializeField] float fallSpeed = 3f;
    [SerializeField] Transform target;
    
    Rigidbody2D rigidbody;
    BoxCollider2D boxCollider;

    bool isFalling = false;
    

    void Start()
    {
        rigidbody = GetComponent<Rigidbody2D>();
        boxCollider = GetComponent<BoxCollider2D>();
    }


    void Update()
    {    
        var frameMovement = fallSpeed * Time.deltaTime;
        var targetPosition = target.transform.position;

        if (isFalling)
        {    
            transform.position = Vector2.MoveTowards(transform.position, targetPosition, frameMovement);

            if (transform.position == targetPosition)
            {    
                gameObject.layer = LayerMask.NameToLayer("Ground");
                boxCollider.enabled = true;    
            }    
        }
    }


    //Called when entering the "danger zone"
    public void ChangeStatus()
    {
        isFalling = true;    
    }

【问题讨论】:

    标签: c# unity3d game-physics


    【解决方案1】:

    我现在做了这段代码,我认为它可能会有所帮助:

         IEnumerator Tremble() {
               for ( int i = 0; i < 10; i++)
               {
                   transform.localPosition += new Vector3(5f, 0, 0);
                   yield return new WaitForSeconds(0.01f);
                   transform.localPosition -= new Vector3(5f, 0, 0);
                   yield return new WaitForSeconds(0.01f);
               }
         }
    

    这个想法是直接将localPosition非常快速地更改为不同的方向。检查它是否是您正在寻找的东西,或者您是否可以努力到达那里?

    【讨论】:

      【解决方案2】:

      也许是这样的?我留下了很多你正常的fall代码,只是协程它。

      这个想法是让一个正弦波驱动震动,所以它有点平滑。

      public class FallingBox : MonoBehaviour
      {
          [SerializeField] float fallSpeed = 3f;
          [SerializeField] Transform target;
          
          Rigidbody2D rigidbody;
          BoxCollider2D boxCollider;
      
          void Start()
          {
              rigidbody = GetComponent<Rigidbody2D>();
              boxCollider = GetComponent<BoxCollider2D>();
          }
      
          //Called when entering the "danger zone"
          public void ChangeStatus()
          {
              StartCoroutine(OnStartFall());
          }
      
          IEnumerator OnStartFall()
          {
              var maxTrembleTime = 0.25f;
              var currentTime = 0.0f;
      
              while(currentTime < maxTrembleTime)
              {
                  currentTime = Mathf.Clamp(currentTime + Time.deltaTime, 0, maxTrembleTime);
      
                  // sinOffset = 0 will have us back at the same point.
                  // You might want to scale this number by a constant to make it shake faster or slower
                  var sinOffset = (maxTrembleTime - currentTime); 
                                                      
                  var offset = Mathf.Sin(sinOffset); // Scale this offset to make it shake over more distance
                  transform.position.y += offset;
      
                  yield return null; // wait until next frame
              }
      
              // Begin normal falling code
      
              while(true)
              {
                  var frameMovement = fallSpeed * Time.deltaTime;
                  var targetPosition = target.transform.position;
                  transform.position = Vector2.MoveTowards(transform.position, targetPosition, frameMovement);
      
                  if (transform.position == targetPosition)
                  {
                      gameObject.layer = LayerMask.NameToLayer("Ground");
                      boxCollider.enabled = true;
                      break;
                  }
      
                  yield return null; // wait until next frame.
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        在大多数情况下,我不是协程的忠实拥护者,只要简单的逻辑就可以解决问题。

        这是一个仅使用 Box State 来确定盒子在任何给定时间应该做什么的示例:

        public enum BoxState
        {
            None,
            Shaking,
            Falling,
            Finished
        }
        
        public class FallingBox : MonoBehaviour
        {
            [SerializeField] float fallSpeed = 3f;
            [SerializeField] Transform target;
        
            [SerializeField] float shakeTime = 0.5f;
            [SerializeField] float shakeSpeed = 1f;
            [SerializeField] float shakeFactor = 0.1f;
        
            Rigidbody2D rigidbody;
            BoxCollider2D boxCollider;
        
            private Vector3 originalPosition;
            private Vector3 targetPosition;
            private float timer;
        
            public BoxState boxState { get; private set; } = BoxState.None;
        
            void Start ( )
            {
                rigidbody = GetComponent<Rigidbody2D> ( );
                boxCollider = GetComponent<BoxCollider2D> ( );
            }
        
        
            void Update ( )
            {
                switch ( boxState )
                {
                    case BoxState.None:
                    case BoxState.Finished:
                        return;
        
                    case BoxState.Shaking:
                        // Use Perlin Noise here for a quasi-random shake. Multiply or Add extra values for noise speed variations.
                        // Many different ways to produc these offset values. This is just one variation.
                        var xOffset = Mathf.PerlinNoise ( Time.time * shakeSpeed, 0 );
                        var yOffset = Mathf.PerlinNoise ( 0, Time.time * shakeSpeed );
        
                        transform.position = originalPosition + new Vector3 ( xOffset, yOffset, 0 ) * shakeFactor;
                        timer += Time.deltaTime;
                        if ( timer > shakeTime )
                        {
                            boxState = BoxState.Falling;
                            timer = 0;
                        }
                        break;
        
                    case BoxState.Falling:
                        transform.position = Vector2.MoveTowards ( transform.position, targetPosition, fallSpeed * Time.deltaTime );
                        if ( ( transform.position - targetPosition ).sqrMagnitude < Vector3.kEpsilon )
                        {
                            transform.position = targetPosition;
                            gameObject.layer = LayerMask.NameToLayer ( "Ground" );
                            boxCollider.enabled = true;
                            boxState = BoxState.Finished;
                        }
                        break;            
                }
            }
        
        
            //Called when entering the "danger zone"
            public void ChangeStatus ( )
            {
                if ( boxState == BoxState.None )
                {
                    boxState = BoxState.Shaking;
                    originalPosition = transform.position;
                    targetPosition = target.transform.position;
                    timer = 0;
                }
            }
        }
        

        我个人还发现这样的解决方案更容易更新。在这里添加额外的状态比创建和计时新的协程要容易得多。

        【讨论】:

          猜你喜欢
          • 2019-10-19
          • 1970-01-01
          • 1970-01-01
          • 2015-08-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-27
          • 1970-01-01
          相关资源
          最近更新 更多