I can't jump when I press the up arrow key. When I remove the condition of isGrounded to be able to jump, then my character can jump while in the air.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[SerializeField] private float speed;
private Rigidbody2D body;
bool isGrounded;
private void Awake()
{
body = GetComponent<Rigidbody2D>();
}
private void Update()
{
float HorizontalInput = Input.GetAxis("Horizontal");
body.velocity = new Vector3(Input.GetAxis("Horizontal") * speed, body.velocity.y);
if (HorizontalInput < -0.01f)
transform.localScale = Vector3.one;
else if (HorizontalInput > 0.01f)
transform.localScale = new Vector3(-1, 1, 1);
if (Input.GetKey(KeyCode.UpArrow))
isGrounded = false;
if (Input.GetKey(KeyCode.UpArrow) && isGrounded)
body.velocity = new Vector2(body.velocity.x, speed);
}
private void OnCollisionEnter2D()
{
isGrounded = true;
}
}
I tried to use OnCollisionEnter2D to set isGrounded to true, but I don't think it is working.
The problem is with this logic:
if (Input.GetKey(KeyCode.UpArrow))
isGrounded = false;
// isGrounded will always be false here if up-arrow key is pressed.
if (Input.GetKey(KeyCode.UpArrow) && isGrounded)
body.velocity = new Vector2(body.velocity.x, speed);
What you are looking for:
if (Input.GetKey(KeyCode.UpArrow) && isGrounded) {
body.velocity = new Vector2(body.velocity.x, speed);
isGrounded = false;
}
Use curly braces to denote multiple lines of code under a statement.
Also, use FixedUpdate for physics related manipulation like Rigidbodies.
Related
I am trying to flip my character sprite when moving left in my game, and I have followed multiple tutorials however my sprite does not seem to flip. It is always facing the same way.
Below is my code for my character's movement. I have created a Flip() function and 2 if statements used to call the function. The character can move left, right, up and down (no jumping).
I cannot seem to see where an error would be and why it is not flipping, so any help would be appreciated. thank you.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if(movement.x < 0 && facingRight)
{
Flip();
}
else if (movement.x > 0 && !facingRight)
{
Flip();
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Updated code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
// Start is called before the first frame update
private Animator animate;
public float moveSpeed = 6f;
bool facingRight = true;
public Rigidbody2D rb;
Vector2 movement;
private void Start()
{
animate = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
animate.SetFloat("Speed", Mathf.Abs(movement.x));
if (movement.x < 0 && facingRight)
{
GetComponent<SpriteRenderer>().flipX = true;
}
else if (movement.x > 0 && !facingRight)
{
GetComponent<SpriteRenderer>().flipX = false;
}
}
void FixedUpdate()
{
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
void Flip()
{
Vector3 currentScale = gameObject.transform.localScale;
currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
facingRight = !facingRight;
}
}
Try to set the flipX property of the SpriteRenderer.
GetComponent<SpriteRenderer>().flipX = true;
You have an animator attached to the game object, if the scale value is controlled by the animation clip, you cannot change it. A typical workaround is give the game object an empty parent and change its scale.
Player <---- Change scale here
Model <---- Animator here
transform.Rotate(0f, 180f, 0f); you have to change y while fliping
will work better instead of using currentScale.x *= -1;
gameObject.transform.localScale = currentScale;
This code worked for me
private void Flip()
{
// Rotate the player
if (transform.localEulerAngles.y != 180 && !facingRight)
transform.Rotate(0f, 180f, 0f);
else if(transform.localEulerAngles.y != 0 && facingRight)
transform.Rotate(0f, -180f, 0f);
// player flip point of attck also flip is direction
//transform.Rotate(0f, 180f, 0f);
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
GetComponent<SpriteRenderer>().flipX = true;
isLookingRight = false;
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
GetComponent<SpriteRenderer>().flipX = false;
isLookingRight = true;
}
Going to right
Going to left
I'm making a 2D platformer with Unity. I used this tutorial to write this code but changed it a little bit. I want to support both keyboard and gamepad, so I use the new Input System. I've defined three variables called GroundedRememeber, JumpPressedRemember and JumpPressedRememberTime and basically they work like timers and check if the player leaves the ground and then the player can jump when he is near the ground without need to touch it and I want to use it instead of famous "groundCheck". But the problem is that these timers are not working and the player can jump forever even in the air when I press jump button rapidly. Also, as you can see, I added a LayerMask named "groundLayers" for the player to jump only on this type of objects but when I choose "Ground" in the "groundLayers" slot in the Inspector, the player can't jump anymore.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour, PlayerInputActions.IPlayerActions
{
private PlayerInputActions controls;
[SerializeField] LayerMask groundLayers;
private Rigidbody2D rb;
private Animator anim;
private bool facingRight = true;
private Vector2 moveInput;
[SerializeField] private float jumpForce;
float JumpPressedRemember = 0;
[SerializeField] float JumpPressedRememberTime = 0.2f;
float GroundedRemember = 0;
[SerializeField] float GroundedRememberTime = 0.25f;
[SerializeField] float HorizontalAcceleration = 1;
[SerializeField] [Range(0, 1)] float HorizontalDampingBasic = 0.5f;
[SerializeField] [Range(0, 1)] float HorizontalDampingWhenStopping = 0.5f;
[SerializeField] [Range(0, 1)] float HorizontalDampingWhenTurning = 0.5f;
[SerializeField] [Range(0, 1)] float JumpHeight = 0.5f;
private void Awake()
{
controls = new PlayerInputActions();
controls.Player.SetCallbacks(this);
}
void Start()
{
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
}
void PlayerInputActions.IPlayerActions.OnMove(InputAction.CallbackContext context)
{
moveInput = context.ReadValue<Vector2>();
}
void Jump() {
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Force);
GroundedRemember = 0;
JumpPressedRemember = 0;
}
bool TryJump() {
if (GroundedRemember > 0) {
Jump();
return true;
} else {
JumpPressedRemember = JumpPressedRememberTime;
return false;
}
}
void PlayerInputActions.IPlayerActions.OnJump(InputAction.CallbackContext context)
{
jumpForce = context.ReadValue<float>();
switch (context.phase) {
case InputActionPhase.Performed:
TryJump();
break;
}
}
void FixedUpdate()
{
if(facingRight == false && moveInput.x > 0){
Flip();
}else if (facingRight == true && moveInput.x < 0){
Flip();
}
}
void Flip(){
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
void OnEnable()
{
controls.Enable();
}
void OnDisable()
{
controls.Disable();
}
void Update()
{
Vector2 GroundedBoxCheckPosition = (Vector2)transform.position + new Vector2(0, -0.01f);
Vector2 GroundedBoxCheckScale = (Vector2)transform.localScale + new Vector2(-0.02f, 0);
bool Grounded = Physics2D.OverlapBox(GroundedBoxCheckPosition, transform.localScale, 0, groundLayers);
GroundedRemember -= Time.deltaTime;
if (Grounded)
{
GroundedRemember = GroundedRememberTime;
}
JumpPressedRemember -= Time.deltaTime;
if ((JumpPressedRemember > 0)) {
TryJump();
}
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
float HorizontalVelocity = rb.velocity.x;
HorizontalVelocity += moveInput.x;
if (Mathf.Abs(moveInput.x) < 0.01f)
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenStopping, Time.deltaTime * 10f);
else if (Mathf.Sign(moveInput.x) != Mathf.Sign(HorizontalVelocity))
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingWhenTurning, Time.deltaTime * 10f);
else
HorizontalVelocity *= Mathf.Pow(1f - HorizontalDampingBasic, Time.deltaTime * 10f);
rb.velocity = new Vector2(HorizontalVelocity, rb.velocity.y);
}
}
If you know how much the player jumps for, then try maybe adding a delay to the next jump
Maybe using the Invoke() function ur just using Coroutines if you know how to use them.
But i would still recommend using a Ground Check since it's practical and just easier and i don't see a reason why you wouldn't use it.
I am new to programming and was wondering how I could make my "dash" make me move forward. I watched an online tutorial on how to make a dash work but after trying, the dash would only push me at all if I had written rb.velocity = Vector2.up * dashSpeed;. Currently, when I press the dash key, my character's gravity slows down for a second but no movement is made. Can I please get some help in making it push my character?
If you need clarification, please ask!
PS: Sorry for the long script, all my player control is in here.
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
public class CharacterController : MonoBehaviour
{
//Player Movement
public float speed;
public float jumpForce;
public Transform feetPos;
public float checkRadius;
public LayerMask whatIsGround;
public float dashSpeed;
public float startDashTime;
public Animator animator;
private Rigidbody2D rb;
private float moveInput;
private bool isGrounded;
private float jumpTimeCounter;
public float jumpTime;
private bool isJumping;
private float dashTime;
private int direction;
void Start()
{
animator.GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
dashTime = startDashTime;
}
void FixedUpdate()
{
moveInput = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
}
void Update()
{
// Moving
isGrounded = Physics2D.OverlapCircle(feetPos.position, checkRadius, whatIsGround);
if (moveInput > 0)
{
transform.eulerAngles = new Vector3(0, 0, 0);
animator.SetBool("Moving", true);
}
else if (moveInput < 0)
{
transform.eulerAngles = new Vector3(0, 180, 0);
animator.SetBool("Moving", true);
}
else
{
animator.SetBool("Moving", false);
}
// Jumping
if (isGrounded == true && Input.GetKeyDown(KeyCode.Space))
{
animator.SetTrigger("IsJumping");
isJumping = true;
jumpTimeCounter = jumpTime;
rb.velocity = Vector2.up * jumpForce;
}
if (Input.GetKey(KeyCode.Space) && isJumping == true)
{
if (jumpTimeCounter > 0)
{
rb.velocity = Vector2.up * jumpForce;
jumpTimeCounter -= Time.deltaTime;
}
else
{
isJumping = false;
}
}
if (Input.GetKeyUp(KeyCode.Space))
{
isJumping = false;
}
if (isGrounded == false)
{
animator.SetBool("Grounded", false);
}
if (isGrounded == true)
{
animator.SetBool("Grounded", true);
}
// Dashing
if(direction == 0)
{
if(Input.GetKeyDown(KeyCode.LeftShift))
{
if ((transform.rotation.eulerAngles.y == 180))
{
Dashleft();
}
else
{
DashRight();
}
}
}
else
{
if(dashTime <= 0)
{
direction = 0;
dashTime = startDashTime;
}
else
{
dashTime -= Time.deltaTime;
}
}
}
void Dashleft()
{
rb.velocity = Vector2.left * dashSpeed;
}
void DashRight()
{
rb.velocity = Vector2.right * dashSpeed;
}
}
The problem is that your horizontal velocity is being controlled in FixedUpdate()
It is being overriden in every physics frame, so when you change velocity in DashLeft() or DashRight() methods, velocity is being reset in this line rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
You can do something like this:
if (dashTime <= 0)
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
So you control your velocity by Input only if player is not dashing
I work in unity since 2 days now. I was scripting for a 2d Sprite. When i added the last elements the script didn't work anymore. but i want to make this work. can someone look at the error messages and then to the script to see what is wrong with it.
Error 1: (25,38): error CS1503: Argument #2' cannot convertfloat' expression to type `UnityEngine.Vector2'
Error 2: (25,38): error CS1502: The best overloaded method match for `UnityEngine.Physics2D.OverlapBox(UnityEngine.Vector2, UnityEngine.Vector2, float)' has some invalid arguments
Script:
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public float speed = 5f;
public float jumpSpeed = 8f;
private float movement = 0f;
private Rigidbody2D rigidBody;
public Transform groundCheckPoint;
public float groundCheckRadius;
public LayerMask groundLayer;
private bool isTouchingGround;
void Start()
{
rigidBody = GetComponent<Rigidbody2D> ();
}
void Update()
{
isTouchingGround = Physics2D.OverlapBox (groundCheckPoint.position, groundCheckRadius, groundLayer);
movement = Input.GetAxis ("Horizontal");
if (movement > 0f)
{
rigidBody.velocity = new Vector2 (movement * speed, rigidBody.velocity.y);
}
else if (movement < 0f)
{
rigidBody.velocity = new Vector2 (movement * speed, rigidBody.velocity.y);
}
else
{
rigidBody.velocity = new Vector2(0, rigidBody.velocity.y);
}
if (Input.GetButtonDown("Jump") && isTouchingGround)
{
rigidBody.velocity = new Vector2(rigidBody.velocity.x,jumpSpeed);
}
}
}
isTouchingGround = Physics2D.OverlapCircle(groundCheckPoint.position, groundCheckRadius, groundLayer);
If you still wanting to use the OverlapBox, here's the link to the Scripting API for it (I personally got here whenever I'm stuck): Unity - Scripting API: Physics2D.OverlapBox
Also, I would move the coding for player jumping to the FixedUpdate function instead of the Update function. Seen below is my code from my player controller script from a 2D platformer that I did for a game jam. Hope this helps.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpForce;
private float moveInput;
private Rigidbody2D rb;
private bool facingRight = true;
private bool isGrounded;
public Transform groundCheck;
public float checkedRadius;
public LayerMask whatIsGround;
private int extraJumps;
private void Start()
{
extraJumps = 1;
rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkedRadius, whatIsGround);
moveInput = Input.GetAxisRaw("Horizontal");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if (facingRight == false && moveInput > 0)
{
Flip();
}
else if (facingRight == true && moveInput < 0)
{
Flip();
}
}
private void Update()
{
if (isGrounded == true)
{
extraJumps = 2;
}
if (Input.GetKeyDown(KeyCode.W) && extraJumps > 0)
{
rb.velocity = Vector2.up * jumpForce;
extraJumps--;
}
else if (Input.GetKeyDown(KeyCode.W) && extraJumps == 0 && isGrounded == true)
{
rb.velocity = Vector2.up * jumpForce;
}
}
void Flip()
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
}
In my script, I have a patrol method and a chase method. My chase code using ray cast is not working properly. The only thing that works is my AI patrol code. When I hit a ray cast that I assign, it doesn't chase me. However, when I remove the patrol code in my script, my chase code works fine. What would be the problem? I want my AI to Patrol and Chase. If there is any collision and if the player is outside of the collision, the AI will start to patrol again
public class LineTrigger : MonoBehaviour {
private Transform targett;
public Transform sightStart, sightEnd;
public bool spotted = false;
public GameObject arrow;
public GameObject target;
public bool facingRight = false;
public float speed = 8;
[SerializeField]
float moveSpeed = 3f;
Rigidbody2D rb;
Vector3 localScale;
float dirX;
Vector3 directionToTarget;
void Start()
{
localScale = transform.localScale;
rb = GetComponent<Rigidbody2D> ();
dirX = -1f;
target = GameObject.Find ("Girl");
}
void Update()
{
if (transform.position.x < 1f)
dirX = 1f;
else if (transform.position.x > 20f)
dirX = -1f;
Raycasting ();
Behaviours ();
}
void Raycasting ()
{
Debug.DrawLine (sightStart.position, sightEnd.position);
spotted = Physics2D.Linecast (sightStart.position, sightEnd.position, 1 << LayerMask.NameToLayer ("Girl"));
}
void Behaviours()
{
if (spotted == true) {
arrow.SetActive (true);
directionToTarget = (target.transform.position - transform.position).normalized;
rb.velocity = new Vector2 (directionToTarget.x * moveSpeed, directionToTarget.y * moveSpeed);
}
else
{
arrow.SetActive (false);
}
}
void FixedUpdate()
{
rb.velocity = new Vector2 (dirX * moveSpeed, rb.velocity.y);
}
void LateUpdate()
{
CheckWhereToFace ();
}
void CheckWhereToFace()
{
if (dirX > 0)
facingRight = false;
else if (dirX < 0)
facingRight = true;
if (((facingRight) && (localScale.x < 0)) || ((!facingRight) && (localScale.x > 0)))
localScale.x *= -1;
transform.localScale = localScale;
}
}
I think you are missing a if(!spotted) in your FixedUpdate