How do I make a simple FSM?

  • Hi guys!

    I want to make a simple multimedia game.

    This works like an audiobook with a choice of scene by the player.

    I have a problem with finite state machine.

    Something I do not understand and therefore I ask you for help.

    The project is built very simply:

    • I have many scenes.
    • Each scene consists of background sound and subsequent speech sounds. Some of them are randomized to make the narrative more attractive when someone plays again.
    • The player doesn't need to hear all the sounds of speech. He can decide to change the scene while listening to the speech.

    To start building the project I used RexRainbow FSM plugin.

    It seemed to me that it would be easy, while I was stuck and didn't know how to deal with it.

    Please look at my little project:

    aum. pl /img /fsm .jpg

    Sorry, I had to give a four spaces in the address,

    otherwise the forum would not save my post.

    In startingPoint I play sounds, but if the player chooses the up arrow, the sounds should be muted and proceed to startingPointDoor.

    The problem is that only one sound of speech is muted, but the rest goes on.

    How to make the system "forget" about doing everything in the previous FSM scene and doing things with the new one FSM?

    I will be very grateful for any hints.

  • The problem is how you use 'wait'.

    You cant stop sounds that are not playing yet (they are somewhere in the 'wait' cue).

    And you cant stop actions that are postponed with a 'wait'.

    I see 3 solutions.

    1/

    Use the Timer behaviour. Timers can be stopped.

    2/

    Use a cue array. Difficult, but possible. Arrays can be cleared.

    3/

    Use wait as you do, but call functions and pair this functions with a condition that looks if the function can run.

    You have that FSM machine (i dont understand that one for 100% myself, but ....)

    Say we are in the state 'StartPoint", when wanting to play those sounds.

    So if you do ....

    On enter state

    ____Wait 3 seconds

    ____Call function "Play" (add what to play as a parameter)

    ____Wait 1 seconds

    ____Call function "Play" (add what to play as a parameter)

    ____Wait 8 seconds

    ____Call function "Play" (add what to play as a parameter)

    On function "Play"

    System > Compare 2 values FSM.CurState = "StartPoint" (are we still in the right state ?)

    ____Play (by name) use the function parameters to fill in the info.

    You still have to stop the already playing sounds 'on exit state'

  • Thanks 99Instances2Go!

    I don't understand fully the timer behavior, so I decided to take advantage of the functions.

    And my project slowly starts to work as it should

    but I have more puzzles.

    Could you tell me please about following topics?

    1. I have a function to randomly play footsteps sounds.

    But only the first sound is playing.

    What I did wrong?

    aum. pl /img /fsm2 .jpg

    (I inserted 4 spaces as before)

    2. When you go to startingPointDoor, the up arrow key is still active.

    I do not know how to make the keys from the previous scene inactive.

    I suspected that I could move the event "on up arrow presed" to FSM "on enter to startingPoint". But this is impossible, the system displays a message:

    Some conditions were not moved. Due to restrictions of triggers, some of the conditions you dropped aren't allowed to be moved here.

    That is a big problem, because I assumed that FSM would help me to switch between scenes.

    And in each scene the arrow keys are used to switch to other scenes.

    3. When you go to startingPointDoor, you hear only background sound (komora-oczyszczajaca),

    And the sounds of speech were lost.

    I don't know why the function "playStartingPointDoor" does not work.

    I changed the value in the global variable.

    Gee, I didn't know it would be so complicated to arrange some sound files

  • 1 The 'on function' is a trigger. You can recognize a trigger because they always start with 'on' and they have that 'green arrow' in there events. Triggers are designed to catch something happening, and then they run once, and after that they wait till that 'something' happens again. In case of the 'On function', it runs once when called, after that it waits till it is called again. You just dont call it again.

    The 'complication' you wrestle with is not playing the sounds. It is the timings.

    Just ask yourself 2 things, at what time do i want to play a sound and, what is the scope of that sound in the current state. Out of scope ? Dont play it, and stop what is already playing.

    For the footsteps.

    They dont need a delayed start, they need to play at random intervals and they can only play when the current state = "StartPoint' (not sure about that last one, anyway)

    So lets bring this in conditions.

    On Enter "StartPoint" < things associated with this state we going to make happen.

    _________ play sound with tag "Steps"

    On ended "Steps" <---- a trigger ! in a new root event

    System > Compare 2 values FSM.CurState = "StartPoint" (are we still in the right state ?)

    _________ wait random time (as you wish)

    _________ play sound with tag "Steps"

    Ok, so, what happens.

    When we enter the State, we play 1 step.

    The trigger 'On ended' will catch the moment that "Steps" is done.

    So now it is time to play a new "step", but only if we are still in the right state. We wait a random time.

    If we dont play a new "Steps" (because we are not in the scope of the state), the trigger will just sit there and do nothing, virtual not touching the performance.

    If we do play a new "Steps" the Trigger will catch again the end of it, and so on ......

  • 2.

    You do have 5 kinds of events.

    An event that sets new states.

    An event that starts things up when entering the state. <--- a trigger

    An event that stop things when leaving the state. <-- a trigger

    An event that maintains code when in that state <----- got to check those every tick

    Restraining of events that are only allowed to run when in a certain state

    Set a new state < an action under a condition that decides the change

    The condition can be anything, a key press, a overlap with an object .... virtual any thing. Now the state is set. And the triggers in the plugin will catch that 'change of state'. So .....

    On enter (state)

    Anything that we want to happen only once when entering this state goes under this condition. Like changing an animation. Play a sound ..... etc

    On exit (state)

    Anything that we only once want to happen on exit. Like reversing an animation, stopping a sound from playing.

    An event that maintains code for that state /

    Anything that needs to be tested every tick as long as we are in that state goes here. Like a continuous checking if the player is overlapping a door.

    Typical this starts with a condition like

    System > Compare 2 values FSM.CurState = "StartPoint" (are we still in the right state ?)

    Restraining of events that are only allowed to run when in a certain state

    A 'on key pressed' is a trigger. A trigger should (not a rule, just what i think is good practice) always be the first condition in a root event. But then we need to constrain that trigger from running its events when not in the right state. Or assign actions depending on the state. That is typical something like, when assigning actions .....

    On key pressed (up arrow) <--------- root condition

    ___System > Compare 2 values FSM.CurState = "StartPoint" <---- sub condition

    __________ action simulate 8 direction go up

    ___System > Compare 2 values FSM.CurState = "InGame"

    __________ action simulate platform jump

    Or when just constraining a trigger

    On function "Play"

    System > Compare 2 values FSM.CurState = "StartPoint" (are we still in the right state ?)

    ____Play (by name) use the function parameters to fill in the info

    Hope this general approach will help you.

  • Wow! How much knowledge to understand!

    Thanks a lot! I learn with great pleasure.

    So far I have analyzed the matter with steps.

    I explain why I did it in this way:

    • Footsteps I need to play between some speech sounds.

    I can not play them all the time in one scene. Footsteps are interrupts, for example when the player goes to another room.

    • I thought that I would not be calling 10 times the random sound of footsteps, since there are functions.

    So I did the function, but it does not work.

    Is there no easy way to call X times this function randomly playing a sound?

  • Now the question is "How do i play a sequence of sounds, whenever i want, not depending on my FSM?"

    Global variable 'WalkThisWay', number = 0

    On Function "PlaySteps"

    _________ Set global 'WalkThisWay' to function parameter 0

    _________ play sound with tag "Steps"

    On ended "Steps"

    Global 'WalkThisWay' > zero ?

    _________ subtract 1 from 'WalkThisWay'

    _________ wait random time (as you wish)

    _________ play sound with tag "Steps"

    Call the function "PlaySteps" with parameter zero = amount of steps you want to walk, whenever you want.

    Set global 'WalkThisWay' to zero if you want to interrupt the steps sequence.

  • Thanks again 99Instances2Go!

    So I started to fold these blocks.

    I created and created and created and have created... a big mess...

    I broke everything so now the sounds are overlapping when I press the arrow-up.

    It may be a shame to admit, but I don't understand some of your commands.

    Maybe is there any tutorial about these states and switching between them?

    I ask because I do not want to be onerous and torture one man with dozens of questions.

  • Well, you are using a plugin that is not used that much.

    But i dont think that it is the FSM that you have a problem with.

    Still. There are tuts about FSM's .. like ...

    https://www.scirra.com/tutorials/1139/h ... e-machines

    Not sure why you want a FSM to play the sounds, i did't get that at first. I thought the 'playing sounds' was just 'another thing', besides the FSM. I thought that you had a problem stopping the sounds when leaving a state.

    The FSM is NOT a time manager.

  • Thanks again!

    I do not need to use the FSM plugin.

    I just thought it would be easier.

    I will write in a nutshell how the program should work, then could you guide me how to simply make it?

    Maybe I was wrong to start working with the FSM plugin?

    • As I mentioned before, this is an interactive audiobook.
    • The player moves from scene to scene. Each scene is a room, or a corridor, or a yard, etc. The player can return to one scene many times.
    • Each scene has a looped background sound. When the player starts the scene, the background sound may change. Then the old one is gently faded out, and the new one is faded in.
    • Each scene has arranged speech sounds. These are short sentences. I should be able to determine the gaps between them.
    • There must be footsteps sounds between some of scenes. Random sounds X times.
    • The player moves from one scene to the second one using the arrow keys.

    Sometimes player can choose only one scene, and sometimes can select one of four neighboring scenes.

    • The player does not have to listen to all speech sounds. I assume that once he was in a particular scene it might be tiring for him to listen again.

    So shortly after entering the scene he can choose another one.

    But that's only if the player was already in the scene before. Otherwise he must listen to the whole speech sounds.

    Is it easy to do for non programmer person?

  • I've had a bit of time so I was able to experiment with some stuff relating to this.

    Here's a reference capx

    Here are some suggestions about how to approach it using the capx as a reference.

    Sequencing audio was done using the Audio::Schedule next play expression. The example sounds I've used were very short sounds, but in your case, it is speech. So the important thing is to know how long each speech audio file is so you can schedule it appropriately. In the capx you will see "Schedule next play for Audio.CurrentTime+1". The +1 is 1 second. You should place as many seconds as it will need to play the audio file that you will play after that schedule action.

    Just an overview of how to organise the project's logic. It's a bit difficult to explain why something is organised they way it is. But the way I thought best to solve the problem is to figure out the basic functionality that you want from the project.

    1.) you want to be able to sequence sounds.

    2.) you want to be able to stop _only_ those sequence of sounds on a key press.

    3.) you want to play sounds before you switch scenes.

    4.) you want to play a background sound that doesn't change.

    For #1 you should be able to work out the technique to sequence the sounds. In the capx you'll see under the group "AUDIO FUNCTIONS" that that is how I approached it.

    For #2 you should be able to identify those sounds that are 'stoppable' by a user keypress. I've done this by using unique tags, and setting a integer variable to keep track of how many sounds are actually playing. For example, in StartFGAudio, I have 4x sounds playing, and tagged them p1, p2, p3, p4. Then I set a global variable ndxs to 4. This notes that there are 4x sounds playing.

    When I decide to stop the sounds, I use a for loop, concatenating 'p'&ndxs, which gives me p1, p2, p3, p4, and I use those strings to stop the audio.

    For #3 you want the same thing as #2, but you need a trigger to let you know when a certain audio has ended. In the function StartTransitionAudio, 2x audio is played (this is to simulate your 'footstep' audio). I play this as sequence, with the last audio having a unique tag called "transition_last". This is the tag that I'm going to be looking for in order to transition to the next scene.

    In the group AUDIO TRIGGERS, you will see the trigger there. And again, this only happens after the sound has ended. If you tried to do this in the StartAudioTransition function, the scene would have changed before the audio has stopped playing. If you like that behaviour then you can place the GoToScene function there.

    For #4, the background sound is played with its own unique tag. As long as you don't stop the audio with this tag, it will keep playing.

    Now, lastly, the overall organisation is putting things into their proper context, and I think that's why you had thought of using FSM. The basic idea that you were going for was to put something to a state, like a scene or layout, and have all the things related to that scene appear. That's fine, but the problem is that you still need to control everything else. So the FSM is not really necessary, but a clear indicator of what your state or scene is important.

    For me, I thought using a 'scene' global variable to determine my current scene. When I change this scene variable to something else, all the other functions that need context will change as needed. For example, when I call fn.Call("StartFGAudio",scene), the function will know what sound to play, because I told it to play the 'machine gun' audio when the current scene is "secondscene".

    But then I prefer to make a more general function called fn.Call("GoToScene",scene), because I can call fn.Call("StartFGAudio",scene) as well as load any other layout that's related to that scene.

    Anyway, I hope the capx explains it better than I have written.

  • nice read, thanks for the reference file.

  • Something close to what you want to do. Straightforward. I think all basics are in here. This is just an example, no more. States are all done with booleans. I should have used Global variables, instead of that brain, thats what i learned out of this.

    The rest you should be able to manage from you own briefing above.

    https://www.dropbox.com/s/il0w50tbjh3qa ... .capx?dl=0

  • Try Construct 3

    Develop games in your browser. Powerful, performant & highly capable.

    Try Now Construct 3 users don't see these ads
  • Wow! Thanks a lot guys!

    It is a great surprise that someone prepared a demonstration for me.

    I have more materials to learn and I see here two different approaches.

    Weekend will be mine!

    Thanks again!

Jump to:
Active Users
There are 1 visitors browsing this topic (0 users and 1 guests)