2D Plataformer: Character doesn't Flip after Walljump . C#
Hi, I'm a beginner in Unity, and I'm making a 2D plataformer and I'm having problems with Fliping the character after a Walljump.
I coded the walljump so the character jumps in a diagonal direction opposite to the wall. (Similar to the New Super Mario Bros).
The WallJump action works, but it doesn't flip the character when it does it.
Here is avideo showing the problem: VideoThis is the function I use to flip the character.
// Function FLIP
void Flip()
{
Vector2 newScale = graphics.localScale; // this is a child object that cntains all the Sprites and animations of the character.
newScale.x *= -1;
graphics.localScale = newScale;
frontOffset.x = -frontOffset.x; // this is the position of the Wall Jump Collider
facingRight = !facingRight;
}
And this is the statement I use to call the Flip() function. This line of code is inside of FixedUpdate:
// INPUT
move = Input.GetAxis("Horizontal") ;
//FLIP
if (move > 0 && !facingRight) Flip();
else if (move < 0 && facingRight) Flip();
For the WallJump I use this function.
void wallJump()
{
rb.velocity = new Vector2(xWallForce * -move , yWallForce);
wallJumpCounter = wallJumpTime;
}
and this line of code for calling the function, this is inside Update():
//WALL JUMP
if(Input.GetButtonDown("Jump") && wallSliding)
{
wallJump();
}
For more context here is the rest of the code.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerBehave : MonoBehaviour
{
// Character controller
[Header("Controller")]
private Rigidbody2D rb;
public float move;
public float speed;
public float maxSpeed;
[Header("Jump")]
public float airSpeed;
public float jumpForce;
public float gravityForce;
//this is a JumpKey
public float fallMultiplaier;
public float jumpDelay = 1;
public float jumpTimer;
// Grafics
[Header("Graphics")]
public Transform graphics;
public bool facingRight;
public Animator anim;
// Ground Checker
[Header ("GroundChecker")]
public Transform groundTransform;
public bool isGrounded;
public LayerMask groundMask;
public float groundLenght = 0.6f;
public Vector3 colliderOffset;
[Header("WallJumpChecker")]
public bool isTouchingFront;
public Vector3 frontOffset;
public bool wallSliding;
public float wallSlidingSpeed;
public Vector2 wallCheckSize;
[Header("WallJump")]
public bool isWallJump;
public float wallJumpTime;
private float wallJumpCounter;
public float xWallForce;
public float yWallForce;
// Start is called before the first frame update
void Start()
{
Application.targetFrameRate = 60;
rb = GetComponent<Rigidbody2D>();
facingRight = true;
maxSpeed = speed * 3;
airSpeed = speed * 2;
}
void FixedUpdate()
{
//GROUNDED
isGrounded = Physics2D.Raycast(transform.position + colliderOffset, Vector2.down, groundLenght, groundMask) || Physics2D.Raycast(transform.position - colliderOffset, Vector2.down, groundLenght, groundMask);
// TOUCHING WALL
isTouchingFront = Physics2D.OverlapBox(transform.position + frontOffset, wallCheckSize,0, groundMask);
//JUMP INPUT
if(jumpTimer > Time.time && isGrounded){
Jump();
}
// INPUT
move = Input.GetAxis("Horizontal") ;
//FLIP
if (move > 0 && !facingRight) Flip();
else if (move < 0 && facingRight) Flip();
}
// Update is called once per frame
void Update()
{
if(wallJumpCounter <= 0)
{
//MOVEMENT
if(isGrounded)
{
rb.velocity = new Vector2(move * speed, rb.velocity.y);
}
else if (!isGrounded && !wallSliding && move !=0)
{
rb.AddForce(new Vector2(airSpeed*move,0));
if(Mathf.Abs(rb.velocity.x)>maxSpeed)
{
rb.velocity = new Vector2(move * speed, rb.velocity.y);
}
}
//GRAVITY
if(isGrounded){
rb.gravityScale = 0;
}else
{
rb.gravityScale = gravityForce;
if(rb.velocity.y < 0){
rb.gravityScale = gravityForce * fallMultiplaier;
}else if (rb.velocity.y > 0 && !Input.GetButton("Jump"))
{
rb.gravityScale = gravityForce * (fallMultiplaier / 2);
}
}
//JUMP Timer
if (Input.GetButtonDown("Jump") && isGrounded )
{
jumpTimer = Time.time + jumpDelay; // esto hace que el jumpTimer se active
}
// WALL sliding
if(isTouchingFront == true && isGrounded == false && move != 0)
{
wallSliding = true;
} else{
wallSliding = false;
}
if (wallSliding)
{
rb.velocity = new Vector2(rb.velocity.x, Mathf.Clamp(rb.velocity.y, -wallSlidingSpeed, float.MaxValue));
}
//WALL JUMP
if(Input.GetButtonDown("Jump") && wallSliding)
{
wallJump();
}
}
else
{
wallJumpCounter -= Time.deltaTime;
}
}
//FUNCTIONS -------------------------------------------------------------------------------------------
// Character movement
void Jump()
{
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
jumpTimer = 0;
}
// Function FLIP
void Flip()
{
Vector2 newScale = graphics.localScale; // this is a child object that cntains all the Sprites and animations of the character.
newScale.x *= -1;
graphics.localScale = newScale;
frontOffset.x = -frontOffset.x; // this is the position of the Wall Jump Collider
facingRight = !facingRight;
}
void wallJump()
{
rb.velocity = new Vector2(xWallForce * -move , yWallForce);
wallJumpCounter = wallJumpTime;
}
//gIZMOS FOR THE COLLAIDERS
private void OnDrawGizmos(){
//GROUND_CHECKER
Gizmos.color = Color.blue;
Gizmos.DrawLine(transform.position + colliderOffset, transform.position + colliderOffset + Vector3.down * groundLenght);
Gizmos.DrawLine(transform.position - colliderOffset, transform.position - colliderOffset + Vector3.down * groundLenght);
//
//WALL JUMP CHECKER
Gizmos.color = Color.green;
Gizmos.DrawCube(transform.position + frontOffset, wallCheckSize);
}
}
Sorry for the lengthy post, but I have no idea why it doesn't flip.
I made this code following tutorials, and I try to understand everything I code. So I'm pretty sure this code is a isn't the best.
Any help is welcome.
Ok, I made some testing and I think I know where is the problem.
In the Flip statement if move*( Input.GetAxis("Horizontal"))* is -1 and the bool facingRight is false, the character flips.
// INPUT
move = Input.GetAxis("Horizontal") ;
//FLIP
if (move > 0 && !facingRight) Flip();
else if (move < 0 && facingRight) Flip();
When I wall jump the float move doesn't change.
So basically it only flips when an input to move in the other direction is detected.
When the character wallJumps, it moves to the opposite direction, but no input is detected so it doesn't flip.
I tried to put the Flip() inside the wallJump statement
//WALL JUMP
if(Input.GetButtonDown("Jump") && wallSliding)
{
wallJump();
Flip();
}
but it only flips for a split second, and then it changes back as it was before the Walljump.
Answer by ReceptiveRaptor · Mar 26, 2021 at 10:37 PM
void Flip()
{
Vector2 newScale = graphics.localScale; // this is a child object that cntains all the Sprites and animations of the character.
newScale.x *= -1;
graphics.localScale = newScale;
frontOffset.x = -frontOffset.x; // this is the position of the Wall Jump Collider
facingRight = !facingRight;
}
As of Unity 5.3, there is built-in "Flip" support. Just check whether you want to flip by X, Y, or both.
SpriteRenderer inspector
In code, you would just assign true/false to SpriteRenderer.flipX and .flipY.
Credit to @JoeStrout
I changed the line of graphics for the SpriteRenderer.flipX and it works, it flips when the character walks and jumps:
void Flip()
{
sprites.flipX = !sprites.flipX;
frontOffset.x = -frontOffset.x; // this is the position of the Wall Jump Collider
facingRight = !facingRight;
}
Still doesn't flip when it walljumps. But I think I know where is the problem. I will post it later.
Test reply
OK that was annoying, I was being told that I can't reply twice to an answer.
You need to reference the Sprite Renderer component. Your original code was probably fine, just needed to replace the local scale stuff with the flip x method
https://docs.unity3d.com/ScriptReference/SpriteRenderer-flipX.html
Check this page for more info. I would double check the script myself but it's 4 am
Ok, I'm not sure if this is what you meant but it works!
//WALL JUMP
if(Input.GetButtonDown("Jump") && wallSliding)
{
wallJump();
sprites.flipX = !sprites.flipX;
}
//WALL JUMP FLIP
if(isGrounded && move < 0 || isGrounded && move > 0) sprites.flipX = false;
else if(!isGrounded && Input.GetButtonDown("Horizontal") || !isGrounded && Input.GetButtonDown("Horizontal")) sprites.flipX = false;
I also put a flipX = false in the Flip() function.
// Function FLIP
void Flip()
{
Vector2 newScale = graphics.localScale; // this is a child object that cntains all the Sprites and animations of the character.
newScale.x *= -1;
graphics.localScale = newScale;
sprites.flipX = false;
frontOffset.x = -frontOffset.x; // this is the position of the Wall Jump Collider
facingRight = !facingRight;
}
The only object that doesn't flip is the wallslider collider, but I think it doesn't matter because the player has to move towards the wall in order to activate the wallsliding.
I will continue the testing but at first glance it seems to be working.
If there is a better way to code this any suggestion is welcome.
@ReceptiveRaptor Thank you very much!