Quick Links: Download Gideros Studio | Gideros Documentation | Ultimate Guide | Gideros Development Center
Waiting for user input - Gideros Forum

Waiting for user input

qxmat2 Member
edited November 21 in General questions
Hi there!

I am programming a little card game for learning purposes. I stepped into a little problem, where I don't know the best practice howto solve it.

If the player (me) throws a certain card, an additional dialog pops up and asks the player which face (spades, diamonds...) he wants from the opponent as the next card, so the opponent is forced to serve this face.

The pseudo code looks like this
function playerMove(playercards, opencardOnStack){
foreach(playercards as card){
if(card==opencardOnStack){ success=1; playerWantToThrowthisCard=card }
}
 
if(success==1){
if(playerWantToThrowthisCard == "Jack"){ -- the Jack is the special card which enables the player to wish a face from the opponent
 
doWait = true
 
dialog = Dialog
dialog:addEventListener("click", function(){ print("clicked"); doWait=false}
dialog:showDialog(wishedFaceFromOpponent = function(){ print("which face do you want from the opponent"); return function readFace() }
 
while doWait==true
end
 
print("the player wants the opponent to throw a" .. wishedFaceFromOpponent)
 
}
 
}
nextPlayersTurn()
}


So I have implemented a kind of "active waiting" which is bad programming practise and additionally it doesn't work, because it hangs my simulator.

Of course I could pack the further statements, which should be executed after "clicked" into that event listener, but that doesn't work with my code well, because it consists of many nested subroutines, beside that it would branch my code even more. For this to work, I'd had to completely redesign my code only for this single purpose, that cannot be the only solution.

I googled but cannot seem to find the right way to do this. The function I'm seeking for is something like waitForEventCompleted(), which halts the further execution as long as the user clicked something in the dialog. This functions should substitute the "while doWait==true end" active wait statement. I guess this "waiting" thing is something different in event-driven environments.

Comments

  • You need to make a state machine or use fake threads.
    +1 -1
  • Oh well, so there isn't already an easy to use implementation for such a simple task? I mean to block the execution of the code until a signal is fired. I've read somewhere that gideros is single threaded, is that the reason why this isn't possible? Would you say, if I need such an function, my program design is bad?
    +1 -1
  • hgy29hgy29 Maintainer
    Yes, gideros being single threaded at heart (not speaking about fakethreads), you can't wait in an event handler, otherwise you'll block the whole app. You should either handle the user response and everything that comes after in the 'click' event listener, or use fakethreads which can yield (sleep).
    +1 -1
  • antixantix Member
    Accepted Answer
    @qxmat2, I would probably go with a simple state machine too. I'm not sure how your whole program is structured but in theory all of your UI elements have event listeners attached so they can do things like update your state machine when required. A simple state machine would be implemented in the EnterFrame event..
    state = "normal"
     
    local function onEnterFrame(e)
    local dt = e.deltaTime
     
    local state = state
     
    if state == "playerTurn" then
    -- code run when it is the players turn
     
    elseif state == "opponentTurn" then
    -- code run when it is the players turn
     
    elseif state == "add more states here" then
    elseif state == "add more states here" then
    elseif state == "add more states here" then
     
    else
    -- nothing happens for unrecognized modes
    end
     
    -- code run no matter what the state is
    end
     
    stage:addEventListener(Event.ENTER_FRAME, onEnterFrame)

    I hope that makes sense :)

    Aye: qxmat2

    +1 -1 (+1 / -0 )
  • Your example makes it very clear what a statemachine in this context means, so it looks like my whole app is the statemachine, at least from the moment it branches in either the players code or the opponents code. Your example points me, that it is (obviously) better to set the state who can play as early as possible. Due to not being familar with event-driven paradigm I missed that point, now I switch and call player/opponent code all over my classes, which makes the whole code unreadable and hardly tracable. Thanks for your example, I think I can do it better the next time.
    +1 -1 (+2 / -0 )
  • @qxmat2 Sorry I just said 'state machine' - I was short on time and I though a clue is better than nothing. :)

    Aye: antix

    +1 -1 (+1 / -0 )
  • SinisterSoftSinisterSoft Maintainer
    edited November 22
    @oleg Gideros also has a different type of co-routine ("fake threads") that doesn't need a yield - it auto yields. The Lua code runs in unused time between frame events. See:
    http://docs.giderosmobile.com/reference/gideros/Core/asyncCall#Core.asyncCall
    You can have multiple fake threads running, when it reaches the end of the code it's automatically removed. It's akin to time slices, not parallel.

    Aye: oleg

    +1 -1 (+1 / -0 )
  • For a beginner I would still go with a simple Finite State Machine :)
    +1 -1 (+1 / -0 )
  • john26john26 Maintainer
    edited November 30
    Yes, for card games or strategy games, anything which is turn based or sequential you need to use coroutines (Core.asyncCall). Using ENTER_FRAME or GTween will soon give you an unmaintainable mess. Here's an example of sequential (and concurrent) animation using coroutines each of which acts as a thread.

    http://giderosmobile.com/forum/discussion/comment/48666#Comment_48666

    Aye: oleg

    +1 -1 (+1 / -0 )
Sign In or Register to comment.