与 FrostBullet 碰撞时随着时间的推移变慢
Slow over time on collision with a FrostBullet
我是 Unity 和 C# 的新手。我几周前开始玩这款 2D 游戏。
所以基本上我想做的是当玩家被“FrostBullet”击中时,它应该造成伤害并随着时间的推移减缓玩家的速度。在我的脚本中,玩家被 FrostBullet 击中,它造成伤害并且减速是恒定的,而不是随着时间的推移。
我希望它是这样的,当玩家被 FrostBullet 击中时,玩家应该被减速 2 秒,然后他的移动速度恢复正常。
我的代码是这样的:
public class FrostHit : MonoBehaviour
{
float maxS = 40f;
float slowSpeed = 20f;
public Rigidbody2D rb;
int damage = -5;
int timeOfReducedSpeed = 2;
bool isHit = false;
void Start()
{
rb.velocity = transform.right * slowSpeed;
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player_Njinja")
{
HealthNjinja healthNjinja = other.gameObject.GetComponent<HealthNjinja>();
healthNjinja.ModifyHealth(damage);
PlayerMovementNjinja reduceMoveSpeed = other.gameObject.GetComponent<PlayerMovementNjinja>();
reduceMoveSpeed.runSpeed = slowSpeed;
Destroy(gameObject);
}
PlayerMovementKnight maxSpeed = other.gameObject.GetComponent<PlayerMovementKnight>();
maxSpeed.runSpeed = maxS;
HealthKnight healthKnight = other.gameObject.GetComponent<HealthKnight>();
if (other.gameObject.tag == "Player_Knight")
{
isHit = true;
healthKnight.ModifyHealth(damage);
StartCoroutine(speedTime());
Destroy(gameObject);
}
IEnumerator speedTime()
{
while (isHit == true)
{
slowPlayer();
yield return new WaitForSeconds(timeOfReducedSpeed);
revertSpeed();
}
}
void slowPlayer()
{
maxSpeed.runSpeed = slowSpeed;
}
void revertSpeed()
{
maxSpeed.runSpeed = maxS;
}
}
}
还有我的 PlayerMovement 代码:
public class PlayerMovementKnight : MonoBehaviour
{
public CharacterController2D controller;
public Animator animator;
public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
bool crouch = false;
public WeaponKnight Bullet;
public bool grounded;
void Update()
{
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
animator.SetFloat("Speed", Mathf.Abs(horizontalMove));
if (Input.GetButtonDown("Jump"))
{
jump = true;
animator.SetBool("IsJumping", true);
}
if (Input.GetButtonDown("Crouch"))
{
crouch = true;
}
else if (Input.GetButtonUp("Crouch"))
{
crouch = false;
}
if (grounded && GetComponent<Bullet>().knockBack == false)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);
}
}
public void OnLanding()
{
animator.SetBool("IsJumping", false);
}
public void OnCrouching(bool isCrouching)
{
animator.SetBool("IsCrouching", isCrouching);
}
void FixedUpdate()
{
controller.Move(horizontalMove * Time.fixedDeltaTime, crouch, jump);
jump = false;
}
}
问题似乎是您的 bool isHit
在调用协程之前设置为 true
,但从未重置为 false
。
所以循环:
while (isHit == true)
{
slowPlayer();
yield return new WaitForSeconds(timeOfReducedSpeed);
revertSpeed();
}
真是死循环。
您可能想在某处将 bool 重置为 false。
编辑:
根据评论,我现在看到您的脚本已附加到子弹游戏对象。在启动协程并减慢播放器速度后,您 Destroy(gameObject);
之后,脚本也被销毁,协程因此停止......没有任何东西可以让玩家的速度恢复正常。
你应该把协程移动到玩家的脚本中,需要的时候启动它。这样子弹毁了它还存在
您的布尔值 isHit
从未设置为假。导致玩家被减速,然后在他被击中一次后永远重置。
一开始就不需要创建 isHit
。为什么只有当 Player_Knight
已经被击中时才需要在输入 IEnumerator
时检查玩家是否被击中。
代码示例:
public class FrostHit : MonoBehaviour
{
float maxS = 40f;
float slowSpeed = 20f;
public Rigidbody2D rb;
int damage = -5;
int timeOfReducedSpeed = 2;
void Start()
{
rb.velocity = transform.right * slowSpeed;
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player_Njinja")
{
HealthNjinja healthNjinja = other.gameObject.GetComponent<HealthNjinja>();
healthNjinja.ModifyHealth(damage);
PlayerMovementNjinja mSpeedNinja = other.gameObject.GetComponent<PlayerMovementNjinja>();
StartCoroutine(speedTimeNinja());
}
else if (other.gameObject.tag == "Player_Knight")
{
HealthKnight healthKnight = other.gameObject.GetComponent<HealthKnight>();
healthKnight.ModifyHealth(damage);
PlayerMovementKnight mSpeedKnight = other.gameObject.GetComponent<PlayerMovementKnight>();
StartCoroutine(speedTimeKnight());
}
// Destroy Bullet
Destroy(gameObject);
}
IEnumerator speedTimeKnight()
{
mSpeedKnight.runSpeed = slowSpeed;
yield return new WaitForSeconds(timeOfReducedSpeed);
mSpeedKnight.runSpeed = maxS;
}
IEnumerator speedTimeNinja()
{
mSpeedNinja.runSpeed = slowSpeed;
yield return new WaitForSeconds(timeOfReducedSpeed);
mSpeedNinja.runSpeed = maxS;
}
}
我改变的地方和原因:
- 删除了 bool 和 while 循环,没有解决任何实际问题
- 从内部分离 IEnumerator 和 2 个函数
OnTriggerEnter2D()
- 在末尾添加了
Destroy(gameObject);
,因为子弹总是会被摧毁
- 删除了
maxSpeed.runSpeed = maxS;
,因为速度已经达到了 set/reset。没理由撞到子弹后重新设置速度
- 将
GetComponent
for Player_Knight
放入 else if 中,即使 Player_Njinja
被命中,也没有理由执行 GetComponent
。
- 删除了
reduceMoveSpeed.runSpeed = slowSpeed;
Player_Njinja
只会变慢并且永远不会恢复他的速度。而是再次使用 IEnumerator
- 添加了另一个 IEnumerator,以便
Player_Njinja
和 Player_Knight
都能正确减速和减速(现在甚至可以根据玩家被击中创建不同的减速时间)
- 去掉函数,一行代码写一个函数真的不值得。特别是当你可以在 IEnumerator 中设置它而不需要更多代码行时
我是 Unity 和 C# 的新手。我几周前开始玩这款 2D 游戏。
所以基本上我想做的是当玩家被“FrostBullet”击中时,它应该造成伤害并随着时间的推移减缓玩家的速度。在我的脚本中,玩家被 FrostBullet 击中,它造成伤害并且减速是恒定的,而不是随着时间的推移。 我希望它是这样的,当玩家被 FrostBullet 击中时,玩家应该被减速 2 秒,然后他的移动速度恢复正常。
我的代码是这样的:
public class FrostHit : MonoBehaviour
{
float maxS = 40f;
float slowSpeed = 20f;
public Rigidbody2D rb;
int damage = -5;
int timeOfReducedSpeed = 2;
bool isHit = false;
void Start()
{
rb.velocity = transform.right * slowSpeed;
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player_Njinja")
{
HealthNjinja healthNjinja = other.gameObject.GetComponent<HealthNjinja>();
healthNjinja.ModifyHealth(damage);
PlayerMovementNjinja reduceMoveSpeed = other.gameObject.GetComponent<PlayerMovementNjinja>();
reduceMoveSpeed.runSpeed = slowSpeed;
Destroy(gameObject);
}
PlayerMovementKnight maxSpeed = other.gameObject.GetComponent<PlayerMovementKnight>();
maxSpeed.runSpeed = maxS;
HealthKnight healthKnight = other.gameObject.GetComponent<HealthKnight>();
if (other.gameObject.tag == "Player_Knight")
{
isHit = true;
healthKnight.ModifyHealth(damage);
StartCoroutine(speedTime());
Destroy(gameObject);
}
IEnumerator speedTime()
{
while (isHit == true)
{
slowPlayer();
yield return new WaitForSeconds(timeOfReducedSpeed);
revertSpeed();
}
}
void slowPlayer()
{
maxSpeed.runSpeed = slowSpeed;
}
void revertSpeed()
{
maxSpeed.runSpeed = maxS;
}
}
}
还有我的 PlayerMovement 代码:
public class PlayerMovementKnight : MonoBehaviour
{
public CharacterController2D controller;
public Animator animator;
public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
bool crouch = false;
public WeaponKnight Bullet;
public bool grounded;
void Update()
{
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
animator.SetFloat("Speed", Mathf.Abs(horizontalMove));
if (Input.GetButtonDown("Jump"))
{
jump = true;
animator.SetBool("IsJumping", true);
}
if (Input.GetButtonDown("Crouch"))
{
crouch = true;
}
else if (Input.GetButtonUp("Crouch"))
{
crouch = false;
}
if (grounded && GetComponent<Bullet>().knockBack == false)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(0, 0);
}
}
public void OnLanding()
{
animator.SetBool("IsJumping", false);
}
public void OnCrouching(bool isCrouching)
{
animator.SetBool("IsCrouching", isCrouching);
}
void FixedUpdate()
{
controller.Move(horizontalMove * Time.fixedDeltaTime, crouch, jump);
jump = false;
}
}
问题似乎是您的 bool isHit
在调用协程之前设置为 true
,但从未重置为 false
。
所以循环:
while (isHit == true)
{
slowPlayer();
yield return new WaitForSeconds(timeOfReducedSpeed);
revertSpeed();
}
真是死循环。 您可能想在某处将 bool 重置为 false。
编辑:
根据评论,我现在看到您的脚本已附加到子弹游戏对象。在启动协程并减慢播放器速度后,您 Destroy(gameObject);
之后,脚本也被销毁,协程因此停止......没有任何东西可以让玩家的速度恢复正常。
你应该把协程移动到玩家的脚本中,需要的时候启动它。这样子弹毁了它还存在
您的布尔值 isHit
从未设置为假。导致玩家被减速,然后在他被击中一次后永远重置。
一开始就不需要创建 isHit
。为什么只有当 Player_Knight
已经被击中时才需要在输入 IEnumerator
时检查玩家是否被击中。
代码示例:
public class FrostHit : MonoBehaviour
{
float maxS = 40f;
float slowSpeed = 20f;
public Rigidbody2D rb;
int damage = -5;
int timeOfReducedSpeed = 2;
void Start()
{
rb.velocity = transform.right * slowSpeed;
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player_Njinja")
{
HealthNjinja healthNjinja = other.gameObject.GetComponent<HealthNjinja>();
healthNjinja.ModifyHealth(damage);
PlayerMovementNjinja mSpeedNinja = other.gameObject.GetComponent<PlayerMovementNjinja>();
StartCoroutine(speedTimeNinja());
}
else if (other.gameObject.tag == "Player_Knight")
{
HealthKnight healthKnight = other.gameObject.GetComponent<HealthKnight>();
healthKnight.ModifyHealth(damage);
PlayerMovementKnight mSpeedKnight = other.gameObject.GetComponent<PlayerMovementKnight>();
StartCoroutine(speedTimeKnight());
}
// Destroy Bullet
Destroy(gameObject);
}
IEnumerator speedTimeKnight()
{
mSpeedKnight.runSpeed = slowSpeed;
yield return new WaitForSeconds(timeOfReducedSpeed);
mSpeedKnight.runSpeed = maxS;
}
IEnumerator speedTimeNinja()
{
mSpeedNinja.runSpeed = slowSpeed;
yield return new WaitForSeconds(timeOfReducedSpeed);
mSpeedNinja.runSpeed = maxS;
}
}
我改变的地方和原因:
- 删除了 bool 和 while 循环,没有解决任何实际问题
- 从内部分离 IEnumerator 和 2 个函数
OnTriggerEnter2D()
- 在末尾添加了
Destroy(gameObject);
,因为子弹总是会被摧毁 - 删除了
maxSpeed.runSpeed = maxS;
,因为速度已经达到了 set/reset。没理由撞到子弹后重新设置速度 - 将
GetComponent
forPlayer_Knight
放入 else if 中,即使Player_Njinja
被命中,也没有理由执行GetComponent
。 - 删除了
reduceMoveSpeed.runSpeed = slowSpeed;
Player_Njinja
只会变慢并且永远不会恢复他的速度。而是再次使用 IEnumerator - 添加了另一个 IEnumerator,以便
Player_Njinja
和Player_Knight
都能正确减速和减速(现在甚至可以根据玩家被击中创建不同的减速时间) - 去掉函数,一行代码写一个函数真的不值得。特别是当你可以在 IEnumerator 中设置它而不需要更多代码行时