playMaker

Author Topic: RunThisFrame Boolean suggestion.  (Read 4069 times)

Murcho

  • 1.2 Beta
  • Junior Playmaker
  • *
  • Posts: 54
    • View Profile
RunThisFrame Boolean suggestion.
« on: March 24, 2011, 10:11:44 PM »
Suggestion here thats open for discussion.

I quite often find myself having to create new states with almost identical logic to handle one action in the state turning on and off.  E.G. I have a "power up bar" that is counting up every frame.  Now during the power up state I'd like to put an interrupt in that stops the counting, then turn it on shortly afterwards.  In order to handle this now I need to leave my current state, wait, then return to the state.  This is compounded when I have multiple branches handling the count up (the count up monitors the rotation of another object and has to handle when the angle goes from 360 to 0).

So I guess what I'm after is the ability to link a boolean to a "RunThisFrame" option, that allows you to easily handle turning on and off an individual action.  I know you can manually turn an action on and off, but having a more programatic way of handling this would reduce the amount of work needing to be done overall.

Thoughts?  Anyone have a way of handling this already?

Alex Chouls

  • Administrator
  • Hero Member
  • *****
  • Posts: 3202
  • Official Playmaker Support
    • View Profile
    • LinkedIn
Re: RunThisFrame Boolean suggestion.
« Reply #1 on: March 25, 2011, 08:57:42 AM »
One quick trick to embed some boolean behavior into a state is with Convert Bool to XXX. E.g., Convert Bool to Float could set a deltaPower variable to 0 or 10 depending on the value of a Paused variable.

Another more flexible strategy is to split it into 2 FSMs. E.g., a View FSM and Controller FSM to use the view/controller pattern. I often find I have more visual states than logical states, so rather than tying them together, make it 2 FSMs that talk to each other. Or another way to look at it: when you find yourself copy/pasting code you think about refactoring that code into a method - when you find yourself duplicating actions, you might want to consider making a separate FSM.

A third strategy would use the Next Frame action to execute a few states all in one update. E.g., Calculate deltaPower state, goes to draw power state, and at the end of the draw state a Next Frame action goes to the deltaPower state to kick the loop off again in the next frame. So every frame you're executing the calculate and draw states. To be honest I don't use this pattern myself very much - it fights a little with the FSM idea of one active state. I tend to prefer the multiple FSM approach, it feels cleaner to me... but it's good to know your options.

Actually this topic got me thinking about FSM patterns. It would be cool to collect common FSM patterns in a thread (with diagrams and explanations). Eventually those could make it into the tool as templates...

Murcho

  • 1.2 Beta
  • Junior Playmaker
  • *
  • Posts: 54
    • View Profile
Re: RunThisFrame Boolean suggestion.
« Reply #2 on: March 25, 2011, 06:33:11 PM »
The third strategy was the way I was going to go, but it feels messy to me, and doesn't really feel like correct way to work. 

Whenever I've written state machines before, each state could have some small amount of branching logic within itself.  I guess to be true to the pattern it should have been split into two other states, but that somehow felt incorrect.  Maybe this is me just being lazy not wanting to deal with more FSMs/States, or being pedantic about trying to keep everything tidy.

I think a thread on patterns would be very useful though.

e.Ko

  • Administrator
  • Playmaker Newbie
  • *****
  • Posts: 13
    • View Profile
Re: RunThisFrame Boolean suggestion.
« Reply #3 on: March 27, 2011, 08:10:09 AM »
Ultimately Playmaker will have a hierarchical FSM - so you can double click on a state and get a whole new fsm. This will let you go crazy with logic inside states. Right now you can do it manually using a separate FSM and the Enable FSM action. It might help to think of your FSM hierarchically - What logic do I need to perform while in this state? Are there sub-states? - and use the separate FSM/EnableFSM pattern to build it.

Murcho

  • 1.2 Beta
  • Junior Playmaker
  • *
  • Posts: 54
    • View Profile
Re: RunThisFrame Boolean suggestion.
« Reply #4 on: March 27, 2011, 06:59:56 PM »
Now this sounds a lot more like what I'm looking for.  As I was writing my posts I was always thinking "shouldn't I be able to embed an FSM inside a state", and I can technically right now, it's just not the most elegant way of setting it up in the editor.

I look forward to the hierarchical FSM's in the future!

MaDDoX

  • 1.2 Beta
  • Full Member
  • *
  • Posts: 165
    • View Profile
    • FluidPlay Studios
Re: RunThisFrame Boolean suggestion.
« Reply #5 on: March 27, 2011, 11:59:18 PM »
Ultimately Playmaker will have a hierarchical FSM - so you can double click on a state and get a whole new fsm. This will let you go crazy with logic inside states. Right now you can do it manually using a separate FSM and the Enable FSM action. It might help to think of your FSM hierarchically - What logic do I need to perform while in this state? Are there sub-states? - and use the separate FSM/EnableFSM pattern to build it.

Feel free to correct me if I'm wrong, but that's how I understand it currently: each FSM contains a single logical block, a number of instructions executed sequentially. That would be a bunch of lines of code surrounded by brackets, if you code in C#. Now, considering there's no nesting, if you want an IF-THEN-ELSE you can get it inside the same FSM only if (pun intended) the THEN (yes) and the ELSE (no) result can be executed with a single command. If not you basically have to create a state just for that "code block". Or execute the IF multiple times, which is less than optimal to say the least.

That said, having multiple states is the right thing to do at times, but when you fire an event you drive the execution flow to it entirely - in practice it's an old-school GOTO. No big deal, I actually enjoy GOTOs (that's how I learned to code when I was 6 and there was no "structured coding" thing) as long as they use labels instead of being tied to line numbers, which is the case ;) Now, if you want to do a "GOSUB", ie. run another chunk of code and once done get back to the same point you are now, or if you want to do a "Start Coroutine" ie. run another chunk of code in parallel without disrupting the current logical block execution, you need to use a secondary FSM. That's closer to "OO" (object oriented) coding in the sense that you refactor (cut and paste elsewhere) a chunk of code not to another function in the same "text file", but to a completely different "text file". I see two main disadvantages in the OO approach. The first is exactly that it stresses the parameters traffic, making it more human-error prone, although that's heavily alleviated by code completion (intellisense) if you use Visual Studio or a similar IDE. If you're still on Notepad, forget it, you'll at the very least be VERY inefficient trying to code with it. Now, that's not a problem in visual script editors like PlayMaker for the obvious reason that it already uses drag-and-drop and dropdown combo boxes. The second disadvantage is that you tend to focus on the leaves instead of the trees and start losing the "panoramic view" of code flow, which's especially bad for design and analysis. Back to the PlayMaker case, if we had different panels (think dual- or quad-view in a 3D program) to inspect different FSMs side to side, that would work things out beautifully. You would then be able to edit, say, the "PlayerShipTurret" fsM right next to the "PlayerProjectileTurret" and perfectly visualize/understand the correlation between the two.

The nested FSM idea sounds nice for simple stuff where a whole new FSM seems overkill, but wouldn't it just clutter the FSM list? Maybe if we could filter it out in the list, not sure, anyways it might be best to simply have another "structure" for that, maybe call it subFSM or something.

PS.: Excuse me, but is e.Ko the same as Alex Chouls? I mean, if it's not I guess you haven't properly introduced yourself mr e.Ko :)
« Last Edit: March 28, 2011, 12:47:11 AM by MaDDoX »
--
Breno "MaDDoX" Azevedo
@brenoazevedo

Alex Chouls

  • Administrator
  • Hero Member
  • *****
  • Posts: 3202
  • Official Playmaker Support
    • View Profile
    • LinkedIn
Re: RunThisFrame Boolean suggestion.
« Reply #6 on: March 28, 2011, 11:55:17 AM »
eKo is co-founder of Hutong Games - I was reading on her computer and accidentally posted with her username. I'm sure eKo will introduce herself on the forums when she has a free moment... :)

Being able to see FSMs side by side would be very useful. We'd also like to have a project style view, one level up from the FSM graph view, that shows all FSMs in the project and their relationships...

It's often useful to understand the design problems/choices that drove the development of a tool - it can give you a better mental picture of how to use it. So here's a quick overview:

The State Inspector was designed to work like the Unity Inspector, so it feels familiar. The Unity Inspector is great, but it has no concept of state -you set up and tweak all your behaviors for one implicit state (e.g., run around and shoot) and then have to come up with some system for changing state (what happens when I'm climbing, or falling, or dead...), which mostly means hard-coding state changes in scripts where they're hard to visualize and maintain.

Most games have to manage a lot of state changes - input, AI, animations, game modes, object states etc. Really it's all these state changes that add up to a game! So the goal with Playmaker was to expand the Inspector panel idea to allow easy authoring of state changes. That's the model that drove the Graph View and State Inspector - the ability to author a set of Actions to perform when in a state, with clear transition events to other states.

Making the actions more modular and executing them in sequence allowed Actions to be combined in interesting ways, while retaining a familiar simplicity - basically if you can use the Unity Inspector, you can build states in Playmaker - at least that's the idea!

I like how simple (yet powerful) this model is in practice, but obviously we will continue to enhance it as Playmaker evolves. Thinking about multiple simple FSMs that talk to each other is definitely the strategy I would pursue - and then when Playmaker supports hierarchical FSMs you'll be well placed to take advantage...




MaDDoX

  • 1.2 Beta
  • Full Member
  • *
  • Posts: 165
    • View Profile
    • FluidPlay Studios
Re: RunThisFrame Boolean suggestion.
« Reply #7 on: March 29, 2011, 07:09:48 AM »
Making the actions more modular and executing them in sequence allowed Actions to be combined in interesting ways, while retaining a familiar simplicity - basically if you can use the Unity Inspector, you can build states in Playmaker - at least that's the idea!
Alex, don't get me wrong, I really like the list model simplicity - hey, isn't that what we use to code anyways, a simple list of lines? :) I also think I've already grasped the concept of PlayMaker. After spending the weekend on it, yesterday I've taught to one of our coders how the tool worked in finer detail than what we've checked during the beta and he got positively impressed by its flexibility and power.

I'm really just curious about how much we can push the tool into visual-coding-land, and as you can see I'm quite pushy when I enjoy something heh. So, there are a couple questions and ideas still floating in my mind about it, and most of them related to state changes and flow control. As follows:

- Supposing I want to emulate a "Go Subroutine", that's how I'd do it: I'd have the main routine splits in states A and C, with the "gosub" condition at the end of state A (right before a sequence event to state C), and the gosub routine at state B. Flow would then go as A -> B -> C. This would work fine I imagine, but maybe we could have a "wait for event completion" action to spare us from the maintenance trouble of having to split states every time we need to branch the actions execution like that? I imagine you might not like the idea since it kinda challenges the concept of "states" and probably require some type of feedback (maybe yellow stroke around the paused state?), but I think it'd be quite useful in practice.

- My fellow coder pointed to the fact that FSMs are just like scene binary files and hence can't be merged in GIT (the version control we use). Personally I don't see a problem since we intend to keep only the highest level operations - which I'll be doing single-handed - in the FSMs. Apparently he's scared of Unity's "lose component settings for no apparent reason" oddity which happens from time to time, so he asked me if the FSM settings could be exported to text as a backup. Would templates be any good for that or they just hold the states structure and not the actions/variable values? And are templates saved in text format?

- You mentioned previously that you have arrays inside PlayMaker, and even cited a couple actions which give employ lists in a way or another. How do you intend to expand and give us better access to those collections? I do miss variable arrays at times.

- "Next Frame Event" is still a mystery to me. I know it's supposed to be a way to execute multiple actions in the same logical frame, but description is really ambiguous, how is it supposed to be setup for that? It looks as if you'd define a custom event in the end of the actions list for the event and then loop it back to the state. But what does that mean, that all actions in the list take one logical frame and that the state transition regularly takes more than one logical frame to be performed (and next frame event would be a way to circumvent this)? That's a bit much guesswork for me, so it'd be cool if you can shed some light for us here :)
--
Breno "MaDDoX" Azevedo
@brenoazevedo

e.Ko

  • Administrator
  • Playmaker Newbie
  • *****
  • Posts: 13
    • View Profile
Re: RunThisFrame Boolean suggestion.
« Reply #8 on: March 29, 2011, 10:03:59 AM »
I think multiple FSMs is the way to go for "gosub" functionality.

Here's an example:

Recently I was working on a sample scene with an RC car control. I started off making one FSM for the controller, but it was getting too complex for my liking. So I split the Accelerator off into its own FSM. The accelerator has it's own states and basically calculates the acceleration at any given time, given user input, deceleration etc. Now in the main Controller FSM, I use Get Fsm Float to get the current acceleration from the Accelerator FSM to apply to the car. What was becoming one quite complex FSM, turned into 2 very simple FSMs.

So when thinking about the subroutine ask if it can be it's own FSM.

Note this also helps you to avoid splitting a state the way you describe. When you send an event to another FSM it is processed immediately then execution returns to the calling FSM. So, for example, you can send an event to another FSM (and data using Set Event Data), and that FSM can run its logic, and control will return after that event is fully processed (all OnEnters have been called). The calling FSM can then get a variable from that FSM, do something based on that FSM's new state (using Fsm State Switch), etc. It's fairly equivalent to a gosub or a function call...

Splitting logic into separate FSMs like this really makes life simpler. It's probably my number one guiding principle in designing FSMs!

Another reason to take this approach is you will generally add states to an FSM over the course of development. If you have to weave those new states into a big FSM it can get messy... but if you've split the problem into parallel FSMs it can be trivial to add these states. Making it easier to add states, even later in development, is one goal of Playmaker (traditionally it gets scarier to add these states because you can't visualize/debug the consequences very easily).

Another example:

You have a light that you want to turn off/on, so you make a simple On/Off FSM. Later you decide you want to control the light color as well... you could add this to the On/Off FSM, but the states and transitions will start to multiply... or you could make a new Color Control FSM...

Anyway, I think you get the idea. The same goes for states, it's often tempting to keep adding actions to a state even when it would be clearer and more maintainable to add more states. Over the course of a project clarity/maintainability is always worth the extra up front time... And again, if a state feels like it needs lots of actions and needs to run all the time, maybe it should be it's own FSM :)

Templates:

In 1.1 all FSM data is stored in a template (missing variables was actually a bug!). Templates are derived from ScriptableObject, like GUISkins. So they are assets that can be backed up, copied etc. But they are binary.

At some point I do want to implement a text dump of a project/fsm (to send with bug reports, to do diffs on etc.).

Arrays/Lists:

You can use arrays in custom actions (just declare a public array field), but you can't pass them around as Fsm Variables yet. The plan is to support a List Fsm Variable type that you would add like any other variable in the Variable Manager. We're likely to implement an Object Pool system before that though, which will handle many cases where you need a collection of game objects... But, yes, I want List Fsm Variables too!

Next Frame Event:

This action is most useful when you need to loop through a few states every update without creating an infinite loop. Putting Next Frame Event at the end of the loop breaks you out of the loop until the next update. IOW, the whole loop will be processed once per update.

I'll try to make a sample that demonstrates the idea.

Honestly, I'm a little wary of this action! It blurs the line between FSM and visual coding, and can easily be abused to make messy state machines with no real state, just a mess of "code". I really believe the organizing power and discipline of FSMs help you better build, debug, and maintain behaviors. But I figure it's better to have this action, than not...

-Alex (on e.Kos machine!).



MaDDoX

  • 1.2 Beta
  • Full Member
  • *
  • Posts: 165
    • View Profile
    • FluidPlay Studios
Re: RunThisFrame Boolean suggestion.
« Reply #9 on: March 30, 2011, 09:52:23 AM »
Thanks for the detailed reply Alex. Yeah, I am already trying to split among multiple FSMs as much as possible. For me the trick is spending lots of time on paper before jumping into PlayMaker. That's really the way to go in my opinion since, on paper, you can have all FSMs "open" at once, and easily draw connection "wirings" among them ;)

For larger code blocks I completely agree with you. I'm more concerned to the really trivial/tiny code blocks, two-three lines of code. I'll give an example. In a pong-like game we're developing, we have a main game controller FSM. One of this FSM's states is "PointScored". In this state I want to do (in pseudo-code):
If iCurrentPlayer = 1:
   iScoringPlayer = 2
   iScoreP1 = iScoreP1+1
else
   iScoringPlayer = 1
   iScoreP2 = iScoreP2+1


BTW, I use iScoringPlayer to define what animation will be played on an specific in-game character, that's why I need it. To convert that to PlayMaker terms I would try something like this:

<<suppose I already have a boolean bCurrentPlayerIs1 defined in a main gamedata FSM and read by the state once initialized>>
- Convert Bool To Int (bCurrentPlayerIs1, iScoringPlayer, True Value = 1, False Value = 2)

Which's kinda of an encryptic/hacky way to change a value according to a boolean, but it's okay. Now, I don't see any option to selectively add a point to one or the other player's score in the same state, I really need to have separate states as such:

State: PointScored
- IntSwitch(1, Player1Scored, Player2Scored)

State: Player1Scored
- SetIntValue (iScoringPlayer,1)
- IntAdd (iScoreP1,1)

State: Player2Scored (Same as above, just for Player 2)


That makes it three states for what in my mind should be just one, since it's the same "logic step". Any other FSM wouldn't know it's on the designed "PointScored" state since it could actually be in either of these three states. Which makes me add another boolean variable set to true initially in the 'parent' state and set to false at the end of Player1Scored and Player2Scored, and make this flag variable the only thing that mattered for other FSMs. You *could* name those states in a base+suffix way and, after getting the FSM state name process the substring but.. c'mon!

I think it'd be much better if we had a structure similar to GUILayout Start -- GUILayout End for actions. So we'd had versions of the current state-switching logic actions as such:
Float Changed Start <test defined here>
- Action 1 < visual offset or small icon added to the right, like an indent >
- Action 2 < same as above >
Float Changed End
Rest of Code

Of course this *could* lead to nested Mayhems, but one can already do so with GUILayout anyways, and to be honest any code-flow development tool can be misused no matter how hard you try to prevent that. I don't think smart users should pay for the mistakes of the non-smart ones :) Anyways, any form of sub-state / code container that doesn't switch the actual state still seems more useful and manageable than sub-FSMs and a myriad of boolean or string variables to hold the "logical state".

As for using FSMs for gosub/module/class functionality. If I got your proposal right, you'd switch another FSM on (Enable FSM / reset on exit), which would simply execute a bunch of actions. Sounds good, but wouldn't that present problems to other state machines trying to poll the state or variables inside the calling FSM? Or do disabling FSMs simply disables the execution of actions but still keep them available for state and variable polling? It'd be quite interesting if that's the case, but for proper behavior we'd still need to know what FSM issued the enabling call, or else how can we call an FSM (as a procedure) from various different FSMs and make sure the right one will be disabled? Maybe by sending an event + info first? Hmm...

Quote
Next Frame Event: This action is most useful when you need to loop through a few states every update without creating an infinite loop. Putting Next Frame Event at the end of the loop breaks you out of the loop until the next update. IOW, the whole loop will be processed once per update.
Man, I still don't get you clearly, guess I'll really need that example! As I understand it, there are only two "forms of execution" in the life cycle of a state, instructions executed right away once entering the state - without the 'every frame' option checked - which are run on start (Unity API term) and the ones that are executed every frame, be it update or lateupdate (Unity API). If your state has no "FINISHED" connection, that's very easy to understand. Now, when you have a FINISHED connection to the same state (forming a loop) things get a little blurry in my mind. How fast does that go? From what you said the loop could potentially run may times per logical frame, since you mention multiple state transitions could run in the same logical frame. Then you use Next Frame Event to "close" the loop and wait for the next logical frame update, is that it?

Anyways, sorry for the long posts, I'm just trying to better understand how things are supposed to work now and in the future - and hopefully provide some helpful feedback in the process. Keep up the amazing work!
--
Breno "MaDDoX" Azevedo
@brenoazevedo