[英](2D) Make a GameObject Shake using script in Unity
当玩家进入危险区域(由对撞机触发)时,我有以下游戏 Object(盒子)掉落,但我想要的是盒子在掉落前摇晃半秒钟。 我认为协程是实现这种情况的最佳方式,并且我有使盒子掉落的代码,但我不确定如何使盒子在我的脚本中摇晃。
这是我的代码,以防它有助于理解:
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;
}
也许是这样的? 我留下了很多你正常的秋季代码,只是协同它。
这个想法是让一个正弦波驱动震动,所以它有点平滑的震动。
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.
}
}
}
我现在做了这段代码,我认为它可能会有所帮助:
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非常快速地更改为不同的方向。 检查它是否是您正在寻找的东西,或者您是否可以努力到达那里
在大多数情况下,我不是协程的忠实拥护者,只要简单的逻辑就可以解决问题。
这是一个仅使用 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;
}
}
}
我个人也发现像这样的解决方案更容易更新。 在这里添加一个额外的 state 比创建和计时新的协程要容易得多。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.