Trouble with jumping and remembering jump time - c#

I'm trying to make my character be able to jump whenever he is grounded OR if he's airborne to only be able to jump when he has extra jumps and x amount of time has passed.
Currenty I have this:´
void Jump()
{
jumpTime -= Time.fixedDeltaTime;
if ((jumpRemember > 0) && ((groundRemember > 0) || ((jumps>0) && (jumpTime <= 0))))
{
jumpRemember = 0;
groundRemember = 0;
rb.velocity = new Vector2(rb.velocity.x, jumpForce);
jumps--;
jumpTime = timeSinceLastJump;
}
}
(the jump remember and ground remember are checks to see if i pressed the jump button or was grounded in the last 0.1 seconds)
but when he is grounded and collides with a roof and get sent back to ground he cant jump after the time has passed anyways, even though I used the ''OR'' operator.

Try using Debug.Log(variable) to check the states of your variables.
"when he is grounded and collides with a roof and get sent back to ground" - What variables does this change?
Are any of these variables being changed unexpectedly when the character collides with the roof?
I would leave this in a comment but you need reputation to unlock that feature of this site.

An example how you could approach your issue.
const int MAX_JUMPS = 2;
const FLOAT JUMP_TIMER = 1;
const float JUMP_FORCE = 100;
int jumps = 2;
float nextJump = 0;
bool grounded = true;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
TryJump();
}
void TryJump()
{
if (grounded || (jumps > 0 && nextJump < Time.time))
{
Jump();
}
}
void Jump()
{
rb.velocity = new Vector2(rb.velocity.x, JUMP_FORCE);
jumps--;
nextJump = Time.time + JUMP_TIMER;
}
void Grounded()
{
grounded = true;
jumps = MAX_JUMPS;
}
void Airborne()
{
grounded = false;
}
void OnCollisionEnter(Collision col)
{
if (col.tag == "Floor")
Grounded();
}
void OnCollisionExit(Collision col)
{
if (col.tag == "Floor")
Airborne();
}

I think you have misplaced parenthesis. You want both of the first two true or both of the second two right?
if ((jumpRemember > 0) && ((groundRemember > 0) || ((jumps>0) && (jumpTime <= 0))))
should it be?
if ((jumpRemember > 0 && groundRemember > 0) || (jumps>0 && jumpTime <= 0))
That second parenthesis in front of groundRemember is causing it to be grouped with the two to the right of the or statement. You are requiring remember all the time and then either ground remember > 0 OR the other two to both be true. It doesn't sound like that is what you are intending. Is it?

Related

Endless Runner: When I swipe up to jump, the player jumps but then moves left or right on the single up swipe

I am making an endless runner mobile game. The PC controls work perfectly and the Touch/Swipe controls for Left and Right work too. The problem is when I swipe up to jump, the player jumps but then also either moves left or right (seemingly at random). For the life of me I cannot figure it out. This is my first C# project so my code/game is Frankenstein of tutorials and google searches. I found out about the rigidbody component a little too late but I don't want to start using it now if I don't have to... Please help, I am at a total loss. I would also like to apologise in advance if my code is extremely messy and incoherent, I have tried my best. Here is my Player movement script:
PC Controls
public class PlayerMove : MonoBehaviour
{
public float moveSpeed = 8;
public float leftRightSpeed = 7;
static public bool canMove = false;
public KeyCode moveL;
public KeyCode moveR;
public float horizVel = 0;
public int laneNum = 2;
public string controlLocked = "n";
private float speedUpTime;
private float waitTime = 0.45f;
private Vector3 startTouchPosition;
private Vector3 endTouchPosition;
public GroundCheck groundCheck;
public float jumpForce=7;
public float gravity = -9.81f;
public float gravityScale = 3;
public float jumpCoolDown = 0.5f;
private float lastJumpTime = 0;
float velocity;
// Start is called before the first frame update
void Start()
{
speedUpTime = Time.time;
}
// Update is called once per frame
void Update()
{
if (Time.time - speedUpTime >= 10f)
{
moveSpeed += 1;
leftRightSpeed +=1;
waitTime -= 0.05f;
speedUpTime = Time.time;
}
transform.position += new Vector3(horizVel, 0, moveSpeed) * Time.deltaTime;
if((Input.GetKeyDown(moveL)) && (laneNum>1)&& (controlLocked == "n"))
{
horizVel = -leftRightSpeed;
StartCoroutine(stopSlide());
laneNum -= 1;
controlLocked = "y";
}
if((Input.GetKeyDown(moveR)) && (laneNum<3)&& (controlLocked == "n"))
{
horizVel = leftRightSpeed;
StartCoroutine(stopSlide());
laneNum += 1;
controlLocked = "y";
}
velocity += gravity * gravityScale * Time.deltaTime;
if (groundCheck.isGrounded && velocity < 0)
{
velocity = 0;
lastJumpTime = 0;
}
if (Input.GetKeyDown(KeyCode.Space) && (Time.time - lastJumpTime) > jumpCoolDown)
{
lastJumpTime = Time.time;
velocity = jumpForce;
}
transform.Translate(new Vector3(0, velocity, 0) * Time.deltaTime);
Touch Controls
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
startTouchPosition = Input.GetTouch(0).position;
}
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
{
endTouchPosition = Input.GetTouch(0).position;
// Check for horizontal swipe
if((endTouchPosition.x < startTouchPosition.x) && (laneNum>1)&& (controlLocked == "n"))
{
horizVel = -leftRightSpeed;
StartCoroutine(stopSlide());
laneNum -= 1;
controlLocked = "y";
}
if((endTouchPosition.x > startTouchPosition.x) && (laneNum < 3) && (controlLocked == "n"))
{
horizVel = leftRightSpeed;
StartCoroutine(stopSlide());
laneNum += 1;
controlLocked = "y";
}
// Check for vertical swipe
if ((endTouchPosition.y > startTouchPosition.y) && (Time.time - lastJumpTime) > jumpCoolDown)
{
lastJumpTime = Time.time;
velocity = jumpForce;
}
}
}
IEnumerator stopSlide()
{
yield return new WaitForSeconds(waitTime);
horizVel = 0;
controlLocked = "n";
}
}
I've been at it for so many hours, I don't even remember what I've tried. Either the player stops moving, Right becomes Left, Jump is Right, Left is jump, etc...
Since you said the touch-controls were the issue, this answer will be focused on your second block of code.
The reason seems to be because when a player swipes up, their finger will almost never be at the same x-position. To illustrate this, try swiping up on your screen in an exact perfect line.
Computers take things very literally. So even being off by 0.0000001 is significant enough to be counted as less/more.
So what does this mean? When you swipe up, your fingers x and y position will change - causing both if-statements to activate
A fix that wouldn’t be too time-draining would be to create a dead-zone for swipes.
To put it simply, a dead-zone is a threshold that must be passed in addition to the action.
Here is an example of a dead-zone:
if(endPosition < startPosition - 2) { <SNIPPED> }
# ^ THIS IS THE DEADZONE

How to start an animation of some object while destroying other object?

I want to start the animation when destroying another game object. How is this possible? To have this in mind I was trying to use setActive() in the else statement where the object is destroyed. However, nothing happens, only it does activate when I put it inside if(target). So I'm trying something like this:
public void Update()
{
anim = GetComponent<Animator>();
anim.SetBool("isWalking", isWalking);
if (target)
{
bar.fillAmount = (float)health / baseHealth;
float distance = Vector3.Distance(transform.position, target.transform.position);
if (distance >= attackRange && isAttacking)
{
isWalking = true;
agent.SetDestination(target.transform.position);
}
if (distance - 1 <= attackRange)
{
isWalking = false;
agent.ResetPath();
}
if (distance - 1.5 <= attackRange && Random.value < Time.deltaTime && Time.time > lastAttackedAt + cooldown && agent.remainingDistance <= agent.stoppingDistance)
{
isAttacking = true;
isWalking = false;
Attack();
lastAttackedAt = Time.time;
anim.SetTrigger("isAttacking");
}
}
else
{
OnDeath();
spawnPortal.SetActive(true);
}
}
The object is well destroyed but still the animation does not appear. It remains hidden (unchecked)...

Unity2D using coroutines for tracking when the player is turning?

I am using skeletons to animate the player. I have 3 fundamental skeletons to transition between when the player turns:
Player in profile,
player turning and
player facing-the-camera
to face left or right, the renderer is simply rendered mirror-image using:
if (movement > 0) transform.localScale = new Vector2(1f, 1f);
if (movement < 0) transform.localScale = new Vector2(-1f, 1f);
however, capturing the intermediate state where a player is moving from right to left (or vice versa) is proving tricky.
I setup a 3 renderers to operate as below:
void Start()
{
rightRenderer.enabled = true;
turningRenderer.enabled = false;
centerRenderer.enabled = false;
}
and I had been operating on the assumption that a coroutine could be used to measure the movement of Input.GetAxis("Horizontal"); from left-to-right (or vice versa). So I put together various experiments based around the below:
private List<float> trackedMovement = new List<float>();
private bool isTurning;
private float speed = 0f;
private int turningCounter = 0;
public IEnumerator countdownTurn()
{
while (0 < turningCounter--)
{
if (turningCounter == 0)
{
StopCoroutine("countdownTurn");
break;
}
yield return new WaitForSeconds(0.2f);
}
}
public IEnumerator turn()
{ // speed can be between 0 and 2.5f;
if (speed > 0 && speed <= 0.5f)
{
while (speed != 0)
{
trackedMovement.Add(movement);
trackedMovement.ForEach(f =>
{
if (
((f > 0 && movement < 0) ||
(f < 0 && movement > 0)))
{
isTurning = true;
trackedMovement = new List<float>();
turningCounter = 5;
StartCoroutine("countdownTurn");
}
});
yield return new WaitForSeconds(0.02f);
}
}
}
void Update()
{
StartCoroutine("turn");
speed = defaultAnimator.GetFloat("Speed");
turn();
}
the theory in my head was that turningCounter could demonstrate states of player by number
say I move from left to right:
turningCounter = 4 player is turning from left-towards-camera.
rightRenderer.enabled = false;
turningRenderer.enabled = true;
centerRenderer.enabled = false;
turningCounter = 3 || 2 player is facing camera.
rightRenderer.enabled = false;
turningRenderer.enabled = false;
centerRenderer.enabled = true;
turningCounter = 1 player is turning from camera-toward-right-profile.
rightRenderer.enabled = false;
turningRenderer.enabled = true;
centerRenderer.enabled = false;
turningCounter = 0 player is fully facing right.
rightRenderer.enabled = true;
turningRenderer.enabled = false;
centerRenderer.enabled = false;
all my experiments have yielded results that are inconsistent.
If I place the renderer routines inside the sub-coroutine countdownTurn, they don't always fire when the player turns left/right.
if I try and measure the turning counter in any update statement (I have tried standard, fixed and default without much success) I get stale feedback on the turningCounter value (ie. it sometimes gives me some of the countdown but not all of the countdown).
so my question is:
Are coroutines the best way to address this? if so, are there any recommendations on how I might get a clean and consistent turning counter value from them?
If coroutines aren't a good solution, are there any other methods people have taken to create the desired result?
[EDIT] as suggested by #Everts, use the current localscale as the basis for working out the change in direction.
if localscale.x < 0 and movement > 0 then we can surmise that the player wants to turn (for this contrived example). likewise is true for localscale.x > 0 and movement < 0.
so we are able to draft the following Update (I attach here a simplified version ignoring things like crouching mechanics etc.):
void Update()
{
movement = Input.GetAxis("Horizontal");
if (((transform.localScale.x > 0 && movement < 0) ||
(transform.localScale.x < 0 && movement > 0))
&& !isTurning)
{
isTurning = true;
turningCounter = 5;
StartCoroutine("countdownTurn"); // simply ticks down turningCounter every 0.n seconds
}
if (turningCounter == 3) setRenderDirection(); // ie. routine for transforming localscale (mirroring the image)
// show player in profile at end of counter
profileRenderer.enabled = turningCounter < 1;
// show player turning towards camera on 4 and away from camera on 1
turningRenderer.enabled = turningCounter == 4 || turningCounter == 1;
// show player looking dead center for 2 counts
centerRenderer.enabled = turningCounter == 2 || turningCounter == 3;
if (turningCounter < 1)
{
isTurning = false;
defaultAnimator.SetBool("isTurning", false);
}
}

Why does mashing jump let the player jump twice?

I'm having an issue where if the player mashes the jump button fast enough, they get an extra jump.
I'm pretty sure it has to do with my implementation of coyote time since it's letting the player jump even when slightly off the ground, but I'm not sure how I could change it to fix this issue without removing the mechanic entirely.
Here's the code I'm using for jumping.
//Check if player is grounded
IsGrounded = Physics2D.OverlapCircle(GroundCheck.position, 0.1f, GroundLayer);
//Coyote Jump
if (IsGrounded == true)
{
HangCount = HangTime;
}
else if(IsGrounded == false)
{
HangCount -= Time.deltaTime;
}
//Jump Buffer
if (Input.GetButtonDown("Jump"))
{
JumpBufferCount = JumpBufferLength;
}
else
{
JumpBufferCount -= Time.deltaTime;
}
//Jump
if (JumpBufferCount >= 0 && HangCount > 0)
{
RB.velocity = new Vector2(RB.velocity.x, JumpHeight);
FindObjectOfType<AudioManager>().Play("Jump");
HangCount = 0;
JumpBufferCount = 0;
}
}
}
Found a solution. I just added a check to see if my Y velocity was equal to or less than 0 so the player couldn't jump while already ascending.

Implementing ladders in unity 2D

I am trying to implement ladder climbing functionality in unity and i have achieved it to some degree.I have put circular collider on the top of the characters head so it detects when the ladder is above his head. what i want to do is that if i press the upward key it only climbs one step of the ladder and stays there..But instead the character falls as soon as i stop pressing the upward key and keeps going up if i press it one time..I have messed with the gravity of the rigidbody but no luck.
void Update()
{
if((isgrounded || !doublejump) && Input.GetKey(KeyCode.Space) )
{
anim.SetBool( "Ground",false);
rigidbody2D.AddForce(new Vector2(0,jumpforce));
if(!doublejump && !isgrounded)
doublejump = true;
}
if(Ladder && Input.GetAxis("Vertical")>0)
{
rigidbody2D.gravityScale =0;
rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x,Input.GetAxis("Vertical")*maxspeed);
}
if(!Ladder)
{
rigidbody2D.gravityScale =1;
}
}
Solved it.any body wondering this was the answer.
void Update()
{
if((isgrounded || !doublejump) && Input.GetKey(KeyCode.Space) )
{
anim.SetBool( "Ground",false);
rigidbody2D.AddForce(new Vector2(0,jumpforce));
if(!doublejump && !isgrounded)
doublejump = true;
}
if(Ladder && Input.GetAxis("Vertical")>0)
{
anim.SetBool("LadderUp",true);
transform.Translate (new Vector2(0,0.2f) * Time.deltaTime*maxspeed);
rigidbody2D.gravityScale =0;
// rigidbody2D.velocity = new Vector2(rigidbody2D.velocity.x,Input.GetAxis("Vertical")*maxspeed);
}
if(!Ladder)
{
anim.SetBool("LadderUp",false);
rigidbody2D.gravityScale =1;
}
}

Categories