2D Toolkit Forum

2D Toolkit => Support => Topic started by: zeteginara on February 28, 2014, 07:19:06 pm

Title: How do I automatically go diagonally when hitting a diagonal?
Post by: zeteginara on February 28, 2014, 07:19:06 pm
So, I'm starting a top-down 2D RPG sort of game, with free-form movement instead of, well, large-grid specific movement. I got a 'basic guy moving across the screen colliding with a tilemap'. However, when I hit a tile with a diagonal collider, I slow way down.

I seem to be doing this: (http://i51.photobucket.com/albums/f363/zeteginara/22869-wrong_zpsa28fc79f.png)

When I should be doing this:  (http://i51.photobucket.com/albums/f363/zeteginara/22869-wrong_zpsa28fc79f.png)

My code is very simple and barebones.

float moveHorizontal = Input.GetAxisRaw("Horizontal");
float moveVertical = Input.GetAxisRaw("Vertical");

Movement = new Vector2(moveHorizontal, moveVertical);
rigidbody2D.velocity = Movement * Speed;

I've heard there are things you can do with Raycasts to take a slope into account.... but I haven't done anything with that before.  This seems to be a relatively common problem (like any platformer with slopes would have to code against), so I'm sure that it's easy to solve, but I'm not sure where to start.
Title: Re: How do I automatically go diagonally when hitting a diagonal?
Post by: zeteginara on March 01, 2014, 02:48:36 am
I've been working on this and scouring the internet all day, and getting frustrated.

Here's the entire code that I have:
Code: [Select]
void FixedUpdate()
    {
        float moveHorizontal = Input.GetAxisRaw("Horizontal");
        float moveVertical = Input.GetAxisRaw("Vertical");

        Movement = new Vector2(moveHorizontal, moveVertical);
        Movement.Normalize();
        rigidbody2D.velocity = Movement * Speed;
    }


    void OnCollisionEnter2D(Collision2D other)
    {
        Normal = other.contacts[0].normal;
        rigidbody2D.velocity -= Normal * Vector2.Dot(rigidbody2D.velocity, Normal);
    }


It seems that no one has a good answer to this, and I imagine this is a relatively standard problem.  I'm colliding with a diagonal on a sprite tilemap.  What am I doing wrong?
Title: Re: How do I automatically go diagonally when hitting a diagonal?
Post by: mitralone on March 01, 2014, 03:01:58 am
I remember reading somewhere that using sphere colliders in slopes produces the smoothest collisions. Can you try changing your colliders to sphere?
Title: Re: How do I automatically go diagonally when hitting a diagonal?
Post by: zeteginara on March 01, 2014, 04:54:17 am
I'm currently using spheres exclusively, so that's not the problem, but thanks.
Title: Re: How do I automatically go diagonally when hitting a diagonal?
Post by: zeteginara on March 01, 2014, 04:42:00 pm
Update:

One problem was that the velocity was only being updated once when the collision first happened, then was being overriden by FixedUpdate.  I've fixed that, and a few other errors that popped up, but there is one other:

Here's my new code:

void FixedUpdate()
{
    float moveHorizontal = Input.GetAxisRaw("Horizontal");
    float moveVertical = Input.GetAxisRaw("Vertical");

    Movement = new Vector2(moveHorizontal, moveVertical);
    Movement.Normalize();
    rigidbody2D.velocity = Movement * Speed;
    if (Colliding && Movement == RecordMovement)
    {
        rigidbody2D.velocity -= Normal * Vector2.Dot(rigidbody2D.velocity, Normal);
    }
    else
    {
        RecordMovement = Movement;
    }
}

void OnCollisionEnter2D(Collision2D other)
{           
    Normal = other.contacts[other.contacts.Length - 1].normal;
    Normal.Normalize();
    OppositeNormal = Normal * -1;

    if ((OppositeNormal != Movement) && (Colliding != true))
    {
        Colliding = true;
    }
    else
    {
        Colliding = false;
    }
}
void OnCollisionExit2D(Collision2D other)
{
    Colliding = false;
}
However, then I had another problem. Well, several other problems. I've resolved some, but one remains.

If I am up against a wall, and moving parellel to it so that my collider is 'just touching' the wall, and I hit a diagonal from there, then I move just as slow as if my new code didn't exist. After lots of debugging, I found that we are detecting a new collision, but if I try to get the normal of this new collision, I end up with the normal of the old collision (the wall I was sliding against) I don't know if this is a bug in Unity, or a flaw in the colliders generated by the 2D tilemap, or what.

I even tried changing my code to "Normal = other.contacts[other.contacts.Length - 1].normal;", assuming that would get the last element of the array (latest), but no dice, same incorrect normal.

So, any ideas?
Title: Re: How do I automatically go diagonally when hitting a diagonal?
Post by: zeteginara on March 03, 2014, 04:08:12 pm
I finally resolved this! My gut feeling was right: I was overthinking it.

Step 1: Remove all of the code example above and just have a simple:

Code: [Select]
    void FixedUpdate()
    {
        float moveHorizontal = Input.GetAxisRaw("Horizontal");
        float moveVertical = Input.GetAxisRaw("Vertical");
 
        movement = new Vector2(moveHorizontal, moveVertical);
        movement.Normalize();
        rigidbody2D.velocity = movement * Speed;
    }

Step 2: In your assets folder, go to Create > Physics2DMaterial. Create one.

Step 3: Click your new material, and call it whatever you want. I called it "Frictionless". Set Friction to 0, and make sure "Bounce" is 0.

Step 4: Drag your new material to any of the "Physics Material (2D)" fields in any of the objects involved in the equation.

You're done!