Okay so here is a video showing the problem that is pretty self explanatory
https://youtu.be/7701UK0ijy4
My problem is purely that when I switch to the Running Left animation, it still plays the Running Right animation instead
Before you read this list just know, none if it had any effect.
So far, I have tried setting Speed of Main_Run_Left to -1.
I have checked the Mirror box.
I have deleted all animations and reset them.
Edit: I switched Running_Left animation with a different monster animation and it kinda worked briefly? as in it was playing running_Left with the other monster animation set instead? Like I said briefly, it went back to running right while going left.
public Animator anim;
// Update is called once per frame
void Update()
{
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
if (horizontalMove > .001)
{
anim.SetBool("Running Right", true);
anim.SetBool("Running Left", false);
anim.SetBool("Chillin", false);
}
else if (horizontalMove < -.001)
{
anim.SetBool("Running Left", true);
anim.SetBool("Running Right", false);
anim.SetBool("Chillin", false);
}
else
{
anim.SetBool("Chillin", true);
anim.SetBool("Running Left", false);
anim.SetBool("Running Right", false);
}
What you're doing is kind of weird. You have a walking right animation AND a walking left animation, even though they're mirror flips of each other. How about deleting the walking left animation and renaming the other one to just 'Walking'? Then delete all the bools in your animator and replace them with a single one called 'Moving'. The condition to transition from chillin to walking is whether the 'Moving' bool is true, and vice versa. Then in code, you flip the sprite when its horizontal is less than zero. I posted a script below that shows what I'm talking about.
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
private float _speed;
private Rigidbody2D _rb;
private Animator _anim;
private SpriteRenderer _sprite;
void Start()
{
_rb = GetComponent<Rigidbody2D>();
_anim = GetComponent<Animator>();
_sprite = GetComponent<SpriteRenderer>();
}
void FixedUpdate()
{
Move();
}
private void Move()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
Vector2 movement = new Vector2(horizontal, vertical);
_rb.velocity = movement * _speed;
_anim.SetBool("Moving", horizontal != 0);
if (horizontal != 0)
Flip(horizontal > 0);
}
private void Flip(bool facingRight)
{
_sprite.flipX = !facingRight;
}
}
Related
When my player is moving, the animation switches between idle and walk when I am holding down D. I played the animation and it looks fine but when I play the transition it starts idle and switches to walk. I have tried creating a new project and doing it again but it does the same thing. Does anyone know how to fix this?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField]
float moveForce = 10f;
[SerializeField]
float jumpForce = 11f;
float movementX;
Rigidbody2D myBody;
Animator Anim;
private SpriteRenderer sr;
string WALK_ANIMATION = "Walk";
private void Update()
{
playerMoveKeyboard();
animatePlayer();
}
private void Awake()
{
myBody = GetComponent<Rigidbody2D>();
Anim = myBody.GetComponent<Animator>();
sr = GetComponent<SpriteRenderer>();
}
void playerMoveKeyboard()
{
movementX = Input.GetAxisRaw("Horizontal");
transform.position += new Vector3(movementX, 0f, 0f) * moveForce * Time.deltaTime;
}
void animatePlayer()
{
if(movementX > 0)
{
Anim.SetBool(WALK_ANIMATION, true);
sr.flipX = false;
}
else if (movementX < 0)
{
Anim.SetBool(WALK_ANIMATION, true);
sr.flipX = true;
}
else
{
Anim.SetBool(WALK_ANIMATION, false);
}
}
}
Not sure if I am seeing the problem correctly from the gif, but can't you just turn off "Has exit time" and change the transition duration to 0?
Not sure but using a float instead of a bool to decide when to play the animation might solve this. That is how I've been doing it and never had any problems.
Do this by creating a new parameter in the animator called "Speed". Change the condition from idle to walk to Speed greater 0.01 and walk to idle to Speed less 0.01 or some other small number.
In the code you can change "Speed" to the player speed by adding:
anim.setFloat("Speed", Mathf.Abs(movementX))
to the update function inside the player movement script.
You should also remove the Anim.SetBool() from the funciton animatePlayer().
I came across a problem that I can't solve. Whenever I move my character if it's near the edge of the map it goes through the tilemaps collider and goes out of the map. Here's the screenshot I took:
This is normal: link text
This is when the bug occurs: bug
Here's the code I'm using to move and flip the character:
using System.Collections;
using UnityEngine;
using UnityEngine.InputSystem;
public class MovementScript : MonoBehaviour
{
Vector2 moveInput;
Animator animator;
Rigidbody2D rb;
BoxCollider2D myCollider;
PlayerStats playerStats;
float playerSpeed;
[SerializeField] float timeToWaitAfterBeingAttackedToMoveAgain = 1f;
[SerializeField] int kickbackFromEnemyAttack = 40;
void Start()
{
myCollider = GetComponent<BoxCollider2D>();
rb = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
playerStats = GetComponent<PlayerStats>();
}
void FixedUpdate()
{
playerSpeed = playerStats.GetPlayerSpeed();
if(playerStats.PlayerIsAlive())
{
Run();
FlipSprite();
}
}
//If the player goes left the sprite flips left, otherwise it flips to the right
void FlipSprite()
{
bool playerHasHorizontalSpeed = Mathf.Abs(rb.velocity.x) >= Mathf.Epsilon;
if(playerHasHorizontalSpeed)
{
transform.localScale = new Vector2(Mathf.Sign(rb.velocity.x), 1f);
}
}
void Run()
{
Vector2 playerVelocity = new(moveInput.x * playerSpeed, rb.velocity.y);
rb.velocity = playerVelocity;
if (myCollider.IsTouchingLayers(LayerMask.GetMask("Ground")))
{
animator.SetBool("run", Mathf.Abs(rb.velocity.x) >= Mathf.Epsilon);
}
}
void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.CompareTag("Enemy") && playerStats.PlayerIsAlive())
{
this.enabled = false;
TriggerKickup();
StartCoroutine(ActivateMovement());
}
}
}
You’d likely be better to get the SpriteRenderer component and change its flipX property rather than reversing the scale.
Either way, if the sprite is moving in an unintended way when you flip it, it’s likely that the pivot isn’t set the way you want it — e.g. in this case it’s probably set to the bottom left of the sprite.
Select the sprite asset, click “Sprite Editor” in the inspector, and set the sprite’s pivot to the middle or bottom middle. Apply the changes and the sprite should flip from the centre instead of from the edge.
I was trying to code a system where a 2D character's sprite and collider turn to face the direction being input (i.e. pressing the left key makes the character face left, pressing the right key makes the character turn right). I had this script and it seemed to work for a while:
public bool turnedAround = false; //Says if you are facing to the left (true) or right (false)
[SerializeField]
private float xVelocityTolerance = .6f; //The slowest the player's X can move at to have the running animation show
[SerializeField]
private float groundDetectionOffset = .3f; //How far the raycast origin is offset
private Animator anim;
private Rigidbody2D rb;
private PlayerController playerController;
public float HalfPlayerHeight
{
get
{
return playerController.halfPlayerHeight;
}
}
private bool IsOnGround() //Checks if there is ground below the outside to the left, middle, and outside to the right
{
return Physics2D.Raycast(transform.position - new Vector3(groundDetectionOffset, 0f, 0f), -transform.up, HalfPlayerHeight) || Physics2D.Raycast(transform.position, -transform.up, HalfPlayerHeight) ||
Physics2D.Raycast(transform.position + new Vector3(groundDetectionOffset, 0f, 0f), -transform.up, HalfPlayerHeight); //Uses an artificial line break
}
void Start()
{
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
playerController = GetComponent<PlayerController>();
}
// Update is called once per frame
void Update()
{
//NOTE ABOUT WHOLE SECTION OF IS ELSE: The if checks if the player's facing right and moving left. If it is then it turns left and changes turnedAround to be true which means it is facing left. The else if is the opposite
if (rb.velocity.x < -xVelocityTolerance && !turnedAround)
{
transform.Rotate(0, 180, 0);
turnedAround = true;
}
else if (rb.velocity.x > xVelocityTolerance && turnedAround)
{
transform.Rotate(0, -180, 0);
turnedAround = false;
}
/*NOTE ABOUT WHOLE SECTION OF IS ELSE: The if checks if the player is moving either left and right fatser than the VelocityTolerance and if the player isn't jumping/falling.
If true it will tell the animator by setting IsRunningNotJumping to true. If it it false it will be set to false.*/
if ((rb.velocity.x > xVelocityTolerance || rb.velocity.x < -xVelocityTolerance) && IsOnGround() && !anim.GetBool("IsRunningNotJumping"))
{
anim.SetBool("IsRunningNotJumping", true);
}
else if (anim.GetBool("IsRunningNotJumping"))
{
anim.SetBool("IsRunningNotJumping", false);
}
//NOTE ABOUT WHOLE SECTION OF IS ELSE: The if statement checks if the player is jumping/falling. If they are than it will tell the animator by setting IsJumpingOrFallling to true and vice versa with the else.
if (!IsOnGround() && !anim.GetBool("IsJumpingOrFalling"))
{
anim.SetBool("IsJumpingOrFalling", true);
}
else if (IsOnGround() && anim.GetBool("IsJumpingOrFalling"))
{
anim.SetBool("IsJumpingOrFalling", false);
}
if (Fireballs.HasFireballs != anim.GetBool("HasFireballs"))
{
anim.SetBool("HasFireballs", Fireballs.HasFireballs); //Sets the HasFireballs bool in the animator equal to the HasFireball bool in the Fireballs script
}
if (BonusLife.hasBonusLife != anim.GetBool("HasBonusLife"))
{
anim.SetBool("HasBonusLife", BonusLife.hasBonusLife); //Sets the HasBonusLife bool in the animator equal to the HasBonusLife bool in the BonusLife script
}
if (SpawnFireballs.isThrowing != anim.GetBool("IsThrowing"))
{
anim.SetBool("IsThrowing", SpawnFireballs.isThrowing); //Sets the IsThrowing bool in the animator equal to the IsThrowing bool in the SpawnFireballs script
}
}
}
(rb = RigidBody2d)
However, for some reason now when I try to walk in one direction the TurnedAroud bool would constantly switch on and off and the player would be unable to move except in weird and unexpected ways. How can I fix this? I am open to different ways of making the Player face the correct direction.
I am coding in c# in Unity 2020.3.24f1 using visual studio. I am new to stack exchange so if I asked this question wrong I am sorry.
So, this code just isn't responding for whatever reason. I have an enemy that I'm trying to get to face the player at all times (The enemy swoops over the player's head back and forth periodically). But other than making a flip happen whenever a timer hits 0, which doesn't really work all that well, I can't get the Flip function to work. I know the Flipper function is fine; I already tested it out and everything. I'm just not sure how to tell the enemy that when the player is to the left of it, to turn, and vice versa.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class dragoonDetection : MonoBehaviour {
private Rigidbody2D rb;
private Animator anim;
public Transform Player;
private bool facingRight = true;
void Start ()
{
rb = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
}
void Update()
{
Flip();
}
void Flip()
{
if (Player.transform.localScale.x > 0) {
transform.localScale = new Vector3 (1.69f, 1.54f, 1f);
}
if (Player.transform.localScale.x < 0) {
transform.localScale = new Vector3 (-1.69f, 1.54f, 1f);
}
}
void Flipper()
{
facingRight = !facingRight;
Vector2 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
Got any ideas? I'd rather avoid using FindGameObject because it's not actually looking for the player script. It's looking for a child transform with no script attached to the player. And because I have two different player GameObjects that you can switch to anytime in the game, it wouldn't really work for me in that regard.
You will need to perform a check of some sort against the players position with the bird position if you want it to face the player at all times. A barebones method would just be to compare the x-positions of the two objects and change the scale accordingly.
void Update()
{
transform.localScale = new Vector3(getDir()*1.69f, 1.54f, 1);
}
private int getDir()
{
if (player.transform.position.x < transform.position.x)
return -1;
else
return 1;
}
You should throw some additional checks in here to keep it from updating the scale every frame when there is no change.
I'm trying to make a simple drag and drop game where you have objects that can be picked up and if left above 1/2 of the screens height then it will fall down to high they will fall if you let them go below half of the screen they will stay there. Its a 2D game and what give the illusion of depth.
This is an image of the Thing i would like to make
Currently I can move the blue bucket from the bottom. If i lift the bucket above the PolygonCollider it will fall down to the Edge Collider 4. When i leave it somewhere withing the Polygone Colider i set the object to kinetic so it wont fall it will give the illusion that you placed it on the ground.
My problem is that the colliders of the bucket what I use to detect the click on it, will overlap with the PolygonCollider. And can sometimes the object is on top and sometime the polygoncollider , and if the polygoncollider is on top i can not lift the object.
Is there a way to ignore on click all layers except the PickebleObject layer that i use to identify the objects that can be picked up ?
EDIT: here is my ObjectController script
public LayerMask interactLayers;
public LayerMask ignoredColliders;
public Action<GameObject> OnDrag;
public Action<GameObject> OnLand;
private Rigidbody2D objRB2D;
private Vector2 MousePos;
private bool IsOnFloor = false;
private void Start()
{
transform.position = new Vector3 (transform.position.x, transform.position.y, transform.position.z - 0.1f);
ignoredColliders = ~ignoredColliders;
objRB2D = transform.GetComponent<Rigidbody2D>();
objRB2D.gravityScale = GameManager.Instance.GlobalFallingSpeed;
}
private void OnMouseDown()
{
objRB2D.isKinematic = true;
}
private void OnMouseDrag()
{
MousePos = Camera.main.ScreenToWorldPoint (new Vector2 (Input.mousePosition.x, Input.mousePosition.y ));
//Limit So elements cant be moved out of the scene.
float HorizontalClamp = Mathf.Clamp (MousePos.x, CameraControll.Instance.CamTopLeft.x, CameraControll.Instance.CamBottomRight.x);
transform.position = new Vector3 (HorizontalClamp, MousePos.y, transform.position.z);
//Check what is under the mouse.
RaycastHit2D IsHoveringOver = Physics2D.Raycast(transform.position, transform.TransformDirection (Vector3.down), 0 , ignoredColliders);
if (IsHoveringOver.transform != null) {
if (GameManager.Instance.GroundColliders.value == LayerMask.GetMask (LayerMask.LayerToName (IsHoveringOver.transform.gameObject.layer)))
IsOnFloor = true;
}else IsOnFloor = false;
RaycastHit2D HitColider = Physics2D.Raycast(transform.position, transform.TransformDirection (Vector3.down), Mathf.Infinity , ~ignoredColliders);
#if UNITY_EDITOR
if (HitColider.collider != null) {
Debug.DrawLine( HitColider.point, transform.position, Color.magenta);
}
#endif
}
void OnMouseUp()
{
if (!IsOnFloor) objRB2D.isKinematic = false;
}
void OnCollisionEnter2D(Collision2D coll) {
//Debug.Log(coll.gameObject.transform.name);
}
I fixed the problem by using the Z axes to define wich of the colliders to be on top.
If you are using physics raycast in your drag-n-drop logic take a look at this documentation, there you will find a topic about LayerMask and Raycasting.