OnGUI() problem - firing twice a time! [SOLVED]

Discussion in 'Scripting' started by Kokumo, Jul 25, 2010.

  1. Kokumo

    Kokumo

    New Member

    Joined:
    Jul 23, 2010
    Messages:
    390
    Hello guys!
    First of all, excuse me for my english; i'm a spanish native speaker.

    I'm learning how to develop games in Unity 3D by myself, so i decided to make a FPS to play with my friends (the best motivation i found to achieve my goal).
    I wrote my weapon's manager (SC_ManagerArmas.cs) which listen through OnGUI method (it doesn't listen really... well, i think you may understand what i'm trying to say) what kind of key is pressed by the gamer, and then changes the character weapon: 1 for granade launcher, 2 for shuriken launcher, and 3 for a pistol.

    The problem - firing weapons:
    If i put the code that allow firing the current weapon into Update() method, everything go well; however, if i put the code into OnGUI() method, the weapon shots twices a time.

    Anyone can help me with this issue?

    Thaks a lot!
    Kokumo

    ps: you will see an interface's method call; i like more implement an interface rather than use a broadcasting.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class SC_ManagerArmas : MonoBehaviour {
    6.  
    7.    private Camera vision;
    8.    private RaycastHit rayResultado;
    9.    private Ray rayoVision;
    10.    private IArmas armaActual;
    11.  
    12.    //i'm setting the vision for my raycast and first weapon
    13.    private void Awake () {
    14.       vision = gameObject.transform.parent.camera;
    15.       elegirArma(0);
    16.    }
    17.    
    18.    //firing a weapon!... here it shots once a time
    19.    private void Update() {
    20.       if (Input.GetButtonDown("Fire1")) {
    21.       rayoVision = vision.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
    22.  
    23.       if (!Physics.Raycast(rayoVision, out rayResultado))rayResultado.point = Vector3.zero;
    24.  
    25.       armaActual.Disparar(rayResultado);
    26.       }
    27.     }
    28.  
    29.    private void OnGUI() {
    30.         if (Input.GetKeyDown("1")) {
    31.             elegirArma(0);
    32.         } else if (Input.GetKeyDown("2")) {
    33.             elegirArma(1);
    34.         } else if (Input.GetKeyDown("3")) {
    35.             elegirArma(2);
    36.     }
    37. /* SHOTS TWICE!
    38.         else if (Input.GetButtonDown("Fire1")) {
    39.            rayoVision = vision.ScreenPointToRay(new Vector3(Screen.width / 2, Screen.height / 2, 0));
    40.            if (!Physics.Raycast(rayoVision, out rayResultado))rayResultado.point = Vector3.zero;
    41.             armaActual.Disparar(rayResultado);
    42.     }*/
    43.     }
    44.  
    45.    private void elegirArma(int indice) {
    46.       GameObject goTemp;
    47.       for (int i=0; i< gameObject.transform.childCount; i++) {     
    48.          goTemp = transform.GetChild(i).gameObject;
    49.          if (i == indice) {
    50.             goTemp.SetActiveRecursively(true);
    51.             armaActual = (IArmas) goTemp.GetComponentInChildren(typeof(IArmas));
    52.           } else goTemp.SetActiveRecursively(false);
    53.  
    54.       }
    55.  
    56.    }
    57.  
    58. }
  2. AkilaeTribe

    AkilaeTribe

    Member

    Joined:
    Jul 4, 2010
    Messages:
    1,149
    Why would you set irrelevant code in the OnGUI function instead of the Update ?

    Who told you to put this code in OnGUI, if Update works ?
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Messages:
    24,590
    OnGUI runs at least twice per frame, by design. Don't use it for anything except GUI code.

    --Eric
  4. Kokumo

    Kokumo

    New Member

    Joined:
    Jul 23, 2010
    Messages:
    390
    AkilaeTribe, Eric5h5, thanks for your answers.

    As you said Eric5h5, i just realize OnGUI it's called several times per frame; i have to recognize that i could check this out at Unity Script Reference before post my doubt here... a friend of mine told me that there wasn't any explanation in the web. Next time, i will take a look.

    AkilaeTribe, i wrote the code OnGUI because i thought was the right place where to put it; i'm a newbie and i'm giving my best, but looks like i have a long road to go... sorry :(

    Perhaps this post will serve to someone who, like me, make this mistake.

    Thanks people!
    Kokumo
  5. Robert G

    Robert G

    New Member

    Joined:
    Nov 17, 2009
    Messages:
    233
    Don't be so hard on yourself Kokumo, you actually did the right thing.
    Asking questions to find out that you did it the wrong way.
    That is how we learn things!

    All the best, Robert
  6. dxchen

    dxchen

    New Member

    Joined:
    Sep 17, 2009
    Messages:
    4
    I did some test about this topic. And I have some conclusions. If there is anything wrong , please tell me.

    First, we know that unity will call Update() function per frame, and will call OnGUI() per Event.
    When one frame is updated , Unity will receive more than one Event, and need to initiate that event before call OnGUI. and the initiate will also send one event to OnGUI, that is EventType.Layout.
    Except EventType.Layout, Unity will send EventType.Layout before all Events are send to OnGUI.
    So we know every frame updated, OnGUI will called at least two times. The first one is EventType.Layout , the second one isEventType.Repaint.

    Before receiving EventType.Repaint´╝îOnGUI will be called by all other Events. ex: EventType.MouseMove, after that, called by EventType.Repaint.
    Of course, before EventType.MouseMove and EventType.Repaint , there are also EventType.Layout.

    So you can do the test, if you move the mouse , than, your OnGUI will be called my four Events during one frame is updated. Those four events are:
    EventType.Layout
    EventType.MouseMove
    EventType.Layout
    EventType.Repaint

    Here is my test code:
    Code (csharp):
    1. function Update () {
    2.    print("Update Event.current = "+Event.current + "     Time.time " + Time.time + "     Time.realtimeSinceStartup " + Time.realtimeSinceStartup);
    3. }
    4. function OnGUI ()
    5. {
    6.    print("OnGUI Event.current = "+Event.current + "     Time.time "+ Time.time + "     Time.realtimeSinceStartup " + Time.realtimeSinceStartup);
    7. }
    It refer by those data below:
    1.MonoBehaviour.OnGUI
    2.Event
    3.EventType


    Here are some import hints:
    1.For each event OnGUI is called in the scripts;
    2.EventType.Layout
    EventType.Layout is sent prior to anything else - this is a chance to perform any initialization. It is used by the automatic layout system.
    3.EventType.Repaint
    All other events are processed first, then the repaint event is sent.
    4.Event Execution Order
  7. dxchen

    dxchen

    New Member

    Joined:
    Sep 17, 2009
    Messages:
    4
    There is another topic, I want to discuss.

    if I use function Update() to receive the iPhoneTouch event

    we have example in the document just like this:
    Code (csharp):
    1. function Update () {
    2.     if (iPhoneInput.touchCount > 0 )
    3.     {
    4.         if(iPhoneInput.GetTouch(0).phase == iPhoneTouchPhase.Ended)
    5.         {
    6.             //...
    7.         }
    8.     }
    9. }
    But I notice there is a special situation happened.
    that is iPhoneTouchPhase.Ended Event happened but iPhoneInput.touchCount = 0 in the function Update.
    Is there anyone have this problem?