Advertisement

Trouble with sprite sorting layers and rotation!

Started by June 21, 2020 06:43 PM
3 comments, last by LorenzoGatti 4 years, 6 months ago

Hi guys! I'm working on a 2D platformer in which there are two playable characters that the player can toggle between and control independently. I'm having two issues with these characters regarding their movement. I would like the dark grey character to move (render) behind the light grey character, however, even when I put them on separate sorting layers (or even same sorting layer but different order in layer) they are still bumping into each other and falling all over the place. All other sorting layers are rendering fine, so I don't know why these two game objects are continuing to interact this way.

The other problem I'm having is trying to keep the entire base of the sprites in contact with the ground layer when moving. When I move the dark grey sprite, it falls over when it goes up or down hill. So I tried to freeze the rotation on the rigid body, which worked fine for the falling, but the entire base will obviously no longer be on the ground since it's frozen.

I've attached my movement code and some photos, hopefully that helps! I'm still very new to Unity, so please explain it like I'm 5 so I can understand *why* this is happening instead of just implementing a solution I don't understand.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharacterController : MonoBehaviour
{
    //public variables
    [Range(0.0f, 10.0f)] public float moveSpeed;
    public float jumpForce;
    public float fallMultiplier = 3.5f;
    public float lowJumpMultiplier = 3f;


    //private variables
    Rigidbody2D _rb2d;
    Transform _transform;
    PolygonCollider2D _playerCollider;
    float _horizontal;
    bool _isFacingRight;
    bool isGrounded;

    // Start is called before the first frame update
    void Start()
    {
        _rb2d = GetComponent<Rigidbody2D>();
        _transform = GetComponent<Transform>();
        _playerCollider = GetComponent<PolygonCollider2D>();
    }

    // Update is called once per frame
    void Update()
    {
        MovePlayer();
        Jump();
    }

    private void LateUpdate()
    {
        FlipSprite();
    }

    private void MovePlayer()
    {
        float horizontal = Input.GetAxis("Horizontal");
        Vector2 moveVelocity = new Vector2(horizontal * moveSpeed, _rb2d.velocity.y);
        _rb2d.velocity = moveVelocity;
    }

    private void Jump()
    {

        if (Input.GetButtonDown("Jump") && _playerCollider.IsTouchingLayers(LayerMask.GetMask("Ground", "Shadow", "Protagonist")))
        {
            _rb2d.velocity = Vector2.up * jumpForce;
        }

        if (_rb2d.velocity.y < 0)
        {
            _rb2d.velocity += Vector2.up * Physics2D.gravity.y * (fallMultiplier - 1) * Time.deltaTime;
        }

        else if (_rb2d.velocity.y > 0 && !Input.GetButton("Jump"))
        {
            _rb2d.velocity += Vector2.up * Physics2D.gravity.y * (lowJumpMultiplier - 1) * Time.deltaTime;

        }
    }

    private void FlipSprite()
    {
        bool playerIsMovingHorizontally = Mathf.Abs(_rb2d.velocity.x) > Mathf.Epsilon;
        if (playerIsMovingHorizontally)
        {
            transform.localScale = new Vector2(Mathf.Sign(_rb2d.velocity.x), 1f);
        }
    }
}

Sorting-layers are only for rendering (=drawing sprites in certain orders on top of each other) and have no effect on movement or collision. So if you want your characters to not touch, you have to configure a collision-mask on the rigidbody (for example, set both to “player” and make “player” not collide with itself in Physics2D-project settings).

Rendering and collision are very distinct systems. You render the result of what the physics/transform-system gives you, so in generel do not expect to change the behaviour of your characters physics/movement by changing render-parameters.

Advertisement

@Juliean Thank you so much for the quick reponse! I was hesitant to play with the collision matrix because it was very fixed, but I think I should be able to achieve my desired results by ignoring layer collisions programmatically. Applying a bool offered some extra flexibility.

Any thoughts/ideas on the rotation and grounding issues?

In the first picture, the dark grey hook character has an implausible position: standing on air with a single point contact with the ground (the light green shape) and an exactly horizontal base, presumably the result of “freezing rotation”.

For a more realistic appearance, it should either immediately tumble downhill or deform so that

  • the base is tangent to the hill shape, not horizontal (even better, deformed to match the hill shape)
  • the downward projection of the barycenter is above the single tangent contact point or (better) between the projections of two contact points (i.e., for people, two feet)

Alternatively, you could:

  • avoid arbitrary slopes that require adjustable characters, restricting the terrain to a limited set of possible slopes with matching, predetermined character poses and animations, like in countless traditional platformer games.
  • not make the character stand. For example, it could fly, jump or run without stopping.

Omae Wa Mou Shindeiru

This topic is closed to new replies.

Advertisement