- Home /
Avoiding sttutering or sinking when Collision between trigger and kinematic body occurs
I'm doing some tests trying to avoid the use of raycasts. I'm trying just to let a box fall (kinematic body), and make it stand on another big box (floor). You can think it as a player colliding with floor. I achieved success using raycast for this but I wanted to try doing it with own unity collision system avoiding any player sttutering or sinking.
The code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Test : MonoBehaviour
{
Vector2 _velocity = Vector2.zero;
public Vector2 _acceleration = new Vector2(0, -10);
Rigidbody2D _rb;
void Awake()
{
_rb = GetComponent<Rigidbody2D>();
}
// Use this for initialization
// Update is called once per frame
void FixedUpdate ()
{
Debug.Log("Moved");
_velocity += _acceleration * Time.deltaTime;
_rb.position=_rb.position + _velocity * Time.deltaTime;
}
void OnTriggerEnter2D(Collider2D col)
{
Debug.Log("trigger Enter");
Vector3 pos = _rb.position;
float maxY=col.GetComponent<Collider2D>().bounds.max.y;
Vector3 newPos = new Vector3(0, maxY,0);
_rb.position=newPos;
_velocity.y = 0;
}
}
Really simple code. The problem is:
1) If I use OnTriggerStay instead of OnTriggerEnter it works correctly but this is too cpu intensive.
2) If I use OnTriggerEnter, it seems that when I move the box over the floor they are still sharing one edge (at y=0) and though, they are still colliding colliding and falling box (player) starts to sink next frame because no more OnTriggerEnter will be called.
3) If I use OnTriggerEnter with for example a delta of 0.1f, it stutters (you have to really get close to notice it because I use 1 pixel == 1 unity pixel but it happens).
So, Is there any possibility to accomplish total balance of the player on the floor without using OnTriggerStay?
Note: Player has its pivot at the bottom.
Note: The floor top is set at 0.
Thanks in advance.
Answer by lgarczyn · Mar 15, 2017 at 10:56 AM
You could just use a PlayerController. It has everything you need, gravity, good collision detection, etc.
You're really not using the system as it is meant to be used, nor doing things well at all.
Players or other sensitive elements should use Continuous (maybe even dynamic) Collision Detection (RigidBody settings).
The FixedUpdate intervals also are not a multiple of the Update interval, so you might randomly have one or two FixedUpdates between two render update.
You don't have any detection that your player is currently on a surface, and you use a bad approximation of physics, not even offset by doing them in small steps. Every frame your object sinks in the object, and is jumped back up.
removed false statement about OnTrigger calls
OnTriggerEnter also won't be called again if you don't move your object high enough to actually get out of the collider.
Have you actually checked that OnTriggerStay is too CPU intensive? That would surprise me a lot.
If you really want to do thing your way, activate interpolation on your RigidBody2d, use accurate physics movements, do them in small steps, and check yourself that you just moved in a collider. You can do that by getting a list of colliders in a reasonable range, and checking every step that you moved in a collider.
Once you are on a collider, you should check every frame that you still are on said collider, and round your position to the height of the collider using a "stayOnGroundForce" variable, that you can easily modify. You should still check other colliders for horizontal movement in a similar way.
And in the end you would have just reimplemented PlayerController. Just use what is available to you.
Hi,
Please first of all you should read unity life cycle https://docs.unity3d.com/$$anonymous$$anual/ExecutionOrder.html
From the graph when a collision is detected, you have the oportunity in OnTriggerXXXX to apply a response, so, OnTriggerXXXX could be executed several times but on FixedUpdate frame no Update frame.
On the other hand I don't like PlayerController it has several problems and it is not good for tight platformer physics. You say it has good collision dectection? Wrong again, https://docs.unity3d.com/ScriptReference/CharacterController.OnControllerColliderHit.html . Collisions are only detected when the character controller is moving. $$anonymous$$ore, it uses a capsule as collider. If you want to have something more or less good when you are at the edges start adding raycast and applying response by yourself to do not slide.
OnTriggerStay is too CPU intesive compared to other methods.
Anyway, my question wasn't about using Character controller. I have my own character controlled based on raycast for my 2d games. Just wanted to know why my attempts doing what I explained did not success because it should from the documentation. Anyway, it seems it is not possible to do it that way because to get a good response I must move the caracter where I did but it will always be touching the collider it collided previously, so, no more OnCollision Enter.
Cheers.
You are correct on OnTrigger. It was my understanding that anything trigger wasn't a physics call, but that appears to be false.
However I did state that OnColliderEnter would not be called again if you didn't move your collider high enough. Simply moving it a bit above the collider could work.
That said, I really don't know what you are trying to say with your link to OnControllerColliderHit. PlayerController will also call every usual Collider messages, such as OnCollisionEnter, OnCollisionExit, and OnCollisionStay. I actually tested this to be sure. No OnTriggerEnter, because the PlayerController is not a trigger.
PlayerController does have some weaknesses, but that collider is just used to know where you can move. $$anonymous$$ost games use a sphere colliders or variations for this. You could jut use different collider for hit detection, modify it for crouching, or add more behaviour to the PlayerController.
What I was trying to say with my link to OnControllerColliderHit is that OnCollision events are only triggered if CharacterController is moving. They are not triggered if it is stand still. The doc states that, and it is something I don't want.
About the collider thing you mention about handling my own collision. I have been tempted to build a quadtree and do it my way bypassing unity physics, but it is a pitty to do becase it is exactly what the 2d engine does (for the broad detection phase).
Again, What I was trying to do, that I think it is not possible is to detect the collsiion of the 2 colliders and move the "player" collider outside the "floor" collider. But this leads to sink if I just move at the same level (top for example) of the floor because no more Trigger Enter will occurr or leads to sttutering if I move it for example 1 pixel over the floor. This is why I was asking how people do this with a kinematic body. At this moment, what I do when I detect a collision using unity built-in collision system is move the player collider away and do not apply more gravity until the floor is left.
Cheers.
Answer by hexdump · Mar 16, 2017 at 09:55 AM
I use a trigger on the "non moving parts" because I don't want to use unity physics (only the collisiion detection part) and don't need the information that OnCollisionXXXX provides.
Cheers.
Your answer
Follow this Question
Related Questions
Physics2D.OverlapCircle dont detect triggers 3 Answers
OnCollisionEnter fires, but OnCollisionExit does not 1 Answer
OnTriggerEnter2D is not working 1 Answer
Colliding two GameObjects 1 Answer
Check for collision while animating 0 Answers