Detecting collision and fixing position odd behaviour.

Hi!,

Sorry for the dumb Topic, but didn’t really know how to describe my problem. First of all I must say I have spent last 5 days trying to make this work without luck, so, I have tested everything I have come across before posting. I’m pretty depressed not being able to find a solution for thi “easy” problem

What I’m trying to do is fairly easy, I have a player that has a collider (box collider). In the other side I have another 90 dregrees horizontal collider (a wall). I want that when I get a trigger enter in my player, push it out of the wall he is hitting. More ore less it works, but i can see during litle periods of time how player gets into the wall collider, what creates a vibrating effect on the player character being move it forward and back again to fixed position out of the wall collider.

What I’m doing is move the body in FixedUpdate based on player input and then wait for collisions. When I detect a vertical collision I just put the body back out of the colliding wall. Here is the the code I use:

public class PlayerController : MonoBehaviour
{

    // Use this for initialization
    void Start()
    {
        speed = 250;
        jumpSpeed = 1400;
        gravity = -850;
        _weapon = GetComponent(typeof(IWeapon)) as IWeapon;
        _mainCamTransform = Camera.mainCamera.transform;
        _thisTrans = transform;
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        CharacterController2D controller = this.GetComponent<CharacterController2D>();
        PackedSprite spr = this.GetComponent<PackedSprite>();

        Vector3 moveVector = Vector3.zero;

        if (Input.GetKey(KeyCode.RightArrow))
        {
            moveVector = Vector3.right * speed;
            if (!facing)
            {
                gameObject.transform.localScale = (new Vector3(1, 1, 1));
                facing = !facing;
            }

        }

        //Move he body
        _deltaPos = moveVector * Time.fixedDeltaTime;
        rigidbody.MovePosition(rigidbody.position + _deltaPos);
    }


    void HandleVerticalCollision(Collider other)
    {
        Debug.Log("Entering Vertical Collision for " + other.name);

        //We have a collision, check if it collided and push the collider out
        Bounds otherBound = other.bounds;
        Rigidbody body = gameObject.rigidbody;

        Vector3 newPos = body.position;
        Vector3 oldPos = newPos - _deltaPos;

        //Check if collision moving in X
        Bounds thisBound = collider.bounds;
        thisBound.center = oldPos + new Vector3(_deltaPos.x, 0, 0);

        if (thisBound.Intersects(otherBound))
        {
            //Push back the body if we're heading right
            if (transform.localScale.x > 0)
            {
                newPos.x = otherBound.min.x - thisBound.extents.x;
            }
            else if (transform.localScale.x < 0)
            {
                //Push back the body if we're heading left
                newPos.x = otherBound.max.x + thisBound.extents.x;
            }
        }

        body.position = newPos;
    }



    void OnTriggerEnter(Collider other)
    {
        HandleVerticalCollision(other);
    }


    public float speed;
    public float jumpSpeed;

    private float gravity;

    public Vector3 verticalSpawnPoint;
    public Vector3 horizontalSpawnPoint;

    IWeapon _weapon;

    //Right
    bool facing = true;

    //can jump
    bool jumping = false;

    //100 units per second
    float curJumpSpeed = 0;

    Transform _mainCamTransform = null;
    Transform _thisTrans = null;

    Vector3 _deltaPos;
}

At first I was thinking about the idea that some rendering was made between the FixedUpdate call and the collision detection, so, this could explain why the player was first rendered inside the wall and later out of it, but it seems by one of the wiki enties (execution order of monobehaviours) that nothing is executed between fixedupdate and collision code, so my idea should work.

I have minimized the code to make easy for everybody to check it. I really need to fix this, so, if anyone could be so kind to have a look at it I would be really gratefull.

Thanks in advance,
HexDump.

I don’t have an answer, but it looks like you’re trying to mix the built-in physics system with custom collision detection and response code (or something like that). Is there any reason you can’t just do one or the other? (That is, let the physics system handle it, or perform all collision detection and response yourself.)

Hi!,

Well, mainly I’m trying to use only collision detection system in Unity, I don’t want any physics. Main reason is I’m creating a 2D game for ios and I prefer not to have dynamic rigid bodies, I’m using kinematic bodies with a box collider. This provides me with an entry point to the physic system to let me be notified of collisions and calculate responses (really simple ones). For Y axis I use raycasts, and for X axis I use the above code because all will be straight colliders. All this is done just for eficiency, as i said I’m working on ios. I could do it all myself, but If I can use unity collision system would be much better. I don’t want to use Built-in character controller because it has some issues with 2D playability, for example, sliding on plataform edges because the capsule collider.

If anyone has a better solution or could explain the problem I exposed before I would be really happy because this problem is driving me nuts.

Thanks in advance,
HexDump.

I don’t know off the top of my head if/how your current method can be made to work with the physics system. However, if the collision detection and response requirements are fairly simple, you might consider just implementing the collision detection and response yourself. (Unfortunately such a system can be tricky to get right even when the requirements are straightforward, but it’s certainly doable.)

Hi!,

Thanks for the anwer.

It would be nice if anyone at UT could confirm this can be done using physic system. From the docs it seems it is yet possible but I get the problem state above.

It would save me a lot of work (Implementing a quadtree, etc…), so it is my main objective to use built-in syste.

I really need help with this :/.

Thanks in advance,
HexDump.

Hello there!

It seems you’re not using forces, correct?
In that case you could try setting rigidbody.velocity = Vector3.zero in your HandleVerticalCollision().
Since there’s no actual physical collision with the the trigger, if you were to have a velocity you would enter the wall.

Also it occurs to me that the small offset you use could cause vibrations, have you tried setting it to 0?

Hi!,

Thanks for the answers.

First of all as I’m using only kinematic rigid bodies. It implies no forces act on the body. If you try to set the velocity on a kinematic rigidbody you will get an exception saying it is not dynamic.

About the little offset, if you check the HandleVerticalCollision function, you will see that the body is pushed out exactly to the same position based on player/wall colliders, so no vibrations should be noticiable (it is really noticiable, I can add a video if needed).
This offset serves to let me get more TriggerEnter callbacks (don’t want to use TriggerEnter TriggerStay), and as I really think this is not the source of the problem, because I can see how the collider is getting inside the wall by a little period of time (around 0.1 secs or something like this).

I really like unity, and it is my main game programming tool, but sometimes it is like a “black box” where no more things can be done/tried if UT programmers don’t bring some more information on internals. Could this be one of these times?

Thanks in advance,
HexDump.

After a second look I’ve spotted another possible problem.
On a collision you’re actually moving another step forward.

You move at the end of your update:
rigidbody.MovePosition(rigidbody.position+_deltaPos);

And you move another step in your collision handling:
Vector3 oldPos = body.position;
Vector3 pos = oldPos + _deltaPos;

gameObject.rigidbody.position = pos;

Try declaring oldPos at the top of your script and set it to rigidbody.position right before your MovePosition()

Hi,

First of all wanna thanks both to take your time to read the code. Myx your were right, I was moving one step forward when I shouldn’t.

I have fixed the code and clean it a bit more. I was able to get rid of the Offset :), but same thing still occurs. Istead of do what you have suggested, I just calculate oldpos from rigid body position - _deltaPos. Thanks for the tip, I have spent so much time trying things that did not notice it.

If anyone knows why the problem still persists I’m all ears…

Edit:

Well I have been doing some tests, and it seems I found the problem. Here is the log of FixedUpdate and then the OntriggerEnter call during a Move/Collision detected.

First number is the frame count, current pos is the rigidbody.position when entering FixedUpdate. Player maxx is the bound max x of the moving collider (player). NewPosition is the nextposition calculated in FIxedUpdate after applying the moving vector for the player.

13 FixedUpdate current pos: (2589.9, 185.2, 10.0) player maxx:2624.873
13 Fixedupdate newpos: (2593.9, 185.2, 10.0) player maxx:2628.873

21 FixedUpdate current pos: (2593.9, 185.2, 10.0) player maxx:2628.873
21 Fixedupdate newpos: (2597.9, 185.2, 10.0) player maxx:2632.873
21 HandleVerticalCollision playerPos: (2597.9, 185.2, 10.0) bound maxx: 2632.873
21 HandleVerticalCollision WallPos: (2624.9, 299.3, 0.0) bound minx: 2624.873
21 HandleVerticalCollision Fixed position: (2589.9, 185.2, 10.0)

As we can see in frame 13 when we move the rigidbody in fixedstep player maxx is 2628.873 what is bigger than wall minx: 2624.873 so a collision should have been notified, but instead, another FixedUpdate call is done in frame 21 and then the collision is reported. The weird vibration is because this 8 frames collision notification delay, where player stays into the wall colldier. Is this how things work in unity for the TriggerEnter callback? O_O.

Thanks in advance,
HexDump.

Hi!,

I have built a little example project showing the problem I exposed.

It is just 2 boxes that collide and the moving one is repositioned beside the other. You can see in the output (root project folder log.txt) that OnTriggerEnter is notified a FrameFixedUpdate late than it should what is causing the vibrating problem.

Thanks in advance,
HexDump.

499184–17632–$test.zip (81.1 KB)