Hello Guest

Author Topic: How do I automatically go diagonally when hitting a diagonal?  (Read 5829 times)

zeteginara

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 38
    • View Profile
How do I automatically go diagonally when hitting a diagonal?
« 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:

When I should be doing this: 

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.
« Last Edit: March 01, 2014, 02:57:05 am by zeteginara »

zeteginara

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: How do I automatically go diagonally when hitting a diagonal?
« Reply #1 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?

mitralone

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 25
    • View Profile
Re: How do I automatically go diagonally when hitting a diagonal?
« Reply #2 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?

zeteginara

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: How do I automatically go diagonally when hitting a diagonal?
« Reply #3 on: March 01, 2014, 04:54:17 am »
I'm currently using spheres exclusively, so that's not the problem, but thanks.

zeteginara

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: How do I automatically go diagonally when hitting a diagonal?
« Reply #4 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?

zeteginara

  • 2D Toolkit
  • Newbie
  • *
  • Posts: 38
    • View Profile
Re: How do I automatically go diagonally when hitting a diagonal?
« Reply #5 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!