- Home /
OnCollisionEnter2D not triggering fast enough(?)
To keep it short:
I'm creating a platformer with a character that has a bow and can shoot arrows towards the cursor. I'm trying to make it so that the arrow stops on collision and "sticks" to the collided object. Problem is that if the arrow travels too fast, it rotates the arrow slightly and the arrow goes inside the collider. This is not an issue if the moveSpeed is set to i.e 10.
public int moveSpeed = 150;
public float shotDepth;
private bool hit = false;
private void Awake()
{
Physics2D.IgnoreLayerCollision(8, 8, true);
}
void Update()
{
if (!hit)
{
transform.Translate(Vector3.right * Time.deltaTime * moveSpeed);
Destroy(gameObject, 6.0f);
}
}
private void OnCollisionEnter2D(Collision2D col)
{
hit = true;
transform.parent = col.transform;
Destroy(gameObject.GetComponent<Rigidbody2D>());
Destroy(gameObject.GetComponent<Collider2D>());
Debug.Log("Collision " + col.collider.name);
col.transform.Translate(shotDepth * -Vector2.right);
}
This is the code that moves the arrow and checks for collision.
Any help would be appreciated!
Answer by fdz_ · Dec 08, 2017 at 06:49 PM
Why don't you move the arrow with the Rigidbody2D.velocity and set the Collision Detection to Continous? If you don't want that, maybe you could raycast.
What happens now is that the arrow moves so fast, that it kinda teleports through the colliders, since you are translating the transform.
The script for moving the arrow and the one that actually shoots are different. Hence why I'm using transform.Translate. I've been taught that's the proper way for linear movements, is that wrong? How would I go about moving something forward with RigidBody2D.velocity?
EDIT: Scratch that, I figured it out. It still seems to be rotating a bit strangely after it hits the collider, any ideas?
You could freeze the rotation of the arrow. To to that, on the Inspector go to the Rigidbody2D and under Constraints check Freeze Rotation Z or with code:
var rb2d = GetComponent<Rigidbody2D>();
rb2d.constraints = RigidbodyConstraints2D.FreezeRotation;
Answer by Dray · Dec 08, 2017 at 08:06 PM
You could try moving the arrow using Rigidbody.MovePosition in FixedUpdate() and replacing deltaTime with fixedDeltaTime
Hey, thanks for the answer. What's the point of using fixedDeltaTime within a FixedUpdate function?
The difference between Update() and FixedUpdate() is that between each Update() call the scene is rendered and sent to the screen once, which takes a different amount of time depending on the complexity of the current scene, while FixedUpdate() operates independently, usually looping much quicker and always with the same fixed timestep. The benefit of that is obviously accuracy (in terms of collision/physics calculations and such) aswell as predictability of your results. In most cases you're better off using FixedUpdate for physical, time based calculations since that will give you cleaner movements.
For example a ball rolling down an uneven hill could be calculated in Update() with varying timesteps for each frame, which would also give you kind of sane results but the point where the ball stops rolling would always be a different one since there will be some differences in the smaller digits. Calculating the movement in FixedUpdate() though will cause the ball to always move the same distance in each "physical" frame and therefor will always end up in the same end-position, no matter how often you run your simulation.
This by the way can be the cause for objects moving trough each other and stuff like that when you have bigger framedrops.
Your answer
Follow this Question
Related Questions
How to calculate faces for collision? 1 Answer
Detect Collision Direction 0 Answers
collision detection on user-controlled rigidbodies 1 Answer
Bug in collision detection? 1 Answer
Colliders attached to bones 0 Answers