Search Unity

D-pad input...

Discussion in 'Scripting' started by xelliottco, Jun 14, 2019.

  1. xelliottco

    xelliottco

    Joined:
    Feb 27, 2018
    Posts:
    5
    So here is what I am trying to do...

    Turn-based combat, the user selects an ability, then the user has to input a button sequence using the D-pad, then the user selects the enemy IF the user enters the correct button sequence. The way I coded it with my sub-par logic skills is that each ability has an "Input Sequence" that consists of a string of numbers 1-4. The D-pad correlates with this -> up = 1, down = 2 etc... I'm just trying to make it so that WHEN the user hits the button to select an ability, the D-pad input activates, and records user input WHILE either the user input string (via D-pad) length is LESS than the required ability Input Sequence, and if the user input is less than or equal to the length, the user has to press the "submit" button on their controller to end the D-pad input time... The following code is BARELY an example of this because I can't get to the point of input after selecting an ability...

    I put the following code as the last click event on each ability - so that when you click the ability, this is the last thing that runs before you select an enemy... However, it won't run... or it freezes in while loops. I HAVE gotten it to work in "update," however, I only need it to run AFTER the player selects the ability and BEFORE they select the enemy because the user otherwise uses the D-pad to navigate the menu.

    Anyway, thanks for checking it out! :D




    Code (CSharp):
    1.     int n = 0;
    2.  
    3.     public void GetButtonSequence()
    4.     {
    5.         float h = Input.GetAxisRaw("dPADHori");
    6.         float v = Input.GetAxisRaw("dPADVert");
    7.  
    8.         while (n < HeroChoice.chosenAttack.inputSequence.Length )
    9.         {
    10.             if (theLastDpadInt.Length < 4)
    11.             {
    12.                 {
    13.                     if (dPadInt != 1)
    14.                     {
    15.                         if (h == 1)
    16.                         {
    17.                             dPadInt = 1;
    18.                             theLastDpadInt = theLastDpadInt + "" + dPadInt.ToString();
    19.                             n++;
    20.                         }
    21.                     }
    22.                     if (dPadInt != 2)
    23.                     {
    24.                         if (h == -1)
    25.                         {
    26.                             dPadInt = 2;
    27.                             theLastDpadInt = theLastDpadInt + "" + dPadInt.ToString();
    28.                             n++;
    29.                         }
    30.                     }
    31.                     if (dPadInt != 3)
    32.                     {
    33.                         if (v == 1)
    34.                         {
    35.                             dPadInt = 3;
    36.                             theLastDpadInt = theLastDpadInt + "" + dPadInt.ToString();
    37.                             n++;
    38.                         }
    39.                     }
    40.                     if (dPadInt != 4)
    41.                     {
    42.                         if (v == -1)
    43.                         {
    44.                             dPadInt = 4;
    45.                             theLastDpadInt = theLastDpadInt + "" + dPadInt.ToString();
    46.                             n++;
    47.                         }
    48.                     }
    49.  
    50.                     Debug.Log(dPadInt);
    51.                     Debug.Log(theLastDpadInt);
    52.                 }
    53.             }
    54.         }
    55.     }
    This particular effort is crashing Unity because of the While loop - I have also tried this in a coroutine with no success.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    3,678
    You can't hard-loop in Unity and expect any kind of input. In order for Unity to process each frame of input you either have to yield using a coroutine, or do your logic in Update() and let it flow out after each frame.

    I recommend looking into either coroutines, or else making your own simple state machine to look for the most recent series of directional presses and decide if they meet your criteria.
     
    xelliottco likes this.
  3. xelliottco

    xelliottco

    Joined:
    Feb 27, 2018
    Posts:
    5

    Thanks for the reply - I put this code into a coroutine using yield returns. While the game didn't crash, it simply just didn't accept the inputs and wouldn't move past this part of the game to make the player select the target of the ability.

    That said, I feel like I'm not fully grasping coroutines well and don't understand how to implement this into one...

    Thanks again!
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    3,678
    I think your inputting requirement might be best modeled by identifying and recording transitions, specifically transitions from "no direction pressed" to "a direction pressed."

    Let's call each of these transitions up, down, left and right, just from a conceptual "this event has happened" standpoint.

    You need to detect those events by comparing input from last frame to this frame. That's step 1.

    Now that you decide that an "up" has occurred, you might add it to the end of a list of events. That's probably step 2.

    Finally when you get an event and have added to the list, then you might want to inspect the last X events in that list and say "Hey, are these left left right right up down up down?" and if so, go do something.

    That's sort of how I could imagine coding this process. What's handy about this is you can display the list of events in your Debug.Log() output to easily identify what is happening.
     
    xelliottco likes this.
  5. xelliottco

    xelliottco

    Joined:
    Feb 27, 2018
    Posts:
    5
    I think I understand what you're saying...It sounds like how I first tested the code.

    Maybe this will add some insight as to why I'm so lost on this issue right now. I originally put this code into my State Machine 'update.' It ran fine. As I used my Dpad to input 1, 2, 3, or 4, (up, down, left, or right) it created a string and I continued to call Debug.Log to read the string. However, the problem is that I need to isolate the capability to read that input to a very specific section of the game (after the ability is chosen). So I removed it from 'update,' put the code directly after the player selects the first input (which is on a button press), but it's not running the same way it did when it was in 'update' because I don't think it's reading it by frame now (because the code runs after the ability button is pressed?). I just can't figure it out... that's why I'm here lol. :)
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    3,678
    Well I think you're probably really close to getting it. Let's talk about the API for it first though.

    The way I see it you are going to have some kind of Monobehavior on some kind of GameObject somewhere to do the detecting of your gesture pattern. This is mostly just so it can get a steady Update() heartbeat call.

    I assume there's some kind of timeout involved, like to get to a success/fail decision: you either put in the right keys or you don't within a timeout period, and both of those have consequences of one kind or another.

    So basically lets say you put one of these things in your scene, probably just one that is shared by all users, and you either drag a reference into it, or keep some central reference to it.

    If I have understood you correctly above, the API for it might have the following single method, sort of a fire-and-forget:

    Code (csharp):
    1. void BeginGestureRecognition( string desiredGesture, float timeLimit, System.Action success, System.Action failure)
    2. {
    3.   // code here, see below
    4. }
    The guts of that function would:

    - write down the desired gesture
    - write down the time limit amount
    - write down the two System.Action (these are also known as "callback functions")
    - start the timer out at zero seconds (just a float)
    - reset all the counters and lists in the script
    - turn the gesture recognition routine on (set a boolean true for example)

    And away it goes, immediately returning to the caller, who would likely do something like gray out the buttons so you can't invoke things twice from your primary interface.

    Once it is running, the gesture recognizer's Update() loop would basically do two things:

    1. count the timer. If the time expires, call the failure() callback and turn off the recognizer

    2. watch for gestures. If you get one, add it to the list and see if it matches the desired pattern, and if so call the success() callback and turn off the recognizer.

    Does that help you think about it?
     
    xelliottco likes this.
  7. xelliottco

    xelliottco

    Joined:
    Feb 27, 2018
    Posts:
    5
    Hey Kurt,

    I won't be able to get back into this until tomorrow likely. I just wanted to say I appreciate the time you're putting in to help me out. I'll keep this updated
     
    Kurt-Dekker likes this.
  8. xelliottco

    xelliottco

    Joined:
    Feb 27, 2018
    Posts:
    5
    So I tried to figure something out this morning while I had a few minutes to think over your last message. Because I had gotten the code to work and run in Update, I have an enumerator that holds stages of update. I added a stage to that enumerator for this particular method call. At the end of that enumeration, I move to the next. I now call the code in Update, however, I have essentially just isolated where this input is accepted to a very specific point... it works. :D I still have some debugging to do as it needs to work with a variety of abilities, but I can't thank you enough for your help in getting me to think it through!

    Thanks again!
     
    Kurt-Dekker likes this.