0
votes

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);
    }
}

}

enter image description here

enter image description here

1
This is almost certainly due to the physics being on FixedUpdate and your coroutine being on (effectively) Update. Try WaitForFixedUpdate() instead.Draco18s no longer trusts SE
I just gave WaitForFixedUpdate() a try and it didn't change anythingdulongj

1 Answers

1
votes

Try adding a rigidbody to the object with your TileMapCollider on it and setting it to kinematic. A collision event should get registered between a Kinematic Rigidbody collider and a Regular Rigidbody collider. Also I don't see any code listening to the OnCollision Event. Can you share some pictures of your configuration for the two objects?