I have a 2d character who can shoot out a hookshot projectile with a rigidbody2d attached, using the script below. When the projectile collides with a tilemapcollider2d on a certain layer (selected in Physics2D project settings) it is supposed to stop immediately. However, OnTriggerEnter2D does not always occur fast enough, causing the projectile to be clipped into the tile before it stops. THE SCRIPT FUNDAMENTALLY WORKS USING THIS SET UP, OTHER THAN THE CLIPPING.
I understand that onCollisionEnter2D and using velocity instead of MoveTowards might be the solution here, to stop the projectile when it collides with a tile of that layer. Unfortunately I cannot get this to work and I'm unsure why. I unchecked "is Trigger" on both the tilemapcollider2d and the projectiles rigidbody2d and it goes right through, the onCollisionEnter2D event never being registered.
public class Hookshot : MonoBehaviour
{
private GameObject player;
private Vector2 playerPos;
private BoxCollider2D col;
private Rigidbody2D rbody;
public GameObject DustParticle;
private readonly float hookshotCastTime = 0.2f;
private readonly float hookshotReturnSpeed = 200f;
private readonly float hookshotDistanceBuffer = 0.2f;
private void Awake()
{
col = GetComponent<BoxCollider2D>();
rbody = GetComponent<Rigidbody2D>();
}
public IEnumerator CastHookshot(float castDistance, Vector2 aimDir, GameObject playerInstance)
{
player = playerInstance;
playerPos = gameObject.transform.position;
Vector2 target = playerPos + (castDistance * aimDir);
float speed = castDistance / hookshotCastTime * Time.deltaTime;
while (Vector2.Distance(transform.position, target) > hookshotDistanceBuffer)
{
//transform.position = Vector2.MoveTowards(transform.position, target, speed);
rbody.velocity = speed * 10 * aimDir;
yield return new WaitForFixedUpdate();
}
transform.position = target;
StartCoroutine(ReturnHookshot());
}
public IEnumerator ReturnHookshot()
{
col.enabled = false;
playerPos = player.transform.position;
while (Vector2.Distance(transform.position, playerPos) > hookshotDistanceBuffer)
{
playerPos = player.transform.position;
transform.position = Vector2.MoveTowards(transform.position, playerPos, hookshotReturnSpeed * Time.deltaTime);
yield return new WaitForEndOfFrame();
}
Destroy(gameObject);
}
//private void OnTriggerEnter2D(Collider2D collision)
//{
// StopAllCoroutines();
// Player playerInstance = player.GetComponent<Player>();
// playerInstance.hookshotAttached = true;
// if (GameManager.instance != null)
// {
// GameManager.instance.Emit(DustParticle, 5, transform.position, Vector2.one * 3f);
// }
//}
private void OnCollisionEnter2D(Collision2D collision)
{
StopAllCoroutines();
rbody.velocity = Vector2.zero;
Player playerInstance = player.GetComponent<Player>();
playerInstance.hookshotAttached = true;
if (GameManager.instance != null)
{
GameManager.instance.Emit(DustParticle, 5, transform.position, Vector2.one * 3f);
}
}
}
FixedUpdate
and your coroutine being on (effectively)Update
. TryWaitForFixedUpdate()
instead. – Draco18s no longer trusts SE