唯一对我有用的是设置一个knockedOut
临时标志来决定何时RigidBody.MovePosition()
暂时停止调用以给RigidBody.AddForce()
一些时间采取行动。
然后玩弄forceValue
,RigidBody.mass
并RigidBody.linearDrag
得到想要的效果。
这是我的 PlayerController 的实现:
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
[SerializeField] float speed = 1f;
[SerializeField] float impactEffect = 5f;
[SerializeField] float knockOutTime = 0.05f;
Vector2 direction = Vector2.zero;
Rigidbody2D rbody;
bool knockedOut;
IEnumerator knockOutCoroutine;
void Awake()
{
rbody = GetComponent<Rigidbody2D>();
}
void FixedUpdate()
{
if(!knockedOut) // Don't call Move() if I am knockedOut
Move();
}
// Triggered by the InputSystem
void OnMove(InputValue value)
{
// Set the direction value
direction = value.Get<Vector2>();
}
// Controls the normal movement of the Player based on the actual `direction` value
void Move()
{
Vector2 adjustedMovement = direction * speed * Time.fixedDeltaTime;
Vector2 newPos = rbody.position + adjustedMovement;
rbody.MovePosition(newPos);
}
// Invoke this method when Collision
public void Impact(Vector2 impactPosition)
{
Vector2 impactDirection = ((Vector2)transform.position - impactPosition).normalized;
rbody.velocity = Vector2.zero;
rbody.AddForce(impactDirection * impactEffect, ForceMode2D.Impulse);
KnockOut(knockOutTime);
}
void KnockOut(float seconds)
{
if(knockOutCoroutine != null)
StopCoroutine(knockOutCoroutine);
knockOutCoroutine = KnockOutCoroutine(seconds);
StartCoroutine(knockOutCoroutine);
}
// KnockedOut stop movement effect
IEnumerator KnockOutCoroutine(float seconds)
{
direction = Vector2.zero;
knockedOut = true;
yield return new WaitForSeconds(seconds);
knockedOut = false;
}
}