Ok so I'm building a platformer with two types of jump.
Normal jump - whilst on ground, pressing space bar
Air jump - whilst jumping, a limited amount of extra jumps (also whilst pressing space bar)
I've worked out the main mechanics for this jump, But I've hit a snag. the limited amount of airjumps starts as 3 each time you jump. However, with the code I've written, Unity is using the initial "normal jump" as one of the three.
Here is a sample of my code below:
bool pressingJumpButton = Input.GetKeyDown("space");
if (pressingJumpButton)
{
if (canJump)
{
jumping = true;
}
}
if (jumping)
{
if (pressingJumpButton && inAir == false) {
Debug.Log("jump");
GetComponent<Rigidbody>().velocity = new Vector3(
GetComponent<Rigidbody>().velocity.x,
jumpingSpeed,
GetComponent<Rigidbody>().velocity.z);
inAir = true;
}
}
//airJump logic
if(inAir==true)
{
airJump = true;
if (airJump && maxAir>0 && pressingJumpButton)
{
Debug.Log("airJump");
maxAir -= 1;
GetComponent<Rigidbody>().velocity = new Vector3(
GetComponent<Rigidbody>().velocity.x,
jumpingSpeed,
GetComponent<Rigidbody>().velocity.z);
}
}
// on the floor
void OnTriggerStay (Collider otherCollider)
{
if (otherCollider.tag =="JumpingArea")
{
canJump = true;
jumping = false;
inAir = false;
maxAir = 3;
airJump = false;
}
}
I put the debug.logs in to see if I could find the issue and when I'm doing the first jump (from the ground) its registering as both normal and air jumps.
I thought that by having an inAir bool that only returns true after pressing the jump button once would be the fix but no luck.
What am I doing wrong?
You need to combine your jumping and in air test and use an else clause. As it's written, you are doing the jump, setting inAir = true and then after that testing if inAir is true, meaning you are always doing an air jump after every normal jump.
if (jumping && !inAir)
{
Debug.Log("jump");
...
}
else if (inAir && jumping)
{
Debug.Log("airJump");
...
}
There is also no need to recheck pressingJumpButton since you've already tested that when setting jumping = true.
A (IMHO) better version that avoids repeated code and gets rid of unnecessary variables:
if (pressingJumpButton && canJump)
{
if (!inAir)
{
Debug.Log("jump");
inAir = true;
DoJump();
}
else if (maxAir > 0)
{
Debug.Log("airJump");
maxAir--;
DoJump();
}
}
private void DoJump()
{
GetComponent<Rigidbody>().velocity =
new Vector3(GetComponent<Rigidbody>().velocity.x,
jumpingSpeed,
GetComponent<Rigidbody>().velocity.z);
}
Related
The problem is that the player have animator and when idle it's playing some animation that make the player moving a bit.
I added to the terrain a ZeroFriction material but didn't change anything yet in the properties : Dynamic Friction , Static Friction , Bounciness are all set to 0 and Friction Combine is set to Multiply and Bounce Combine to Average.
Not sure if I should change something by script on this ZeroFriction to lock the player from moving or just to disable/enable the components on the player Third Person User Control and Third Person Character.
private void Update()
{
if (closeCarte == false)
{
var heading = transform.position - player.transform.position;
var dot = Vector3.Dot(heading, -transform.forward);
if (dot > 1)
{
var lookat = player.transform.position - securityKeyPadInteractable.transform.position;
lookat.y = 0;
if (lookat.magnitude <= interactableItem.distance && interactableItem != null)
{
if (!playAnimOnce)
{
if (ikControl.handFinishedMove == true)
{
if (securityKeyPad1 != null)
{
securityKeyPad1.SetActive(true);
}
if (virtualCam != null)
virtualCam.enabled = true;
freeLookCam2.enabled = false;
Cursor.visible = true;
camerasContorl.enabled = false;
// Here
playAnimOnce = true;
}
}
}
else if (playAnimOnce)
{
if (securityKeyPad1 != null)
{
securityKeyPad1.SetActive(false);
}
if (virtualCam != null)
virtualCam.enabled = false;
camerasContorl.enabled = true;
freeLookCam2.enabled = true;
Cursor.visible = false;
if (m_hasOpened == true)
{
//anim.Play("Crate_Close");
//StartCoroutine(dimLights.dimLightOverTime(0, 2f));
}
playAnimOnce = false;
if (securityKeypadSystem != null)
securityKeypadSystem.ResetCode();
}
}
else
{
securityKeyPad1.SetActive(false);
playAnimOnce = false;
}
}
}
At this point after this line :
camerasContorl.enabled = false;
Where I wrote // Here
I want to lock(prevent from the player to move) but also to make that if the player is pressing one of the movement keys it will release the player and will allow to move again.
At this place in the code it's showing big security keypad and the player should type some code the problem is that because the player is moving a bit even if the player is not pressing any movement keys he lose the touch with the security keypad and I need to move the player forward again to activate the security keypad again.
I want to prevent from the player to move/slide on the terrain but not to disable the movements.
The player have this components : Animator , Rigidbody(when running the game x,y,z on the freeze rotation is checked true and locked) , Capsule Collider , Third Person User Control and Third Person Character.
On the animation side, maybe have a look at if Root Motion is enabled which would actually "move" your object's transform.
Official ref: https://docs.unity3d.com/Manual/RootMotion.html
Using c#, im trying to fire a bullet every 3 seconds, so heres my workflow:
fire button is pressed
only fire if bool fireAgain is true
set bool fireAgain = false
start timer
timer finished = bool fireAgain = true
When debugging it seems to all work properly, but when I test it, Im still able to shoot like 10 bullets a second. So somehow it just doesnt care about the bool FireAgain being false and shoots anyway even if according to debug bool fireAgain is false at that moment.
public void Update()
{
//If LEFT MouseButton is pressed, cast yer spells.
if (fireAgain == true && Input.GetMouseButtonDown(0))
{
StartCoroutine("LoopRotation");
fireAgain = false;
Debug.Log(fireAgain);
Debug.Log("1 should be FALSE");
}
while (fireAgain == false && timer < bulletTime)
{
fireAgain = false;
timer += Time.deltaTime;
Debug.Log(timer);
Debug.Log(bulletTime);
Debug.Log(fireAgain);
Debug.Log("2");
} if (timer >= bulletTime)
{
fireAgain = true;
timer = 0;
//Debug.Log("Timer is finished");
//Debug.Log(timer);
Debug.Log(fireAgain);
Debug.Log("3 should be true");
And here is the code for the Coroutine:
IEnumerator LoopRotation()
{
pivot.transform.Rotate(triggerAngle,0,0);
GameObject bullet = ObjectPooler.SharedInstance.GetPooledObject();
if (bullet != null) {
bullet.transform.position = SSpawn.transform.position;
bullet.transform.rotation = SSpawn.transform.rotation;
bullet.SetActive(true);
}
yield return new WaitForSeconds(.1f);
pivot.transform.rotation = Quaternion.Slerp(transform.rotation, originalRotationValue, Time.deltaTime * rotationResetSpeed);
StopCoroutine("LoopRotation");
}
Enumerator LoopRotation was originally just to pivot the weapon a few degrees forwards and then backwards so it looks like a wack when you cast a spell, but now its also the shoot function, as it creates bullets.
You have a while loop within Update => this loop will completely run in one single frame => "immediately" will increase the timer until it is big enough => "immediately" will set your bool flag to true again!
What you rather would do is e.g.
public void Update()
{
//If LEFT MouseButton is pressed, cast yer spells.
if (fireAgain && Input.GetMouseButtonDown(0))
{
StartCoroutine(LoopRotation());
fireAgain = false;
timer = 0;
Debug.Log(fireAgain);
Debug.Log("1 should be FALSE");
}
else if(timer < bulletTime)
{
// Only increase this ONCE per frame
timer += Time.deltaTime;
Debug.Log(timer);
Debug.Log(bulletTime);
Debug.Log(fireAgain);
Debug.Log("2");
if(timer >= bulletTime)
{
fireAgain = true;
timer = 0;
//Debug.Log("Timer is finished");
//Debug.Log(timer);
Debug.Log(fireAgain);
Debug.Log("3 should be true");
}
}
}
As alternative you could use Invoke and skip the timer in Update completely:
public void Update()
{
//If LEFT MouseButton is pressed, cast yer spells.
if (fireAgain && Input.GetMouseButtonDown(0))
{
StartCoroutine(LoopRotation());
fireAgain = false;
Invoke (nameof(AllowFireAgain), bulletTme);
}
}
private void AllowFireAgain()
{
fireAgain = true;
}
Note that your Coroutine doesn't make much sense to me. You are only rotating exactly once and only a really small amount.
The StopCoroutine in the end is unnecessary.
Also note: for debugging fine but later you should avoid to have Debug.Log running every frame in a built application. Even though the user doesn't see it the log is still created into the player log file and causes quite an amount of overhead.
I have some code that makes a player move up, down, left, and right.
public class playerMovement : MonoBehaviour
{
public float moveSpeed = 5f;
public Rigidbody2D rb;
public Animator animator;
public SpriteRenderer sr;
Vector2 movement;
bool walking = false;
private void Update()
{
//Inputs
movement.x = Input.GetAxisRaw("Horizontal");
movement.y = Input.GetAxisRaw("Vertical");
if (Input.GetKey("left") || Input.GetKey("right") || Input.GetKey("up") || Input.GetKey("down")
{
walking = true;
}
else
{
walking = false;
}
Animate();
}
private void Animate()
{
if (Input.GetKey("down") && walking == false)
{
sr.flipX = false;
animator.Play("idle_front");
}
else if (Input.GetKey("down") && walking)
{
sr.flipX = false;
animator.Play("walk_front");
}
else if (Input.GetKey("up") && walking == false)
{
sr.flipX = false;
animator.Play("idle_back");
}
else if (Input.GetKey("down") && walking)
{
sr.flipX = false;
animator.Play("walk_back");
}
else if (Input.GetKey("left") && walking == false)
{
sr.flipX = false;
animator.Play("idle_side");
}
else if (Input.GetKey("down") && walking)
{
sr.flipX = false;
animator.Play("walk_side");
}
else if (Input.GetKey("right") && walking == false)
{
sr.flipX = true;
animator.Play("idle_side");
}
else if (Input.GetKey("right") && walking)
{
sr.flipX = true;
animator.Play("walk_side");
}
}
public void FixedUpdate()
{
//Movement
rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
}
}
The movement is working perfectly fine, but the character just stays in it's idle state.
I have tried switching the get keys in Input.GetKey("left") || Input.GetKey("right") || Input.GetKey("up") || Input.GetKey("down") to Input.GetKeyDown() and Input.GetKeyUp(), but none of that works.
I have also tried using Blend Trees, but I cannot figure out how to do it.
I'm fairly new to Unity so a simple answer would be great.
open animator window
create 'State'
set animation clip into 'motion'
on top left click 'parameters' tab
click on plus sign next to parameters
click on 'Trigger'
name your trigger
right click on 'Any State' and make transition to drag a line to the new 'State' you created
click on the line between 'Any State' and the 'State' you created
under 'conditions' press the plus sign and add the trigger you just created
in code write
animator.SetTrigger("triggername");
when you want to transition to the before-mentioned animation state
repeat for all your animations, link them all from 'any state'
I am trying to make a 2D game in Unity and I am using in FixedUpdate() function the Input.GetMouseButtonDown() method. I want my player to change the horizontal direction, so for this I have the below code.
if (Input.GetMouseButtonDown(0))
{
if(change == true)
{
rb.velocity = new Vector2(-12,rb.velocity.y);
change=!change;
}
else if(change == false)
{
change=!change;
rb.velocity = new Vector2(12,rb.velocity.y);
}
}
At the beginning, first 3-6 clicks, works fine (one click change direction, another click the other direction) but afterwards I have to press 2 or 3 times to change the actual direction.
What should I do to increase the accuracy, quality of changing directions?
Thank you very much for your patience and attention!
The Unity Documentation states that you have to use GetMouseButtonDown() in the Update function.
You probably should create a global boolean to save the value and reset it in the FixedUpdate(). Something like this:
boolean MouseButtonDown=false;
void Update(){
if(Input.GetMouseButtonDown(0)){
MouseButtonDown=true;
}
}
void FixedUpdate(){
if (MouseButtonDown)
{
if(change == true)
{
rb.velocity = new Vector2(-12,rb.velocity.y);
change=!change;
}
else if(change == false)
{
change=!change;
rb.velocity = new Vector2(12,rb.velocity.y);
}
}
}
The FixedUpdate() function runs after a fixed interval of time, if you click the mouse button at the time when if(Input.GetMouseButtonDown(0) is executing then your input is taken into account. The Update() function runs for every frame that is being displayed on the screen, if your fps (frame rate) is 60fps it means that the Update() function runs 60 times per second so there's a very low possibility that your input isn't recorded. Hope that answers why your code isn't working.
What you can do is:
bool btnPressed = false;
void Update(){
if(Input.GetMouseButton(0) && !btnPressed){
btnPressed = true;
}
}
void FixedUpdate(){
if(btnPressed){
if(change == true){
rb.velocity = new Vector2(-12,rb.velocity.y);
change=!change;
}
else if(change == false){
change=!change;
rb.velocity = new Vector2(12,rb.velocity.y);
}
btnPressed = false;
}
}
I'm looking for a way to apply a force to an object after one button press (using GetKeyDown), essentially toggling the force.
I've had trouble for a few days trying to work this out as I'm learning how to use C#. I'm trying to work out a slide or dash for a 2D platformer, akin to Megaman sliding. This is my code so far, however when I press G, it teleports me forward instead of giving me a set velocity over time (where I want the player to move steadily foward)
public float slideCount;
public float maxSlideCount;
public bool isSliding;
void Update () {
if (Input.GetKeyDown (KeyCode.G) && isSliding == false) {
slideCount += Time.deltaTime;
isSliding = true;
if (slideCount < maxSlideCount) {
rb2d.AddRelativeForce (Vector2.right * 0.05f, ForceMode2D.Impulse);
} else
slideCount = 0;
isSliding = false;
}
Appreciate it
So a standard toggle looks like:
void Update() { // User-interactions happen in the graphics-frame
if (inputDown) {
toggle = !toggle;
}
}
Then to use toggle:
void fixedUpdate() { // Because you're applying forces, do it in the physics-frame
if (toggle) {
myRigidBody.AddForce(...);
}
}