Object not orienting correctly - c#

I have a small script that causes an object to bounce back and forth. It is a bird for an upwards scrolling endless runner. So it represents its flight path. This script moves it from one end to the other and when it reaches the end it flips the 2D sprite and travels in the opposite direction. It works most of the time. But the problem is that sometimes the image flips twice so now it looks like its flying backwards until it does it again. Each time it does it it appears to be random.
public class Fly : MonoBehaviour {
private bool dirRight = false;
public float speed;
public bool facingRight = false;
void Start (){
speed = Random.Range (15.0f, 22.0f);
}
void Update () {
if(transform.position.x >= 25.0f) {
dirRight = false;
Flip();
}
if(transform.position.x <= -25.0f) {
dirRight = true;
Flip();
}
if (dirRight)
transform.Translate (Vector2.right * speed * Time.deltaTime);
else
transform.Translate (-Vector2.right * speed * Time.deltaTime);
}
void Flip()
{
// Switch the way the player is labelled as facing
facingRight = !facingRight;
// Multiply the player's x local scale by -1
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
I modified the if statements and use my bools as well as the position as such:
if(transform.position.x >= 25.0f && dirRight == true) {
dirRight = false;
Flip();
}
if(transform.position.x <= -25.0f && dirRight == false) {
dirRight = true;
Flip();
}
I am running it now and waiting to see if it works.

you are calling Flip() method based on position. and position is updated per frame. So it takes time to Lerp from >=25 to <25 so in every frame when position is >= 25 or <= -25 it calls to Flip(). So you need to add another check for calling Flip(). May be facingright == true will work.

Related

Weird rb.velocity.y

When I'm moving left or right rb.velocity.y changes to weird numbers. How can I get rid of this?
I want to change the gravity when player is jumping and because of this bug it changes even if player is moving left and right.
void FixedUpdate(){
isGrounded = Physics2D.BoxCast(coll.bounds.center,coll.bounds.size, 0, Vector2.down, .1f,WhatIsGround);
rb.velocity = new Vector2(moveInput * speed, rb.velocity.y);
if(jumped){
rb.AddForce(Vector2.up * jump, ForceMode2D.Impulse);
jumped = false;
}
if(rb.velocity.y < 0){
rb.gravityScale = fallMultiplier;
}
else if(rb.velocity.y > 0 && !(Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.UpArrow))){
rb.gravityScale = lowJumpMultiplier;
}
else{
rb.gravityScale = 1f;
}
}
Both floating point calculations and Unity physics aren't precise. When your Rigidbody is moving, the gravity is trying to push it into the ground collider, while collision detection is pushing it upwards. This results in tiny oscillations in velocity.
You should never use direct comparison when working with float values. In this case, you need a small threshold to reliably detect the Y velocity direction:
if(rb.velocity.y < -.1f)
{
rb.gravityScale = fallMultiplier;
}
else if (rb.velocity.y > .1f && !(Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.UpArrow)))
{
rb.gravityScale = lowJumpMultiplier;
}
else
{
rb.gravityScale = 1f;
}

How can I refactor my 2d unity movement script to resolve the behavioral issues I have?

Below is the code I've written for my 2D movement:
void HandleInput()
{
float verticalMoveAmount = Input.GetAxis("Vertical") * playerSpeed * Time.deltaTime;
float horizontalMoveAmount = Input.GetAxis("Horizontal") * playerSpeed * Time.deltaTime;
if (facingRight)
{
transform.Translate(horizontalMoveAmount, verticalMoveAmount, 0);
}
else
{
transform.Translate(-horizontalMoveAmount, verticalMoveAmount, 0);
}
if (horizontalMoveAmount > 0 && !facingRight)
{
Flip();
}
else if (horizontalMoveAmount < 0 && facingRight)
{
Flip();
}
if (Input.GetKeyDown(KeyCode.Space) && hasBall)
{
Shoot();
}
}
void Flip()
{
facingRight = !facingRight;
transform.Rotate(0f, 180f, 0f);
}
I have the below problems though:
I have a Cinemachine virtual camera following the player around. However, whenever the player changes direction they vanish from the camera view. I think this is something to do with the Flip(), but I don't know why or how to fix it.
The if statement for if facingRight where I have to use negative movement on the horizontal axis, this feels like a really poor way to handle it, but if I don't do that I can't move left when the player changes directions to the left. Is there a better way I can do this?
Thank you in advance.
To 1) my guess is that since you rotate the object by 180° you are looking at the backface of it -> it is not being rendered due to backface culling.
To 2) since you rotate the object by 180° it's local coordinate system is now pointing in the other direction. Note that by default Transform.Translate works in the local coordinate system. If you want to rather use global axes then simply pass in
transform.Translate(horizontalMoveAmount, verticalMoveAmount, 0, Space.World);
In general simply assuming you are using a SpriteRenderer which is the most common thing for 2D games you should rather use the property SpriteRenderer.flipX and not rotate your object at all. This would solve both issues at the same time
So together your code could be simply
public SpriteRenderer spriteRenderer;
void HandleInput()
{
var input = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
// ensure that diagonal movement isn't faster
input = Vector2.ClampMagnitude(input, 1f);
var movement = input * playerSpeed * Time.deltaTime;
transform.Translate(movement, Space.World);
// basically the same now as
//transform.position += movement;
if (input.x != 0)
{
spriteRenderer.flipX = input.x < 0;
}
if (hasBall && Input.GetKeyDown(KeyCode.Space))
{
Shoot();
}
}

player doesnt flip after animations are added

animator image
so im new in unity and im trynig to make my first game. so i made a code for flipping the player and it worked good, but when i added animations to the player it just stopped working! here is everything in my code relatable to the topic:
public bool facingLeft = false;
void flip()
{
facingLeft = !facingLeft;
facingRight = !facingRight;
Vector3 Scaler = transform.localScale;
Scaler.x *= -1;
transform.localScale = Scaler;
}
void FixedUpdate()
{
if (facingLeft == true && moveInput < 0)
{
flip();
}
if (facingRight == true && moveInput > 0)
{
flip();
}
}
pls help, thx
This is because you do define your animator but dont use it in the flip, you could or make it so that in the animation that the player moves and rotates accordingly to your stuff. like set the animation position itself.

Unity 2D Jump script

So I was trying to implement double jumping in my game, which doesn't work. And now, somehow, not only can't my players double jump, they can't even jump either!
update: they can jump now, still can't double jump though.
This is my whole movement script:
using UnityEngine;
namespace Players
{
public class Actor : MonoBehaviour
{
//in order to control both players using 1 script.
public int playerIdx;
//Variables.
public float movementSpeed = 150f;
public float jumpForce = 250f;
//Ground stuff.
public LayerMask whatIsGround;
public bool grounded;
//boolean stuff.
private bool facingRight;
private bool moving;
//Needed to check if player is on the ground.
public Transform groundCheck;
//Limit player's movement speed.
public float maxMovementSpeed = 400f;
//Double jump stuff.
private bool doubleJumpReady;
//rb
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
doubleJumpReady = true;
rb = GetComponent<Rigidbody2D>();
facingRight = true;
}
// Update is called once per frame
void FixedUpdate()
{
SlowDown();
}
private void LateUpdate()
{
grounded = Physics2D.OverlapCircle(groundCheck.position, 0.1f, whatIsGround);
if (grounded)
doubleJumpReady = true;
}
private void SlowDown()
{
if (moving) return;
//if player is not moving, slow them down.
if (rb.velocity.x > 0.2f)
rb.AddForce(movementSpeed * Time.deltaTime * -Vector2.right);
if (rb.velocity.x < -0.2f)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right);
}
public void Move(int dir)
{
//Flip the player.
Flip(dir);
//Moving the player.
moving = true;
float xVel = rb.velocity.x; //Get x velocity.
if ( dir > 0)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right * dir);
else if (dir < 0)
rb.AddForce(movementSpeed * Time.deltaTime * Vector2.right * dir);
else if (dir == 0) { } //do nothing.
//Help player turn around faster.
if (xVel > 0.2f && dir < 0)
rb.AddForce(movementSpeed * 3.2f * Time.deltaTime * -Vector2.right);
if (xVel < 0.2f && dir > 0)
rb.AddForce(movementSpeed * 3.2f * Time.deltaTime * Vector2.right);
}
private void Flip(int dir)
{
if (facingRight && dir == -1 || !facingRight && dir == 1)
{
facingRight = !facingRight;
transform.Rotate(0f, 180f, 0f);
}
}
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
grounded = false;
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
}
}
}
}
I don't know if it is because of my jump script, or my player script:
void Update()
{
if (playerIdx == 1)
{
if (Input.GetKey(KeyCode.A))
Move(-1);
if (Input.GetKey(KeyCode.D))
Move(1);
if (Input.GetKey(KeyCode.W))
Jump();
}
if (playerIdx == 2)
{
if (Input.GetKey(KeyCode.LeftArrow))
Move(-1);
if (Input.GetKey(KeyCode.RightArrow))
Move(1);
if (Input.GetKey(KeyCode.UpArrow))
Jump();
}
}
So how can I fix this?
as far as i can see you never reset the
doubleJumpReady = false;
Variable. To fix this simply change the jump code to:
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
grounded = false;
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
}
}
Hope it works ;).
EDIT:
grounded is set by overlapping spheres. Therefore no need to set it here.
Use this code and press your jump btn 2 times and see if the Debug.Log message shows up. Also, your player ID (idx is not needed.) As far as i can see your script is attached two to different objects. Therefore their variables are not shared anyways.
protected void Jump()
{
if (grounded)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = true;
}
else if (!grounded && doubleJumpReady)
{
rb.AddForce(Vector2.up * jumpForce);
doubleJumpReady = false;
Debug.Log("I am double jumping");
}
}
And the final problem is, you do not execute one of your jumps you execute both at once.
THis happens due to your execution.
Input.GetKey(KeyCode.UP)
instead use:
Input.GetKeyDown(KeyCode.Up);
GetKeyDown returns true when the button is pressed.
GetKey returns true WHILE the button is pressed.
Hope it works now ;)
I would implement it with a counter, you can set the number of jumps you want.
The code would be like this:
jumpCount = 0;
protected void Jump()
{
if(!grounded && jumpCount < 2)
{
jumpCount++;
rb.AddForce(Vector2.up * jumpForce);
}
if(grounded)
jumpCount = 0;
}
Going off the assumption that you can now perform the normal jump again after reading the comments. I think the reason you can't 'double jump' is that when you call the Jump() method, you don't just call it once, you call it twice, so what happens is the player jumps and then immediately double jumps and so you don't actually notice that the double jump has occurred. You could make it so that your doubleJumpReady boolean is only true after a set amount of time after you have jumped initially using some sort of co-routine or something I implemented for a sort of double jump mechanic once was that the user could press the jump button again to double jump only when the player had reached the maximum height of the initial jump or after.

Basic C# Unity2D movement script not functioning

Hi there fellow Overflowers!
I have recently dived into C# in Unity, because I believe that it has more functionality than UnityScript, and I come from a C++ background. Referencing some code from a 2D script in the Sample Assets, I have tried to create my own. The code is below:
using UnityEngine;
public class PlayerControl : MonoBehaviour {
//Variables
[HideInInspector]
public bool facingForward = true; //for Flip() Function
bool isGround = true; //for Grounded() Function
public float maxSpeed = 5.0f; //Terminal sideways velocity
public float HorizonAxis; //Checks for a/d movement
public float jumpFloat = 1000.0f; //Modular, use Unity Editor
public float moveFloat = 400.0f; // " "
void Start() {
//transform.position(0,0,0);
}
void Flip() {
facingForward = !facingForward; //switches boolean
Vector3 theScale = transform.localScale; //assigns vector to localscale of Player
theScale.x *= -1; //if x = 1, position becomes -1 and thus flips
transform.localScale = theScale; //reassigns the localscale to update theScale
}
bool Grounded() {
if (transform.position.y > 1) { //if position of gameObject is greater that 1, not grounded
isGround = false;
} else {
isGround = true;
}
return isGround; //function returns true or false for isGround
}
void Update() {
HorizonAxis = /*UnityEngine.*/Input.GetAxis ("Horizontal"); //assigns HorizonAxis to a/d movement from UnityEngine.Input
if (HorizonAxis * rigidbody2D.velocity.x > maxSpeed) { // if Input a/d by current x velocity of gameObject is greater than maxSpeed
rigidbody2D.velocity = new Vector2 (Mathf.Sign (rigidbody2D.velocity.x) * maxSpeed, rigidbody2D.velocity.y); //1 or -1 times the max speed, depending on direction
}
else if (HorizonAxis * rigidbody2D.velocity.x < maxSpeed) { //if Input a/d is less than terminal velocity
rigidbody2D.AddForce(Vector2.right * HorizonAxis * moveFloat); //add force to the right equivilant to Input by scalar moveFloat
}
if (Input.GetButtonDown ("Jump")) { //If Space
if(isGround) { //and isGround returns true
rigidbody2D.AddForce(new Vector2(0.0f, jumpFloat)); //add upwards force to bottom of rigidbody2D
isGround = false; //Resets isGround value
}
}
if (HorizonAxis > 0 && !facingForward) {//if UnityEngine.Input is to the right and facing left
Flip (); //execute
}
else if (HorizonAxis < 0 && facingForward) { //else
Flip (); //execute
}
}
}
Unfortunately, the code just doesn't work. I get no compile errors, but any Input does not effect the current position of the character. Should I be using transform.Translate to change the position, or stick with AddForce to a Vector2 until the character hits a maxSpeed?
Thanks heaps :)
I (kinda) fixed the jerky jumping issue, basically you look for the input in the Update() function which switches a Bool in FixedUpdate()
void Update () {
if (Input.GetKeyDown (KeyCode.Space) && playerGrounded) {
playerJumped = true;
}
}
Then in FixedUpdate() I looked for this Bool and did my AddForce
void FixedUpdate () {
if (playerJumped) {
playerJumped = false;
rigidbody2D.AddForce (new Vector2 (0, jumpForce),ForceMode2D.Impulse);
playerGrounded = false;
}
}
Setting playerJumped to false makes sure it doesn't run several times and the player can't jump again because I also set the grounded to false. grounded gets set back to true when the player collides with things tagged "ground".
I'm still new to Unity and C# overall so I can't guarantee this is the best (or even a good) way. Hope I could help somehow though ;)

Categories