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 jeffreywarf · Sep 13, 2014 at 04:22 AM · guimovementrepeatbutton

How to tell when a RepeatButton is done being Pressed

I want to make movement using on-screen buttons that you can hold down, unfortunately while the keyboard inputs work as intended, the on-screen inputs just won't. They move the controlled object way too fast for some reason when I try to use those "else" statements in "On GUI" and if I try to use booleans to control it, the same thing happens. If I remove or comment out the else statements in OnGUI I get normal movement, albeit not what I intend (I want it to snap to integers after the controls are let go of). So... any ideas as to why this is happening and how to fix it?

 #pragma strict
 
 var speed : float = 3;
 var int_position : int;
 var negative_int_position : int;
 
 var move_left : boolean;
 var move_right : boolean;
 
 var on_screen_only : boolean;
 var keyboard : boolean;
 var keys_or_screen : String;
 
 function Start () {
 
 }
 
 function Update () {
 
 if(keyboard == true)
 {
     if(Input.GetKey(KeyCode.D))
     {
     transform.position.x += speed * Time.deltaTime;
     }
     else if(Input.GetKeyUp(KeyCode.D))
     {
     int_position = Mathf.CeilToInt(transform.position.x);
         
         if(transform.position.x != int_position)// && transform.position.x > 0)
         {
         transform.position.x = int_position;
         }
     }
     
     if(Input.GetKey(KeyCode.A))
     {
     transform.position.x -= speed * Time.deltaTime;
     }
     else if(Input.GetKeyUp(KeyCode.A))
     {
     negative_int_position = Mathf.FloorToInt(transform.position.x);
         
         if(transform.position.x != negative_int_position)
         {
         transform.position.x = negative_int_position;
         }
     }
 }
 
 }
 
 function OnGUI () {
 if(GUI.Button(new Rect(0,50,100,50),"On-Screen"))
 {
 on_screen_only = true;
 keyboard = false;
 keys_or_screen = "On-Screen";
 }
 if(GUI.Button(new Rect(100,50,100,50),"Keyboard"))
 {
 on_screen_only = false;
 keyboard = true;
 keys_or_screen = "Keyboard";
 }
 GUI.Box(new Rect(200,50,100,50),keys_or_screen);
 
 if(on_screen_only == true)
 {
     if(GUI.RepeatButton(new Rect(0,Screen.height - 50,100,50),"<-"))
     {
     //move_left = true;
     transform.position.x -= speed * Time.deltaTime;
     }
     else
     {
     //move_left = false;
     negative_int_position = Mathf.FloorToInt(transform.position.x);
         if(transform.position.x != negative_int_position)
         {
         transform.position.x = negative_int_position;
         }
     
     
     }
 
     if(GUI.RepeatButton(new Rect(100,Screen.height - 50,100,50),"->"))
     {
     transform.position.x += speed * Time.deltaTime;
     }
     /*else
     {
     int_position = Mathf.CeilToInt(transform.position.x);
         if(transform.position.x != int_position)// && transform.position.x > 0)
         {
         transform.position.x = int_position;
         }
     }*/
 }
 
 }
Comment
Add comment
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

3 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Jeric-Miana · Sep 13, 2014 at 08:54 AM

Try OnMouseDown & OnMouseUp function

 function OnMouseDown()
 {
 transform.position.x += speed * Time.deltaTime;
 }
 function OnMouseUp()
 {
 int_position = Mathf.CeilToInt(transform.position.x);
  
         if(transform.position.x != int_position)// && transform.position.x > 0)
         {
         transform.position.x = int_position;
 }
Comment
Add comment · Show 3 · 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 jeffreywarf · Sep 13, 2014 at 07:20 PM 0
Share

well I could, but the intention is to have physical buttons, wouldn't this make it so no matter where you click the movement would happen? and only in one direction?

avatar image Eric5h5 · Sep 14, 2014 at 05:38 AM 0
Share

@jeffreywarf: No, On$$anonymous$$ouseDown only runs when you click on the object that the script is attached to.

avatar image Kiwasi · Sep 14, 2014 at 05:51 AM 0
Share

So to complete this answer you would need a GameObject on screen with a collider to allow clicking. Would work well with a sprite.

avatar image
0

Answer by JoshKingsbury · Sep 13, 2014 at 01:41 PM

I think I can point out some of the causes for trouble in your code.

First, I believe the reason why commenting out one of the else statements allows the object to move is because both else statements are called every OnGUI update. The negative_int position is applied first, then the regular int_position is applied right after, canceling out any movement.

Another trouble I noticed was that if a Debug.Log is placed inside the "else" of the GUI.RepeatButton, it is displayed even when the button is being pressed. I found a link where somebody posted a solution for the issue of making sure the GUI.RepeatButton is actually released.

http://answers.unity3d.com/questions/251760/check-if-gui-button-if-released.html

I also think that part of the trouble for the speed discrepancy between using the keyboard and the on-screen buttons is because OnGUI() is called more often than Update(). More info in this link:

http://answers.unity3d.com/questions/159938/ongui-updates-several-times-a-frame-why.html

My suggested solution to this is to keep with the idea of the booleans in the GUI.RepeatButton and move the actual movement code into the Update() function.

Something inside the Update() function along the lines of:

     if( move_left ){
         transform.position.x -= speed * Time.deltaTime;
     } else if (left_button_released) {
         negative_int_position = Mathf.FloorToInt(transform.position.x);
         if(transform.position.x != negative_int_position){
             transform.position.x = negative_int_position;
         }
         
         left_button_released = false;
     }
     
     if( move_right ){
         transform.position.x += speed * Time.deltaTime;
     } else if (right_button_released) {
         int_position = Mathf.CeilToInt(transform.position.x);
         if(transform.position.x != int_position){
             transform.position.x = int_position;
         }
         
         right_button_released = false;
     }

This code is untested, and the button_released booleans would want to be set true in the case of an actual release, referring to the first link I posted above about detecting the true release of a GUI.RepeatButton.

EDIT:

Here is a complete edit of your script, including corrections for the troubles I mentioned above.

 #pragma strict
  
 var speed : float = 3;
 var int_position : int;
 var negative_int_position : int;
  
 var move_left : boolean;
 var move_right : boolean;
 
 var left_button_released : boolean;
 var right_button_released : boolean;
  
 var on_screen_only : boolean;
 var keyboard : boolean;
 var keys_or_screen : String;
  
 function Start () {
  
 }
  
 function FixedUpdate () {
  
     if(keyboard == true){
         if(Input.GetKey(KeyCode.D)){
             transform.position.x += speed * Time.deltaTime;
         }
         else if(Input.GetKeyUp(KeyCode.D)){
             int_position = Mathf.CeilToInt(transform.position.x);
      
             if(transform.position.x != int_position){
                 transform.position.x = int_position;
             }
         }
      
         if(Input.GetKey(KeyCode.A)){
             transform.position.x -= speed * Time.deltaTime;
         } else if(Input.GetKeyUp(KeyCode.A)){
         
             negative_int_position = Mathf.FloorToInt(transform.position.x);
      
             if(transform.position.x != negative_int_position){
                 transform.position.x = negative_int_position;
             }
         }
     }
     
 
     
     if( move_left && !left_button_released ){
         transform.position.x -= speed * Time.deltaTime;
 
     } else if( move_left && left_button_released ) {
         negative_int_position = Mathf.FloorToInt(transform.position.x);
         if(transform.position.x != negative_int_position){
             transform.position.x = negative_int_position;
         }
         move_left = false;
     }
     
     if( move_right && !right_button_released ){
         transform.position.x += speed * Time.deltaTime;
 
         
     } else if (move_right && right_button_released){
         int_position = Mathf.CeilToInt(transform.position.x);
         if(transform.position.x != int_position){
             transform.position.x = int_position;
         }
         move_right = false;
     }
     
     left_button_released = true;
     right_button_released = true;
  
 }
 
 //function OnMouseUp(){
 //
 //    left_button_released = true;
 //    right_button_released = true;
 //        
 //}
  
 function OnGUI () {
     if(GUI.Button(new Rect(0,50,100,50),"On-Screen"))
     {
         on_screen_only = true;
         keyboard = false;
         keys_or_screen = "On-Screen";
     }
     if(GUI.Button(new Rect(100,50,100,50),"Keyboard"))
     {
         on_screen_only = false;
         keyboard = true;
         keys_or_screen = "Keyboard";
     }
     GUI.Box(new Rect(200,50,100,50),keys_or_screen);
      
     if(on_screen_only == true){
         if(GUI.RepeatButton(new Rect(0,Screen.height - 50,100,50),"<-")){
             move_left = true;
             left_button_released = false;
         } 
      
         if(GUI.RepeatButton(new Rect(100,Screen.height - 50,100,50),"->")){
             move_right = true;
             right_button_released = false;
         } 
 
     }
 }

This fixes the multiple update issue of having the movement code inside of the OnGUI() function. The movement code is now only called once per frame.

This also corrects for the conflicting logic of your original code.

Comment
Add comment · Show 4 · 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 jeffreywarf · Sep 13, 2014 at 07:17 PM 0
Share

Yeah that doesn't work at all. In fact, it just makes the buttons unresponsive. What DID seem to work was when I changed the code for the button to move right to this:

 if(GUI.RepeatButton(new Rect(0,Screen.height - 50,100,50),"->"))
     {
     move_right = true;
     }
     move_right &= Input.Get$$anonymous$$ouseButton(0);


and the code in Update() looked like this:

 if(move_right)
     {
     transform.position.x += speed * Time.deltaTime;
     }
     else if(move_right == false)
     {
     int_position = $$anonymous$$athf.CeilToInt(transform.position.x);
 
         if(transform.position.x != int_position)
         {
         transform.position.x = int_position;
         }
     }

then the button worked as intended. However, when I copied it all over to the button for moving left, then it broke and now it won't move either direction.

avatar image jeffreywarf · Sep 13, 2014 at 07:18 PM 0
Share

If I comment out all code for moving to the right, then the button for moving left works as intended. It seems to not like having the code for both directions :/ Here's how it looks when nothing is commented out (this is in the Update() function)

 if(move_left)
     {
     transform.position.x -= speed * Time.deltaTime;
     }
     else if(move_left == false)
     {
     negative_int_position = $$anonymous$$athf.FloorToInt(transform.position.x);
 
         if(transform.position.x != negative_int_position)
         {
         transform.position.x = negative_int_position;
         }
     }
 
     if(move_right)
     {
     transform.position.x += speed * Time.deltaTime;
     }
     else if(move_right == false)
     {
     int_position = $$anonymous$$athf.CeilToInt(transform.position.x);
 
         if(transform.position.x != int_position)
         {
         transform.position.x = int_position;
         }
     }
 
avatar image JoshKingsbury · Sep 13, 2014 at 09:25 PM 0
Share

In the code you posted directly above this comment:

 else if(move_right == false)
     {
     int_position = $$anonymous$$athf.CeilToInt(transform.position.x);
  
         if(transform.position.x != int_position)
         {
         transform.position.x = int_position;
         }
     }

And:

 else if(move_left == false)
     {
     negative_int_position = $$anonymous$$athf.FloorToInt(transform.position.x);
  
         if(transform.position.x != negative_int_position)
         {
         transform.position.x = negative_int_position;
         }
     }

Are being called at the same time every frame because move_left and move_right are false every single frame.

The trouble here is the logic you are using. Inside of the else, you need a second boolean variable to deter$$anonymous$$e when the correct button is released.

Ins$$anonymous$$d of: else if(move_left == false) { negative_int_position = $$anonymous$$athf.FloorToInt(transform.position.x);

         if(transform.position.x != negative_int_position)
         {
         transform.position.x = negative_int_position;
         }
     }

I was suggesting:

 else if (left_button_released) 
     {
         negative_int_position = $$anonymous$$athf.FloorToInt(transform.position.x);
         if(transform.position.x != negative_int_position)
         {
             transform.position.x = negative_int_position;
         }
  
         left_button_released = false;
     }


The intended logic is as follows:

If the button is pressed, move_left is true and the transform is applied

When the button is released, move_left becomes false and the else statement is triggered

Since move_left already must be false and stays false, it checks to see if the left_button_released is true

If so, it runs the else code only a single time, and then no longer runs because left_button_released has been set to false

Does that make a bit more sense?

avatar image JoshKingsbury · Sep 14, 2014 at 03:39 PM 0
Share

@jeffreywarf I've updated my answer to include an entire working script. Please let me know if it works for you.

avatar image
0

Answer by Kiwasi · Sep 14, 2014 at 05:05 AM

First suggestion: Abandon OnGUI and use the 4.6 beta

Second suggestion: Watch this video from Unite 2013 to get the hang of how the intermediate mode GUI works

Third suggestion: Read the rest of my answer, I'll try explain it here.

First thing to understand is that OnGUI gets called multiple times per frame. The code will run once per GUI event. So it runs once for a mouse button down, once for a mouse button up, once for a key down and so forth. On top of that it runs a layout pass before calling each event, this is where it gets all of the rects and positions everything on the screen. There are also redraw events.

There are a couple side effects of this multiple call scenario. First is OnGUI is slow. Every GUI element is processed multiple times. Even if it just sitting there. That's why other solutions are popular in published games

Second up is that code that is not part of an if loop runs multiple times. This means anything on its own, or in an else clause will run at least once. Maybe more times. GUI buttons get around this by internally checking which event is being run through. GUIButton will only return true if the event is MouseDown, and the mouse is inside the bounds of the button rect. Everything else, including used events and layout events are ignored. You need to programme this behaviour into your else clause.

Now for some actual pseudo code. Be aware I haven't touched OnGUI since the 4.6 was released, it might not compile first time around.

 private bool isButtonDown;
 
 void OnGUI (){
     if (GUI.RepeatButton(....)){
         isButtonDown = true;
     } else if (isButtonDown && Event.current == EventType.MouseUp){
         isButtonDown = false;
     }
 }

That should be enough to get you started. Let me know if you need more assistance.

Comment
Add comment · 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

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

26 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 avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How to Convert each 2D Array to GameObject 2 Answers

Input trick question 3 Answers

RepeatButton Problem 1 Answer

how do i make this move slowly over time 1 Answer

GUI.repeatbutton crazy? 1 Answer


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