Make Character Able To Turn Back and Fourth in Unity - c#

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.

Related

How do I limit a GameObject to jump only Once?

I have Googled Everything but cannot get the right results. I want the GameObject to only jump once in the air, come back to the ground and then the player can jump. My current results are that the GameObject flies in the air if you press the spacebar. I wanna limit the GameObject to jump only once, come back and then jump if the player desires to. I have Shown some code down`
public class SphereController : MonoBehaviour
{
private bool IsOnGround = true;
Rigidbody rb;
public float BallSpeed = 10f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
float Hmove = Input.GetAxis("Horizontal");
float Vmove = Input.GetAxis("Vertical");
Vector3 MoveBall = new Vector3(Hmove, 0f, Vmove);
rb.AddForce(MoveBall * BallSpeed);
if ((Input.GetKey(KeyCode.Space)) && IsOnGround == true)
{
rb.AddForce(0, 20, 0);
}
}
private void OnCollisionStay()
{
IsOnGround = true;
}
Change the IsOnGround to false.
if ((Input.GetKey(KeyCode.Space)) && IsOnGround)
{
rb.AddForce(0, 20, 0);
IsOnGround = false
}
You have the OnCollision method that changes it back to true so this should work fairly well.
So, the way I do it is the following.
STEPS:
1- Tag the floor object as whatever you like. I always tag it as ground. You tag objects in the Inspector window, at the top left. I says Untagged by default
2- This is the Code I write:
bool isGrounded;
void OnCollisionEnter(Collision other)
{
if(other.gameObject.tag == "ground")
{
isGrounded = true; // if its colliding with "ground", isGrounded is true
}
else
{
isGrounded = false;
}
if(Input.GetKeyDown(KeyCode.space) && isGrounded) // change space to whatever key to jump
{
Jump(); // your jump code goes here EG. Rigidbody.AddForce(0, 15, 0);
}
}
I hope this is helpful.

Checking if RigidBody is grounded?

I have a GameObject with a Rigidbody, Mesh Collider, Skinned Mesh Renderer, and the below script.
I'm trying to check if it is Grounded, but the Console continuously spits out "Not Grounded!" when it is, so obviously something is wrong here. Can anyone please help?
public class GroundCheck : MonoBehaviour
{
public float Height;
bool IsGrounded;
Ray ray;
MeshRenderer renda;
private void Start()
{
Height = renda.bounds.size.y;
}
void Update()
{
if (Physics.Raycast(transform.position, Vector3.down, Height))
{
IsGrounded = true;
Debug.Log("Grounded");
}
else
{
IsGrounded = false;
Debug.Log("Not Grounded!");
}
}
}
Another option for checking if the rigidBody is grounded is using the OnTriggerStay function.
void OnTriggerStay(Collider other)
{
if (other.Transform.Tag == "Ground")
{
IsGrounded = true;
Debug.Log("Grounded");
}
else
{
IsGrounded = false;
Debug.Log("Not Grounded!");
}
}
I've checked your code with a simple scene with a plane and a cube, and it works.
It only spawns NotGrounded when it's clearly "floating" arround or the object has the half of it's body outside the plane.
Check those things drawing the Ray, this should give your more information about what is going wrong with your mesh.
Also if the problem is how the game is perceiving the Height of your Skinned Mesh you can also use SkinnedMeshRenderer.localBounds who returns the AABB of the object.
There is a better way to check if your rigidbody is grounded than collision checking and rays. But first, why is collision checking not a good idea: If your level is a single model the walls will too be tagged with the "Ground" tag and hitting a wall will return true, which you don't want. Rays can be used, but that's too much math you don't need to waste time with.
Instead of using new objects and methods, just check if the position is changing:
private float lastYposition;
private bool grounded;
void Start() {
lastYposition = transform.position.y;
}
void Update() {
grounded = (lastYposition == transform.position.y); // Checks if Y has changed since last frame
lastYposition = transform.position.y;
}
From here it's up to you what logic you are going to add.
Get the closest contact point to the bottom. Check if the contact normal is within range.
void OnCollisionStay(Collision collision)
{
var bottom = renderer.bounds.center;
bottom.y -= renderer.bounds.extents.y;
float minDist = float.PositiveInfinity;
float angle = 180f;
// Find closest point to bottom.
for (int i = 0; i < collision.contactCount; i++)
{
var contact = collision.GetContact(i);
var tempDist = Vector3.Distance(contact.point, bottom);
if(tempDist < minDist)
{
minDist = tempDist;
// Check how close the contact normal is to our up vector.
angle = Vector3.Angle(transform.up, contact.normal);
}
}
// Check if the angle is too steep.
if (angle <= 45f) IsGrounded = true;
else IsGrounded = false;
}
void OnCollisionExit(Collision collision)
{
IsGrounded = false;
}
I came up with this answer after reading amitklein's answer.
private void Jump()
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (transform.position.y == 0f)
{
rb.AddRelativeForce(Vector3.up * jumpForce);
}
}
}
I used this approach to jump using addrelativeforce of rigid body only when the position of y in 0.

Why isn't my 2D bullet's collider colliding with anything?

I'm trying to make a platformer game that uses 2D sprites in 3D space. For some reason, though the bullet the player shoots fires correctly from the GO that's a child of the player, it won't collide with anything (enemies, other objects, etc.) in either 2D or 3D. I have a 3D character controller on the parent player GO, but that doesn't affect the bullet object I'm firing, does it?
Colliders on everything appropriately.
Tried with IsTrigger both on and off in various combinations.
Objects are on the same layer and the same Z axis position.
//BULLET FIRING SCRIPT
void Update()
{
if (Input.GetButtonDown("Fire2") && !Input.GetButton("Fire3") &&
Time.time > nextFireTime)
{
Rigidbody2D cloneRb = Instantiate(bullet,
bulletSpawn.position, Quaternion.identity) as Rigidbody2D;
cloneRb.AddForce(bulletPrefab.transform.right *
projectileForce);
nextFireTime = Time.time + fireRate;
}
}
//____________________________________________________________
//BULLET OBJECT SCRIPT
private void Start()
{
direction = Input.GetAxisRaw("Horizontal");
if (direction == -1)
{
facingLeft = true;
}
else if (direction == 1)
{
facingLeft = false;
}
else if (direction == 0)
{
facingLeft = false;
}
if (facingLeft == false)
{
rb.velocity = transform.right * speed;
Debug.Log("Fired Bullet");
}
else
{
bulletPrefab.transform.Rotate(0, 180, 0);
firePoint.transform.Rotate(0, 180, 0);
Debug.Log("Rotated Bullet");
Debug.Log("Fired Bullet Left");
rb.velocity = transform.right * speed;
}
}
// Update is called once per frame
void Update()
{
}
public void OnTriggerEnter2D(Collider2D collider)
{
Debug.Log("Bullet Hit:");
Debug.Log(collider.name);
Enemy enemy = collider.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
}
Expected Result: Bullet object collides with other objects, prints Debug.Log output and gets destroyed.
Actual Result: Bullet object fires through, in front of, or behind other objects that also have colliders and there is no Debug.Log output. Bullet does not get destroyed and so instantiates clones infinitely when assigned input is entered.
Fixed issue by checking Default/Default in the Layer Collision Matrix under Edit-->Project Settings-->Physics. Not sure if it's supposed to be checked by default and somehow got unchecked but checking it solved the problem.

Why are my animations backwards in Unity?

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;
}
}

Unity Cant jump and move on the same time

Hello and thanks for reading this.
I made a little game in Unity and I finally got the movement controls with touch input to work.
But right now I face a little problem with combining the movement and jumping part. I cant jump if I'm moving BUT I can move if I'm jumping.
Each of my arrow keys contain a script and then later calls the "RobotController" script to start the movement.
ArrowRight and ArrowLeft Script. They look very much alike so I'll only post 1:
private RobotController PlayermoveRight;
// Use this for initialization
void Start () {
PlayermoveRight = GameObject.Find("Player").GetComponent<RobotController>();
}
void OnMouseOver()
{
if(Input.touchCount >= 1)
{
var touchr = Input.touches[0];
if(touchr.phase != TouchPhase.Ended && touchr.phase != TouchPhase.Canceled)
{
PlayermoveRight.MoveRight();
}
else
{
}
}
}
The ArrowUp script:
void OnMouseOver()
{
GameObject Go = GameObject.Find("Player");
if ((Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0)))
{
Go.GetComponent<RobotController>().Jump();
}
}
And the RobotController script:
public double moveTime = 0.1;
public double moveTimeR = 0.1;
private double lastPressedTime = 0.0;
private double PressRight = 0.0;
public void MoveLeft() // If ArrowLeft is clicked or Pressed
{
lastPressedTime = Time.timeSinceLevelLoad;
}
public void MoveRight() // If ArrowRight is clicked or Pressed
{
PressRight = Time.timeSinceLevelLoad;
}
void FixedUpdate () {
if (PressRight + moveTimeR > Time.timeSinceLevelLoad)
{
rigidbody2D.velocity = new Vector2 (maxSpeed, rigidbody2D.velocity.y);
}
else if (lastPressedTime + moveTime > Time.timeSinceLevelLoad)
{
rigidbody2D.velocity = new Vector2 (maxSpeed - maxSpeed - maxSpeed, rigidbody2D.velocity.y);
}
else
{
rigidbody2D.velocity = new Vector2(0.0f, rigidbody2D.velocity.y);
}
}
public void Jump()
{
if (isOnGround == true) {
anim.SetBool("Ground",false);
rigidbody2D.AddForce (new Vector2 (0, jumpForce));
}
}
How can I do so I can jump and move on the same time.?
from the up arrow code:
(Input.GetTouch(0).phase == TouchPhase.Began) || (Input.GetMouseButtonDown(0))
you're checking if the first touch has just started, if you are holding down a move arrow and you tap up to jump the "jump touch" isn't the first touch and the first touch (for the movement) isn't in it's began phase.
The reason it works with hitting jump and then moving is because the first touch in that case is the jump touch (by coincidence rather than by code).
You don't want to check against the first touch here, you want to check against the touch that is over the up arrow.
(not sure how you'd actually do that, but I can't comment until I get 50 rep :( )
I am also a newbie and was facing this problem few hours ago but I fixed it as I was told to do in an video tutorial so the fix was: Add some drag to your player, in the inspector there is a "Linear Drag" option in your rigidBody component increase it by 0.3(0 is the default value) this really fixed my problem I hope it will also help you(I know it is really late but I just found your question while googling my problem).

Categories