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;
}
}
Related
I am using an overlap box to detect whether an arrow hits the ground or an enemy, the arrow hitting the enemy works, it's that often the arrow will just pass through the ground, not sure if I am missing something.
Heres my code for detecting the ground or enemy.
private void FixedUpdate()
{
damageHit = Physics2D.OverlapBox(damagePosition.position, damageSize, whatIsEnemy);
groundHit = Physics2D.OverlapBox(damagePosition.position, damageSize, whatIsGround);
if (!hasHitGround)
{
if (damageHit)
{
Collider2D[] detectedObjects = Physics2D.OverlapBoxAll(damagePosition.position, damageSize, whatIsEnemy);
foreach (Collider2D collider in detectedObjects)
{
IDamageable damageable = collider.GetComponent<IDamageable>();
if (damageable != null)
{
damageable.Damage(weaponData.attackDamage);
Destroy(gameObject);
}
IKnockbackable knockbackable = collider.GetComponent<IKnockbackable>();
if (knockbackable != null)
{
knockbackable.KnockBack(weaponData.knockbackAngle, weaponData.knockbackStrength, (int)Mathf.Sign(transform.rotation.y));
}
}
}
if (groundHit)
{
rb.gravityScale = 0f;
rb.velocity = Vector2.zero;
hasHitGround = true;
Destroy(gameObject, 10f);
}
else if (Mathf.Abs(xStartPos - transform.position.x) >= travelDistance && !isGravityOn)
{
isGravityOn = true;
rb.gravityScale = gravity;
}
}
}
private void OnDrawGizmos()
{
Gizmos.DrawWireCube(damagePosition.position, damageSize) ;
}
I thought that the hitbox may have been to small and it would just pass through wall due to not hitting it on any frame. After making the hitbox larger it still did not help, here you can see that even though the overlap box is overlaping the collider the arrow will continue on.
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.
I created a function in Unity that is supposed to allow the character to climb. It creates two problems, first of all it somehow interacts with the general movement function. When the character starts running their animation won't stop even when the player isn't moving them. Second of all the character can climb up and down the ladder but won't get off them, even though technically the logic is constructed in such a way that they should just go back to their normal state.
I have tried turning off the climb function in the Update() function so I know the running problem is caused by it, because it works fine without it.
private void Climb()
{
RaycastHit2D ladder = Physics2D.Raycast(transform.position, Vector2.up, 5, whatIsLadder);
float hDirection = Input.GetAxisRaw("Horizontal");
float vDirection = Input.GetAxisRaw("Vertical");
if (ladder.collider != null)
{
if (vDirection > 0.1f)
{
isClimbing = true;
}
}
else
{
if (hDirection > 0.1f)
{
isClimbing = false;
}
}
if (isClimbing == true && ladder.collider != null)
{
rb.gravityScale = 0;
rb.velocity = new Vector2(rb.velocity.x, climbSpeed * vDirection);
if (Mathf.Abs(vDirection) > 0.1f)
{
anim.speed = 1f;
}
else
{
anim.speed = 0f;
}
}
else
{
rb.gravityScale = naturalGravity;
}
}
I'll also give a link to the whole PlayerController script since that might help some people:
https://github.com/Pacal2/Platformer/blob/master/Assets/Scripts/PlayerController.cs
Try resetting the velocity on the rigidbody when he stops climbing, near the end of the function:
//....
{
rb.gravityScale = naturalGravity;
}
into:
{
rb.gravityScale = naturalGravity;
rb.velocity = new Vector2(0.0f, 0.0f);
}
this code also looks suspect
if (ladder.collider != null)
{
if (vDirection > 0.1f)
{
isClimbing = true;
}
}
else
{
if (hDirection > 0.1f)
{
isClimbing = false;
}
}
change to:
if (ladder.collider != null)
{
if (vDirection > 0.1f || vDirection < -0.1f) //if allowed to climb down
{
isClimbing = true;
}
if (hDirection > 0.1f || hDirection < -0.1f) //moving left
{
isClimbing = false;
}
}
for animation speed try:
anim.speed = rb.velocity.x;
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?
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).