DEV Community

Eduardo Julião
Eduardo Julião

Posted on

Creating abilities - Ground pound

Cool! Our character can move left, right and jump! (and fall off the edge of the map 😅).

But we can add something to our character to make our jump more, spicy, what about we add a Ground pound option?

It's pretty simple and can open a lot of doors for movement interaction, such as breakable ground and force push enemies once we hit the ground.

Also, it's not needed to create a new binding action in our PlayerInput script, we're going to use what we've already created and check for 3 things, if the player is holding down on the controller (or S or down arrow key) pressed jump and it's not grounded.

Ground Pound code

New fields

Let's start by creating something similar to jumpForce, but instead of making our character go up, we'll make our character go down.

Image description

And since we've added a Boolean field to tell us if the player pressed the jump button while grounded, we're going to use the same principle and create a field to tell us if the player met the conditions to do a ground pound.

Image description

And a couple more fields to help us, such as verticalMovement ( which follows the same idea of horizontal movement, but for, well, vertical) and baseGravityScale, which is the default gravity value our RigidBody2D starts with (in our scenario, 1).

Image description

And finally, set our baseGravityScale in the Awake method.

Image description

Updating our new fields

Let's starting by updating our verticalMovement by reading the Y value from our input.

Image description

With our verticalMovement updating, we can do our check.

Image description

Updating FixedUpdate method

Now, it's time to use these new fields in our FixedUpdate method, which controls the character.

First, let's update our velocityX variable, because we don't want to our player to move while ground pound is active.
To do that, we check if isForceDown is true, if it's true, we set our X movement to 0, otherwise, we keep the same movement logic as before.

Image description

And if it's force down, we set our gravityScale in the RigidBody to our downforce.

Image description

Some other code changes

Since we're creating more and more fields, I've decided to handle them in a single if statement instead of handling them individually.

Image description

In here, I'm setting isForceDown and hasJumpButtonTriggered back to false, and body.gravityScale back to its default.

Now that we have a single if statement to handle these fields, we can remove hasJumpButtonTriggered = false from our hasJumpButtonTriggered check, making the code simply:

Image description

Important changes

In some occasions, we're falling to fast to Unity to detect collision, this will break and make the player fall through the ground, to fix that, change the Collision Detection from Discrete to Continuous in the RigidBody2D options.

Image description

Thanks

And that's pretty much it! There's a lot of room for improvements but, its taking shape, slowly but surely! Hope this series is helpful, fun and easy to read! Until next chapter!

Full code

public class PlayerMovement : MonoBehaviour
{
    private PlayerInput playerInput;
    private Rigidbody2D body;
    private float horizontalMovement;
    private float verticalMovement;
    private float baseGravityScale;
    private bool hasJumpButtonTriggered;
    private bool isForceDown;


    [SerializeField]
    private float speed = 5f;

    [SerializeField]
    private float jumpForce = 5f;

    [SerializeField]
    private float downForce = 5f;

    [SerializeField]
    private bool isGrounded;
    [SerializeField]
    private Transform groundCheck;
    [SerializeField]
    private LayerMask groundLayer;

    private void Awake()
    {
        playerInput = new PlayerInput();
        body = GetComponent<Rigidbody2D>();
        baseGravityScale = body.gravityScale;
    }

    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        horizontalMovement = Mathf.RoundToInt(playerInput.Player.Move.ReadValue<Vector2>().x);
        verticalMovement = Mathf.RoundToInt(playerInput.Player.Move.ReadValue<Vector2>().y);

        isGrounded = Physics2D.OverlapCircle(groundCheck.position, 0.02f, groundLayer);

        if(playerInput.Player.Jump.triggered && isGrounded)
            hasJumpButtonTriggered = true;

        if (playerInput.Player.Jump.triggered && verticalMovement == -1 && !isGrounded)
            isForceDown = true;
    }

    private void FixedUpdate()
    {
        var velocityX = !isForceDown ? speed * horizontalMovement : 0;

        body.velocity = new Vector2(velocityX, body.velocity.y);

        if (hasJumpButtonTriggered)
        {
            body.velocity = new Vector2(body.velocity.x, jumpForce);
        }

        if (isForceDown)
            body.gravityScale = downForce;

        if (isGrounded)
        {
            isForceDown = false;
            hasJumpButtonTriggered = false;
            body.gravityScale = baseGravityScale;
        }
    }

    private void OnEnable()
    {
        playerInput.Player.Enable();
    }

    private void OnDisable()
    {
        playerInput.Player.Disable();
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)