Working on a platformer where as the player moves over an energy orb, they can choose to fuel either a double jump or a dash. No errors according to unity, but when I press the corresponding keys for my double jump and dash, neither work. Simply nothing happens. Oh and btw my character randomly freezes and I have to tap the movement key again to get him to continue moving this is also a new issue so may be related. I am very new to all this.
public class playerMovement : MonoBehaviour
{
[SerializeField] private float speed;
[SerializeField] int dashEnergy = 1;
[SerializeField] int doubleJumpEnergy = 1;
private Rigidbody2D body;
private Animator anim;
private int jumpCount;
private void Awake()
{
body = GetComponent<Rigidbody2D>();
}
private void Update()
{
//Left-Right Movement
float horizontalInput = Input.GetAxis("Horizontal");
if(Input.GetKey(KeyCode.Space) && jumpCount == 0)
{
jump();
jumpCount += 1;
}
body.velocity = new Vector2(horizontalInput*speed, body.velocity.y);
//Character Turns Towards Movement Direction
if (horizontalInput > 0.01f)
transform.localScale = new Vector3(-5, 5, 5);
if (horizontalInput < -0.01f)
transform.localScale = new Vector3(5,5,5);
//Dash & doubleJump
void doubleJump()
{
if(Input.GetKey(KeyCode.Space)&&jumpCount==1 && doubleJumpEnergy==1)
{
jump();
doubleJumpEnergy -= 1;
}
}
void Dash()
{
if(Input.GetKey(KeyCode.LeftShift) && dashEnergy == 1)
{
body.velocity = new Vector2(horizontalInput*speed*60, body.velocity.y);
dashEnergy -=1;
}
}
}
public void jump()
{
body.velocity = new Vector2(body.velocity.x, speed);
}
private void OnCollisionEnter2D(Collision2D collision)
{
if(collision.gameObject.tag == "EnergyBubble" && Input.GetKey(KeyCode.V))
{
dashEnergy += 1;
}
if(collision.gameObject.tag == "EnergyBubble" && Input.GetKey(KeyCode.C))
{
doubleJumpEnergy += 1;
}
if (collision.gameObject.tag == "Ground")
{
jumpCount=0;
}
}
}
Firstly, all physics operations should be used from fixedUpdate method, for example:
void FixedUpdate()
{
if (Input.GetButtonDown("Space"))
rb.velocity = new Vector2(0, 10);
}
It's needs for smoothly physics movement.
Or call your own method from it:
void FixedUpdate()
{
if (Input.GetButtonDown("Space"))
jump();
}
Then you have a bug in condition check statements, you have to use:
//Dash & doubleJump
if (Input.GetKey(KeyCode.Space) && jumpCount == 1 && doubleJumpEnergy >= 1)
{
body.velocity = new Vector2(0, 2);
doubleJumpEnergy -= 1;
}
if (Input.GetKey(KeyCode.LeftShift) && dashEnergy >= 1)
{
body.velocity = new Vector2(horizontalInput * speed * 60, body.velocity.y);
dashEnergy -= 1;
}
Problem with a condition check statements, you need to have ">=" operator: dashEnergy >= 1 and doubleJumpEnergy >= 1 instead ==
Related
Here is the complete player controller file.
using UnityEngine;
public class PlayerCont : MonoBehaviour
{
[Header("Movement Variables")]
public float moveSpeed;
private float speed;
public float maxSpeed;
public float acceleration;
public float dropSpeed;
public float slideSpeed;
public int direction = 1;
[Header("Jump Variables")]
public float jumpForce;
public int extraJumps;
private float jumpTimeCounter;
public float jumpTime;
private bool isJumping;
private int jumpNum;
[Header("Dash Variables")]
public float dashSpeed;
public float dashLength = .5f;
public float dashCooldown = 1f;
private float dashCounter;
public float dashCoolCounter;
private KeyCode _lastKeyCode;
private float doubleTapTime = 0.05f;
private bool doubleTap;
public bool isDashing;
public float dashTime;
public float maxDashTime;
[Header("GroundCheck Variables")]
public Transform groundCheck;
public float checkRadius;
public LayerMask whatIsGround;
[Header("Debug Variables")]
public Rigidbody2D rb;
public float moveInputX;
public float moveInputY;
public bool facingRight = true;
public bool isGrounded;
public bool downKey;
public float rbxVel;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
speed = moveSpeed;
jumpNum = extraJumps;
}
void FixedUpdate()
{
}
// Update is called once per frame
void Update()
{
moveInputX = Input.GetAxisRaw("Horizontal");
moveInputY = Input.GetAxisRaw("Vertical");
isGrounded = Physics2D.OverlapCircle(groundCheck.position, checkRadius, whatIsGround);
KeyChecks();
Jump();
GroundPound();
Move();
Dash();
}
void KeyChecks()
{
//restricts movement in Y to only be downward
if (moveInputY > 0)
{
moveInputY = 0;
}
//checks for player drop
if (!isGrounded && moveInputY < 0)
{
downKey = true;
}
else
{
downKey = false;
}
//changes direction relative to keypress
if (Input.GetKeyDown(KeyCode.A))
{
direction = -1;
}
if (Input.GetKeyDown(KeyCode.D))
{
direction = 1;
}
}
void Jump()
{
//sets jump number to user specified amount after touching ground
if (isGrounded)
{
extraJumps = jumpNum;
}
//jumps and decrements extrajumps by 1
if (Input.GetKeyDown(KeyCode.Space) && !downKey && extraJumps > 0)
{
isJumping = true;
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
extraJumps--;
}
//basic jump off of ground
else if (Input.GetKeyDown(KeyCode.Space) && extraJumps == 0 && isGrounded && !downKey)
{
isJumping = true;
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
}
//checks for longkeypress of spacebar and increases length of jump
if (Input.GetKey(KeyCode.Space) && extraJumps > 1 && isJumping) // allows a hold down increase to jump while grounded
{
if (jumpTimeCounter > 0)
{
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
jumpTimeCounter -= Time.deltaTime;
}
else
{
jumpTimeCounter = jumpTime;
isJumping = false;
}
}
}
void GroundPound()
{
//ground pound keypress check
if (!isGrounded && Input.GetKeyDown(KeyCode.S))
{
if (!doubleTap && doubleTapTime > Time.time && _lastKeyCode == KeyCode.S)
{
rb.velocity = new Vector2(rb.velocity.x, -1 * dropSpeed);
Debug.Log("dashing right");
}
else
{
doubleTapTime = Time.time + 0.5f;
}
_lastKeyCode = KeyCode.S;
}
}
void Move()
{
//changes movement relative to input
if (!isDashing)
{
if (isGrounded && Input.GetKey(KeyCode.S))
{
rb.velocity = new Vector2(rb.velocity.x * .999f, rb.velocity.y);
}
else if (moveInputX == 0 && isGrounded)
{
speed = moveSpeed;
rb.velocity = new Vector2(rb.velocity.x * .99f, rb.velocity.y);
}
else if (moveInputX == 0 && !isGrounded)
{
speed = moveSpeed;
}
else
{
rb.velocity = new Vector2(moveInputX * speed, moveInputY / 10 + rb.velocity.y);
}
}
//checks player velocity
rbxVel = rb.velocity.x;
//increases speed relative to input direction
if (moveInputX > 0 || moveInputX < 0)
{
speed += acceleration;
}
//caps speed
if (speed > maxSpeed)
{
speed = maxSpeed;
}
//caps min speed
if (speed < moveSpeed)
{
speed = moveSpeed;
}
}
void Dash()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
isDashing = true;
if (isDashing && dashCoolCounter <= 0)
{
dashTime -= Time.deltaTime;
dashCoolCounter = dashCooldown;
rb.velocity = new Vector2(dashSpeed * direction, rb.velocity.y);
Debug.Log("Dash Started");
}
}
else
{
dashTime = maxDashTime;
isDashing = false;
Debug.Log("No Dash");
}
//resets dash cooldown
if (dashCoolCounter > 0)
{
dashCoolCounter -= Time.deltaTime;
}
}
void Flip()
{
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
}
When using the keys for movement (A, S) the dash doesn't function. Oddly enough the code is executing (I see my debug statement in console) but nothing physically changes.
When rewriting the code for the dash from: rb.velocity = new Vector2(dashSpeed * direction, rb.velocity.y) to: rb.velocity = dashspeed the dash will work without issue. The only downside to that is that the Y component of the RigidBody is being manipulated as well.
This has been an issue for days now, and I am just rewriting the post.
Any and all help is welcomed.
You're setting isDashing = false too soon. It gets set to false as soon as you let go of Shift which allows Move to execute its code and change your rigidbody's velocity back to normal move.
Didn't test this, but give it a shot and see if it works the way you want it to.
void Dash()
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
if (!isDashing && dashCoolCounter <= 0)
{
isDashing = true;
dashTime = 0;
dashCoolCounter = dashCooldown;
rb.velocity = new Vector2(dashSpeed * direction, rb.velocity.y);
Debug.Log("Dash Started");
}
else if(isDashing)
{
rb.velocity = new Vector2(dashSpeed * direction, rb.velocity.y);
dashTime += Time.deltaTime;
if(dashTime >= maxDashTime)
{
isDashing = false;
Debug.Log("No Dash");
}
}
}
// resets dash cooldown
if (dashCoolCounter > 0)
{
dashCoolCounter -= Time.deltaTime;
}
}
I'm pretty new to all of this so sorry for rookie mistakes. I'm making a 2D platformer
I am checking for ground via RayCast and right after the player jumps, the jumpCounter resets to 0, so I get a bonus jump. I tried adding a 0.2s timer before it can reset but that caused trouble when jumping multiple times in a row (bunny hopping). Any help?
private void FixedUpdate()
{
GroundCheck();
if (state != State.hurt)
{
Movement();
DoubleJump();
StateMachine();
}
HurtCheck();
anim.SetInteger("state", (int)state);
}
private void Movement()
{
//Input.GetAxis returns a value between -1 up to 1
//Edit> Project Settings> Input> Axis> Horizontal
float hDirection = Input.GetAxisRaw("Horizontal");
//holding down "D" makes the value positive and vice versa
if (hDirection < 0)
{
rb.velocity = new Vector2(-speed, rb.velocity.y);
transform.localScale = new Vector2(-1, 1);
}
else if (hDirection > 0)
{
rb.velocity = new Vector2(speed, rb.velocity.y);
transform.localScale = new Vector2(1, 1);
}
else
{
}
if (Input.GetButtonDown("Jump") && isGrounded == true)
{
Jump();
}
}
private void Jump()
{
rb.velocity = new Vector2(rb.velocity.x, jumpforce);
state = State.jumping;
jumpCount += 1;
}
private void GroundCheck()
{
Debug.DrawRay(transform.position, Vector2.down * hitDistance, Color.green);
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, hitDistance, ground);
if(hit.collider != null)
{
isGrounded = true;
jumpCount = 0;
}
else
{
isGrounded = false;
}
}
private void DoubleJump()
{
if (Input.GetButtonDown("Jump") && isGrounded == false && jumpCount < 2)
{
rb.velocity = new Vector2(rb.velocity.x, jumpforce);
jumpCount += 1;
}
}
Hey Have you made sure your player's layer isn't ground layer or set ground layermask properly or maybe the hitDistance for the raycast is too high it should be very low like 0.1 or less or does jumpCount start from 0 or 1 try and alternate that or maybe have it start from two to lose the extra bonus jump...These would be where I would look, Good luck!
So I'm trying to add a dash mechanic to a game character im building. However for some reason i can't get the game objects velocity to actually change. I tried using addForce which worked, but i had to add a lot in order to get the desired effect and that behaved strangely sometimes!
Do i need to do anything else to the game objects velocity than i already doing?
Heres my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public float dashSpeed;
private int dashDirection;
private float dashCoolDown;
public float startDashCoolDown;
private float dashTime;
public float startDashTime;
public GameObject dashEffect;
public float speed;
public float jumpForce;
private float moveInput;
private Rigidbody2D rb;
private bool isFacingRight = true;
private Animator anim;
private bool isGrounded;
public Transform groundCheck;
public float checkRadius;
public LayerMask whatIsGround;
private int extraJumps;
public int extraJumpsValue;
public GameObject dustEffect;
public GameObject trailEffect;
private void Awake()
{
// Setting up references.
isGrounded = transform.Find("GroundCheck");
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
}
void Start()
{
extraJumps = extraJumpsValue;
rb = GetComponent<Rigidbody2D>();
dashTime = startDashTime;
dashCoolDown = startDashCoolDown;
}
void FixedUpdate()
{
isGrounded = false;
// Check to see if grounded
Collider2D[] colliders = Physics2D.OverlapCircleAll(groundCheck.position, checkRadius, whatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
isGrounded = true;
anim.SetBool("Ground", isGrounded);
}
}
// Check if movement is allowed
if (!GameMaster.disableMovement)
{
// Move character
moveInput = Input.GetAxis("Horizontal");
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
Instantiate(trailEffect, groundCheck.position, Quaternion.identity);
anim.SetFloat("Speed", Mathf.Abs(moveInput));
}
// Flip character
if (isFacingRight == false && moveInput > 0)
{
Flip();
}
else if (isFacingRight == true && moveInput < 0)
{
Flip();
}
}
private void Update()
{
// Check if the player is grounded
if (isGrounded == true)
{
extraJumps = extraJumpsValue;
}
// Check if movement is allowed
if (!GameMaster.disableMovement)
{
// Check for jump
// If the player has more than one jump available
if (Input.GetKeyDown(KeyCode.Space) && extraJumps > 0)
{
isGrounded = false;
anim.SetBool("Ground", isGrounded);
rb.velocity = Vector2.up * jumpForce;
extraJumps--;
Instantiate(dustEffect, groundCheck.position, Quaternion.identity);
}
// If the player only has one jump available
if (Input.GetKeyDown(KeyCode.Space) && extraJumps == 0 && isGrounded == true)
{
isGrounded = false;
anim.SetBool("Ground", isGrounded);
rb.velocity = Vector2.up * jumpForce;
}
// Check for dash
if (dashCoolDown <= 0)
{
if (Input.GetKeyDown(KeyCode.LeftShift))
{
anim.SetBool("Dash", true);
Dash();
dashTime = startDashTime;
}
}
else
{
dashCoolDown -= Time.deltaTime;
}
}
}
void Dash()
{
if (dashTime <= 0)
{
dashCoolDown = startDashCoolDown;
anim.SetBool("Dash", false);
}
else
{
dashTime -= Time.deltaTime;
if (isFacingRight)
{
rb.velocity = Vector2.right * dashSpeed;
}
else if (!isFacingRight)
{
rb.velocity = Vector2.left * dashSpeed;
}
}
}
void Flip()
{
isFacingRight = !isFacingRight;
// Multiply the player's x local scale by -1.
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
If you dont get the desired dash effect with Rigidbody.velocity, you can try using Rigidbody.addForce(). I know you said you already used it, but there are multiple different force modes you can apply here. I would suggest using this one, because it applies full force from the start and then drops it off. You can read more about it yourself here.
So you could modify your code like so:
void Dash()
{
if (isFacingRight)
{
rb.AddForce(Vector2.right*dashSpeed, ForceMode.VelocityChange);
}
else if (!isFacingRight)
{
rb.AddForce(Vector2.left*dashSpeed, ForceMode.VelocityChange);
}
}
Note, that you also dont need to call dash repeatedly to falloff the velocity. this function should now be only called onse the button to dash (shift) has been pressed.
Hope this helped!
I'm making a 2D platformer in Unity, and made a patrolling enemy with code from a tutorial video. The enemy basically moves randomly to different spots in the scene. But how can I make the sprite turn around?
This is my code so far. I've tried with different approaches, but not getting the expected behavior.
public float speed = 10f;
private float waitTime;
public float startWaitTime = 1f;
public Transform[] moveSpots;
private int randomSpot;
private bool moving = true;
private bool m_FacingRight = true;
void Start()
{
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Length);
}
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, speed * Time.deltaTime);
if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f)
{
//Debug.Log(m_FacingRight);
// if (moving.x > 0 && !m_FacingRight)
// {
// Debug.Log("moving right");
// Flip();
// }
// else if (moving.x < 0 && m_FacingRight)
// {
// Debug.Log("moving left");
// Flip();
// }
if (waitTime <= 0)
{
//moving = true;
randomSpot = Random.Range(0, moveSpots.Length);
waitTime = startWaitTime;
}
else
{
//moving = false;
waitTime -= Time.deltaTime;
}
}
}
//private void Flip()
//{
//m_FacingRight = !m_FacingRight;
//transform.Rotate(0f, 180f, 0f);
//}
**********************************EDIT****************************************
I ended up with this for the enemy script movement
private bool facingRight = true;
private Rigidbody2D rigidBody2D;
private SpriteRenderer spriteRenderer;
public Vector2 speed = new Vector2(10, 0);
public Vector2 direction = new Vector2(1, 0);
private void Awake()
{
rigidBody2D = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.CompareTag("Wall") || collision.collider.CompareTag("Player"))
{
direction = Vector2.Scale(direction, new Vector2(-1, 0));
}
if (!collision.collider.CompareTag("Ground"))
{
if (!facingRight)
{
Flip();
}
else if (facingRight)
{
Flip();
}
}
}
void FixedUpdate()
{
Vector2 movement = new Vector2(speed.x * direction.x, 0);
movement *= Time.deltaTime;
transform.Translate(movement);
}
private void Flip()
{
facingRight = !facingRight;
if (!facingRight)
{
spriteRenderer.flipX = true;
}
else if (facingRight)
{
spriteRenderer.flipX = false;
}
}
Rewrite your Flip function to
private void Flip()
{
m_FacingRight = !m_FacingRight;
GetComponent<SpriteRenderer>().flipX = true;
}
Also, if you're looking for a reference, I made a platformer in Unity that includes enemy patrolling https://github.com/sean244/Braid-Clone
In a sidescroller, an easy way to achieve this is to use SpriteRenderer.flipX.
For instance, if you want to flip X when the velocity is negative:
var sr = GetComponent<SpriteRenderer>();
sr.flipX = velocity.x < 0;
I use Unity 5.1.1 on a Win 64 bit machine, more than capable to run what i'm creating of games. In the making of a 2D sidescroller, i found my character sometimes doesn't jump when prompted. Here is the code:
public float speed;
public float MomentAcc;
private float moveVertical;
private float score;
private float scoreP;
public GameObject wallRight;
public GUIText scoreText;
public bool touching;
void Start() {
MomentAcc = 10;
score = 0;
}
//Jump limiter
void OnCollisionStay2D() {
touching = true;
}
void OnCollisionExit2D() {
touching = false;
}
void Update() {
if (Input.GetKeyDown(KeyCode.W) && touching == true || Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began && touching == true) {
moveVertical = 29;
} else {
moveVertical = 0;
}
}
void FixedUpdate () {
scoreP = GameObject.Find ("Ball").GetComponent<Rigidbody2D> ().position.x + 11;
if(scoreP > score) {
score = score + 10;
}
UpdateScore ();
if(GetComponent<Death>().startGame == true) {
float moveHorizontal = 5;
Vector2 forward = new Vector2 (moveHorizontal, 0);
Vector2 jump = new Vector2 (0, moveVertical);
//Maxspeed limit
GetComponent<Rigidbody2D> ().AddForce (moveVertical * jump);
speed = moveHorizontal * MomentAcc * Time.deltaTime * 5;
if (GetComponent<Rigidbody2D> ().velocity.x < 7.000000) {
GetComponent<Rigidbody2D> ().AddForce (Vector2.right * speed);
if(GameObject.Find ("wallRight").GetComponent<wallRightScript>().wallJumpRight == true) {
GetComponent<Rigidbody2D> ().AddForce (new Vector2 (-420, 300));
}
if(GameObject.Find ("wallLeft").GetComponent<wallLeftScript>().wallJumpLeft == true) {
GetComponent<Rigidbody2D> ().AddForce (new Vector2(420, 150));
}
}
}
}
void UpdateScore() {
scoreText.text = "Score: " + (score );
}
}
(Sidenote: wallLeft/wallRight are for walljumping)
Here is your problem!
you are using Input.GetKeyDown(KeyCode.W) && touching == true in this case your jump is dependent on touching variable which can be false at the time when you press the "W" key. You are using rigidbody you cannot expect it to always colliding with ground when it is being dragged in horizontal. So you may need to change your implementation for ground check.
This Tutorial is good for learning about 2D character.
And one more advice! try to store reference of objects/components in some variables to access them easily. Using GetComponent<>/GameObject.Find() in Update()/FixedUpdate() is not efficient so not a good practice.