Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Bill Cosby · Oct 03, 2012 at 12:52 AM · c#inputjumpboolean

(C#) A better way to limit actions to once per button press?

Hello, I'm working on a simple cannabalt-style platformer where the character jumps (as most platforming characters do). Up until now, I've been using a slightly modified version of the basic character controller found on the Unity Scripting Reference:

 using UnityEngine;
 using System.Collections;
 public class movement : MonoBehaviour {
     public float speed = 6.0F;
     public float jumpHeight = 8.0F;
     public float gravity = 20.0F;
     private Vector3 moveDirection = Vector3.zero;
     void Update() {
         CharacterController controller = GetComponent<CharacterController>();
         if (controller.isGrounded) {
               moveDirection = Vector3.forward;
               moveDirection = transform.TransformDirection(moveDirection);
               moveDirection *= speed;              
             if (Input.GetButton("Jump"))
                 moveDirection.y = jumpHeight;
         }       
         moveDirection.y -= gravity * Time.deltaTime;
         controller.Move(moveDirection * Time.deltaTime);
     }
 }

For the most part, this worked alright, but my problem with it was that as long as you held down the jump button, the character would keep jumping, but I only want him to jump once per button press. I decided to change the code to this:

 using UnityEngine;
 using System.Collections;
 public class movement : MonoBehaviour {
     public float speed = 6.0F;
     public float jumpHeight = 8.0F;
     public float gravity = 20.0F;
     private bool doJump = true;
     private Vector3 moveDirection = Vector3.zero;
     void Update() {
         CharacterController controller = GetComponent<CharacterController>();
                     if (Input.GetButtonUp("Jump"))
             {                
                 doJump = true;
             }
         if (controller.isGrounded) {
               moveDirection = Vector3.forward;
               moveDirection = transform.TransformDirection(moveDirection);
               moveDirection *= speed;        
               
 
             if (Input.GetButtonDown("Jump") && (doJump = true))
             {
                 moveDirection.y = jumpHeight;
                 doJump = false;
             }            
     
         }       
         moveDirection.y -= gravity * Time.deltaTime;
         controller.Move(moveDirection * Time.deltaTime);
     }
 }

For the most part, adding the boolean check seemed to be working fine. The character only jumped once per pressing of the button, and it looked like things were improved. After further testing though, I found a new problem. What's happening is that if I hit the jump button right after the character lands, it sometimes fails to register at all and the jump doesn't activate. I tested several times to make sure that something was wrong with the game and that I wasn't simply hitting the button before he landed completely, and it indeed fails to activate within the first split second or so of landing. Since this is an endless runner, a single missed jump means death, which will be very frustrating if it's not the player's fault. My question is, how could I better go about limiting the game to one jump per button press without causing the controls to become glitchy and sometimes unresponsive?

Comment
Add comment · Show 12
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Seth-Bergman · Oct 03, 2012 at 01:14 AM 0
Share
  if (Input.GetButtonDown("Jump") && (doJump = true))

should be

  if (Input.GetButtonDown("Jump") && (doJump == true)) //(missing a "=")

or better yet

   if (Input.GetButtonDown("Jump") && doJump) //means the same thing

(not sure if that could be the issue tho..)

also, using doJump is kind of pointless here anyway, since your jump code only happens if grounded anyway, so you could just get rid of that altogether..

also, you don't need to call this line every frame:

  CharacterController controller = GetComponent<CharacterController>();

you could declare "controller" outside of the function, and use Start() to initialize it:

 CharacterController controller;
 
 void Start(){
 controller = GetComponent<CharacterController>();
 }

(this to save on performance..)

avatar image Bill Cosby · Oct 03, 2012 at 01:58 AM 0
Share

Thanks for the response. I followed your advice to remove doJump altogether and while I'm getting the desired effect of only having one jump per press, the problem of occasionally not registering persists, although it seems to be happening less frequently now. I also moved the Getcomponent to the Start void like you suggested, and that's working well.

avatar image Seth-Bergman · Oct 03, 2012 at 03:06 AM 0
Share

Hmm, well, it would seem that controller.isGrounded may not be going to true quite as early as you would like.. $$anonymous$$aybe your character controller capsule is a bit too high? You might try lowering that a bit, maybe your character is just riding a little bit into the ground, making him appear to be grounded a bit earlier than the CAPSULE becomes grounded... If this doesn't do it, things get a bit more complicated..

avatar image Seth-Bergman · Oct 03, 2012 at 03:15 AM 0
Share

Also, your character doesn't have a rigidbody, correct?

avatar image Bill Cosby · Oct 03, 2012 at 03:19 AM 0
Share

After going over the program some more, I agree that it's most likely a problem with the capsule as opposed to the code. I did some more testing to try and find what specific situations the jumping doesn't trigger, and I've found that it's right when I'm at the very edge of a platform. It seems like the very bottom of the Capsule has passed over the edge, but the curved part hasn't yet, so sort of like you said it looks like it's grounded when it's really not. I think switching to a box collider will probably solve the problem, since that has a perfectly flat bottom, and since the gameplay is strictly 2D, the capsule might be overkill anyhow. I'm reasonably sure the box collider will probably solve the problem, so I'm going to say yours the right answer. Thanks so much for all of your help!

Show more comments

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Seth-Bergman · Oct 03, 2012 at 03:16 PM

OK, you've got me thinking now..

This is actually kind of tricky to get working as you want. Now, going along with your idea of using a box collider, the way to try this is:

1: create a NEW, empty game object, and give that a box collider.

2: adjust size/position of the box collider to proper position (line it up in the scene with character's feet)

3: child the object to the player

4: add this script to the new object (make sure it is childed directly to the player object which contains the other script):

 using UnityEngine;
 using System.Collections;
 public class GroundedCheck : MonoBehaviour {
 
     public movement otherScript; 
     
     void Start(){
     GameObject myParent = transform.parent.gameObject;
     otherScript = myParent.GetComponent<movement>(); 
     }
     
     void OnCollisionEnter(Collision other){
     if(other.gameObject.tag == "ground")
     otherScript.canJump = true;
     }
     
     void OnCollisionExit(Collision other){
     if(other.gameObject.tag == "ground")
     otherScript.canJump = false;
     }
 }

5: NOW, we are planning to use this var "canJump" INSTEAD of controller.isGrounded, to decide whether we can jump.. So we will update the other script:

     using UnityEngine;
     using System.Collections;
     public class movement : MonoBehaviour {
 
             public boolean canJump = true;
         public float speed = 6.0F;
         public float jumpHeight = 8.0F;
         public float gravity = 20.0F;
         private Vector3 moveDirection = Vector3.zero;
         private CharacterController controller;
         
         void Start(){
             controller = GetComponent<CharacterController>();
             }
         void Update() {        
                 
             if (controller.isGrounded) { 
                   moveDirection = Vector3.forward;
                   moveDirection = transform.TransformDirection(moveDirection);
                   moveDirection *= speed;    
                      }
                      if (Input.GetButtonDown("Jump"))
                                  {
                                  if(canJump || controller.isGrounded)
                                   {
                                   moveDirection.y = jumpHeight;
                                   canJump = false;          
                                   }
                                  }             
         
      
             moveDirection.y -= gravity * Time.deltaTime;
             controller.Move(moveDirection * Time.deltaTime);
         }
     }

6: Add a RigidBody to the ground, check "is kinimatic", uncheck "use gravity".

7: finally, you'll need to tag your ground objects as "ground".

ok...

This should all work assuming you can only be in contact with one "ground" at a time... but if you have separate "pieces" of ground which can be touched simultaneously, I imagine there could be issues.

This may or may not yield the results you are after..

Comment
Add comment · Show 19 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Bill Cosby · Oct 03, 2012 at 05:01 PM 0
Share

This seems like it's going to work, and I won't have the character in contact with more than one ground at a time, but I'm getting several error messages with the code in regards to the line: "otherScript = transform.parent.gameObject.GetComponent(movement);"

I'm getting: "Expression denotes a `type', where a `variable', `value' or `method group' was expected"

"The best overloaded method match for `UnityEngine.GameObject.GetComponent(System.Type)' has some invalid arguments"

"Argument `#1' cannot convert `object' expression to type `System.Type'"

"error CS0103: The name `otherScript' does not exist in the current context"

avatar image Seth-Bergman · Oct 03, 2012 at 05:52 PM 0
Share

oops, sorry! I'm used to javascript..

change it to:

 otherScript = transform.parent.gameObject.GetComponent<movement>();

I'll fix it in the answer...

also, I have inconsistent capitalization.. so change the line:

movement otherscript;

to

movement otherScript;

avatar image Bill Cosby · Oct 03, 2012 at 07:05 PM 0
Share

That's solved several of the errors, but now I'm getting "The type arguments for method `UnityEngine.GameObject.GetComponent()' cannot be inferred from the usage. Try specifying the type arguments explicitly" for that line and I'm still getting "The name `otherScript' does not exist in the current context" as well

avatar image Seth-Bergman · Oct 03, 2012 at 07:28 PM 0
Share

hmmm, maybe try splitting it up:

 void Start(){
 GameObject myParent = transform.parent.gameObject;
 otherScript = myParent.GetComponent<movement>(); 
 }
avatar image fafase · Oct 03, 2012 at 07:29 PM 1
Share

In your start add:

  if(otherScript)print("Working");

if it does not print it means the GetComponent does not find the object. You could try:

  otherScript = transform.parent.gameObject.GetComponent<movement>() as movement;

or

      otherScript = GameObject.Find("ParentObjectName").GetComponent<movement>();
Show more comments
avatar image
0

Answer by MibZ · Oct 03, 2012 at 06:59 PM

A much simpler and guaranteed effective solution: previous and current button states.

EDIT: Simplified this a little bit, I realized you don't need the Start function for this.

 private bool prevSpacebarState = false;
 private bool currSpacebarState = false;

 
 void Update()
 {
      //Neither state has been updated since the last tick, so right now current is the value we want in previous
      //Assign current (of last tick) into previous, then update current
      prevSpacebarState = currSpacebarState;
      currSpacebarState = Input.GetKey(KeyCode.Space);
 
 
      if (!prevSpacebarState && currSpacebarState)
            Jump();
 
 }
Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Seth-Bergman · Oct 03, 2012 at 07:09 PM 0
Share

rather than all this, using Get$$anonymous$$eyDown:

 function Update(){
     if(Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.Space))
     Jump();
 }

would yield exactly the same results.. but unfortunately does not solve the issue at hand...

avatar image MibZ · Oct 03, 2012 at 07:13 PM 0
Share

Wouldn't that code execute Jump each tick space is held down? Previous and current states are the simplest way of limiting actions to once per down - you can hold the key down for an hour and the character will only jump once, how is the issue not solved?

avatar image Bill Cosby · Oct 03, 2012 at 07:18 PM 0
Share

Thanks for responding. The issue of one jump per press has been solved. It turns out that the main issue I was having was actually with colliders, which is what I'm trying to work through with Seth Bergman.

avatar image Seth-Bergman · Oct 03, 2012 at 07:40 PM 0
Share

@$$anonymous$$ibZ - Input.Get$$anonymous$$ey returns true every frame it is held down

Input.Get$$anonymous$$eyDown, on the other hand, returns true ONLY the first frame the button is pushed. It is basically a predefined button state condition, identical to what you are suggesting..

avatar image MibZ · Oct 03, 2012 at 07:46 PM 0
Share

@Seth Bergman Ah, that's right. Last time I used the prev/curr was in an XNA game, and that function is the reason why. Slipped my $$anonymous$$d. Disregard my foolishness :p

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

11 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Help With Simple Jump Script 1 Answer

The Mario Jump? 2 Answers

Can't Set Animator Boolean Parameter C# 1 Answer

Trying to find boolean value in another script 0 Answers

Character cannot move Diagonally forwards 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges