State machine AI for multiple enemies

Welcome to our brand new Clickteam Community Hub! We hope you will enjoy using the new features, which we will be further expanding in the coming months.

A few features including Passport are unavailable initially whilst we monitor stability of the new platform, we hope to bring these online very soon. Small issues will crop up following the import from our old system, including some message formatting, translation accuracy and other things.

Thank you for your patience whilst we've worked on this and we look forward to more exciting community developments soon!

Clickteam.
  • So, I've created a state machine for my player object using event groups and want to take a similar approach for coding enemy behaviours. The problem is (I assume anyway - haven't actually tested) that the code will activate/deactivate groups according to only the first enemy's state, and won't run the code for enemies in different states. The only work arounds I can think of are to either use loops or constantly check the enemy state - both of which involve having to repeat a line of code (i.e. "on loop" or "if state = ...") for every single event in the behaviour. I want to avoid that messiness and tedium if possible but not sure how to.

    Any thoughts?

    EDIT: Please login to see this link.

    Edited once, last by NoeL85 (March 17, 2017 at 3:02 AM).

  • Something I can clarify in the code?
    Cannot think of an easier way to achieve what's requested, or how to achieve group activation/deactivation without looping through each of the objects in some way =/

    If there is a way I would gladly like to know =)

    Edited once, last by Vease (March 16, 2017 at 10:20 PM).

  • Something I can clarify in the code?
    Cannot think of an easier way to achieve what's requested, or how to achieve group activation/deactivation without looping through each of the objects in some way =/

    If there is a way I would gladly like to know =)

    See my mfa.

  • Ahh.. sorry. My bad. Maybe I misunderstood the question.
    Thought the question was how to use groups for different actions, and use group activation/deactivation (which could be useful in more complex cases).

  • You could try putting the code within the enemy objects as a behaviour. Pretty sure that way the groups won't affect each instance. Someone here should be able to confirm this.


    I think that would work (maybe?) but from what I've heard behaviours are very messy/buggy and should be avoided altogether. Which is a shame, because this sort of thing is why behaviours exist in the first place.

    Your example is so complex... working with only 4 events.


    Thank you. Maybe I'm not seeing it but this doesn't seem particularly helpful in my case. Your example is fine for actions that are one or maybe a couple of lines long, but for more complex multi-line behaviours I don't want to have to add "Action of [object] = ..." at the beginning of every event if there's a more elegant solution. I've added an example to my original post of my player state machine that uses groups (not that the enemy solution requires groups, that's just how I've broken up the player code. Rather than having "State of [player] = ..." at the beginning of every event, I have it once at the top that tells the machine which code to run this frame). Enemy behaviours won't be quite as complex (the player's movement code is nearly 200 lines) but they'd still have several different states with several lines of code for each.

    Hello, I have created an example of how I use to do this.
    Hope it helps =)


    Thanks, but this has the same problem too. Instead of "Action of [object] = ..." I have to put "On loop ..." at the beginning.

    I don't want to sound unappreciative, but the two solutions you guys gave are the two "unacceptable" solutions I already mentioned in the OP. :/

  • I'm far from the cleverest coder around these parts, so I may well be missing something, but I just can't see a way around your problem. The way I see it, the beauty of your original state machine is that it works 'automatically', in a sense. No matter what, Fusion will read and execute the code from beginning to end, once per cycle. So all you're doing is turning groups on/off before it gets there. It's a bit like releasing a marble at the top of a ramp, and then quickly running ahead of it to insert/remove various obstacles in its way. Throughout the whole thing, the marble remains 'dumb': all it does is roll, once, from start to finish, with no idea of the frantic work you've just done in setting up its itinerary.

    But what you're proposing with these enemies requires that the marble no longer be 'dumb'. Now, running code once per cycle, from start to finish, isn't enough. The marble can no longer be be allowed to merely run its natural course, but now needs to skip ahead, backtrack, and re-run various parts of the ramp many times, all in the same cycle. I just don't see how you can get the marble to do these new acrobatics, without doing something like what Vease and Patrice have suggested. The marble now needs 'signposts' to help it navigate its new, much more complicated journey, and things like "on loop" or "if state = " are those signposts.

    Is copying-pasting one line at the start of a whole bunch of events really that much of a problem? If it is, I wonder if one of the "Function" extensions would help you. I've never used them myself, but from what I can (hazily) remember of my Actionscript days, a function is perhaps what you're after. There are a few different function objects in the Extension Manager - maybe have a play with one of them.

    Please login to see this link.
    My Fusion Tools: Please login to see this link. | Please login to see this link. | Please login to see this link.

    Edited once, last by Volnaiskra (March 17, 2017 at 6:15 AM).

  • I like Volnaiskras marble analogy and think it descibes the scenario quite well.

    I can recognize 2 ways of implementing a State Machine for multiple enemy instances.
    The question of using Loops or not is unrelevant from my point of view, as you can often avoid using Loops by taking goog advantage og AlterableValues.


    #1
    ( as mentioned previously )
    For all Events that belong to a particular State, add a Condition "State=..." on top of that Event.

    I didnt read everything too carefully so forgive me if im wrong here, but i understand that you are worried about (A) code looking messy and (B) Events running unessesarily when States are inactive and potentially resulting in some kind og lag/ slowdown of the Application.

    -A-
    I wouldnt worry much about the extra condition on Events using thos method. If your using this method this is the way it has to be, but it only means you have to insert this extra Condition ( State=... ) for Events relating to Enemies behaviour/ AI and not ALL events.
    Code 'will' get messy, try to make the best out of it.

    -B-
    I wouldnt worry much about this if you do it correctly,considder theese Events and let me explain:

    EVENT#1
    + State = 5
    + Enemy ShotsFired =< 3*NumberOfEnemies+1/ ClipSize
    + Enemy is overlapping Player
    -> Do some Action...

    EVENT#2
    + State = 5
    + Enemy is overlapping Player
    -> Do some Action

    Fusion runns Events and Condition from top to bottom.
    - If no Enemies have State=5, the only part of the Events that will get checked is 'is State=5?' ( wich will be False ) and Fusion will skip the rest of the Conditions ( Fusion will not use resources to do the calculation or perform the colision check ) and move on to tje next Event below.
    So nothing is running unessesarily or eating wast resorces as long as the 'fundemental' Condition in this case ( State=... ) is placed First.
    - in the case that 2 of 5 Enemies have State=5, Fusion will first select the 2 Enemies and then perform the calculation and colision check for theese 2 Enemies.


    #2
    ( also as mentioned previously ) Implement the Enemies State Machine code/ behavior inside the Enemies 'Behavior Event Editor'.
    I have not used this method before, bit i assume it will enable/ dissble GroupsOfEvents dynamically.
    Id be more than happy to test this and provide an example when im back.

    Ive also heard there are some ( minor maybe ) issues with Behaviour Events, but it should be a perfectly valid way to code.
    One thing i would like to 'stress' however ( if choosing to work with Behaviour Events is this:

    Fusion checks Events from top to bottom, and the ordet your Events are triggered do matter and can be critical ( especially for large or complex creatoons ).

    There a few different Event Editors, and its wize to know in what order they are checked.

    I will list them here in the order ther are checked:
    - Frame Events
    - Global Events
    - Behaviour Events

    Also note that if you choose to work woth multiple Event Editors, you need to jump back and forth between them to get a complete overview of whats going on ( as opposet to using only 1 of the Editors to have 1 compleete list of all your code ), but if you know what your doing or have planned carefully this shouldnt be a huge issue.

    I reserve the right to be wrong about any of this, and please correct me if im wrong.

    Hope this helps.
    Huggs and kisses

    How can i change username and display name?
    Please login to see this link.

  • Thanks for the feedback guys - some nice insight into things. I think, after doing a bit of looking around, that Behaviours are definitely the way to go here. I can't immediately think of any reason I'd need behaviour code to come before anything else and in any sense I can work around that. Having the code split up doesn't bother me too much either, so all the negatives people have said about behaviours don't seem applicable here - especially when there's a big upside to doing it this way.

  • Yep, I just tried it, and qualifiers don't seem to work in behaviours.

    Personally, behaviours to me seem like a messier solution than all the others. They're fiddly to get to, they're easy to forget about or neglect, there's no easy way to jump to them with a hotkey from the other editors, they fragment your code, they can't handle qualifiers. I dunno, that just doesn't seem as elegant as, say, BartekB's example above. Just my 2 cents though.

    Please login to see this link.
    My Fusion Tools: Please login to see this link. | Please login to see this link. | Please login to see this link.

  • There is a workaround to get qualifiers in behaviours and global events, there's a forum post somewhere explaining it but weirdly i cant find it

    Please login to see this link.
    Please login to see this link.|Please login to see this link.|Please login to see this link.

  • I tested to see if 'Behaviour Events' for Instances handle 'Group Of Events' seperatly ( see example ).
    According to the test it does not.

    It appears that the 'Behaviour Events' for an Object is global for all Instances of the Object.
    In the context of this thread it means that if 1 Enemy Instance changes from one State to another ( Deactivates one Group and Activates another ), this happens for all other Instances as well.

    ...
    I had another idea, about creating new Behaviours for each of the States and simply switch between the behaviours to swich States.
    I'm not sure this will work any better but am not able to test this as I cant find any way to swich/ activate/ deactivate behaviours from the Event Editor.

  • Hey, am I late? I have this mini example (If I understood correctly): Please login to see this attachment.


    Thanks, but this has the same problem as other suggested solutions (i.e. needing to repeat a line of code for every single event in each state).

    Yep, I just tried it, and qualifiers don't seem to work in behaviours.

    Personally, behaviours to me seem like a messier solution than all the others. They're fiddly to get to, they're easy to forget about or neglect, there's no easy way to jump to them with a hotkey from the other editors, they fragment your code, they can't handle qualifiers. I dunno, that just doesn't seem as elegant as, say, BartekB's example above. Just my 2 cents though.

    The lack of qualifiers isn't a problem, and in OOP you'd want the code inside the object to only relate to itself anyway. You can easily put general qualifier code in the main sheet - something like "Group.Bullet collides with Group.Enemies -> set DamageModifier("Group.Enemies") to Damage("Group.Bullet")" then have code inside the enemy behaviour that handles the damage (e.g. "DamageModifier <> 0 -> Subtract DamageModifer from HP"). It does break up the code, but having a "Group Interactions" group at the bottom that handles all that keeps it as clean as you'd need (it should only be a handful of lines anyway). And I'm not suggesting BartekB's code is without merit, and in certain situations it'll be fine. But if a single enemy has, say, 50 events controlling it's behaviour, and you have dozens of enemies... having to add "If State = ..." hundreds or thousands of times doesn't seem like fun.

    I tested to see if 'Behaviour Events' for Instances handle 'Group Of Events' seperatly ( see example ).
    According to the test it does not.

    It appears that the 'Behaviour Events' for an Object is global for all Instances of the Object.
    In the context of this thread it means that if 1 Enemy Instance changes from one State to another ( Deactivates one Group and Activates another ), this happens for all other Instances as well.

    ...
    I had another idea, about creating new Behaviours for each of the States and simply switch between the behaviours to swich States.
    I'm not sure this will work any better but am not able to test this as I cant find any way to swich/ activate/ deactivate behaviours from the Event Editor.


    Well that's a bit of a bugger. Scratch the idea of using groups then.

    From what I've seen there's no way to toggle individual behaviours either, so that can be ruled out too. I guess Fusion wasn't designed with state machines in mind!

    Another option I just thought of is to have entirely different actives for each state (you could even have a separate active to store all object's values so you don't need transfer all that data over to the new active whenever you switch states). Though, this is potentially even less elegant than repeating lines of code... but maybe not. Worth experimenting with.

  • The idea about replacing an Active Object to change State is an interesting one.

    You have a qualifyer on each of the AOs that can reffer to the Enemy in general, while State specific code could reffer to the specific AOs representing the State.

    A potentiall ( am not sure but thiink it will be an issue ) issue with this would be frequent fram drops/ lag as muliple enemies change states, due to the fact that a new AO with a new set of graphics and animations will be loaded on each State change.
    It depends on the graphical size of the AO an number of Frames/ Animations it has of cource, for example if its 2-3 animations per State with 5 Frames per animation i dont think it would impact performance much.

    Transferring data from one AO to another uppin State change is unproblematic.

    Id like to suggest however to just roll with State change based on an AltValue and just accept the extra conditions youll have to add.
    Its not really that bad at all, CF is very powerfull and lets you create excellent fuctionallity in very short time, and the extra conditions youll have to add doesnt really deduct you or set you back much in terms of time or days.
    It could be much worse.

    How can i change username and display name?
    Please login to see this link.

  • Entirely new actives for each different states is not a good idea. Creating and destroying objects is quite expensive on performance so I don't recommend it.

    Anyway, I think what you're asking for is a condition for multiple events/actions. I believe Fusion 3 already has this covered named "Child Events": Please login to see this link.

    - BartekB

    Join the Click Converse Discord! - Please login to see this link.

  • For toggling behaviours, can't you just do a version of your original state machine?

    Say your enemy has 3 different behaviours. In each of the 3 event sheets, you put all of the code into a folder, and then you add a line at the very top that switches the group on/off depending on state.

    Please login to see this link.
    My Fusion Tools: Please login to see this link. | Please login to see this link. | Please login to see this link.

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!