1. Hey! Guest! The 34th GMC Jam will take place between August 22nd, 12:00 UTC (Thursday noon) and August 26th, 12:00 UTC (Monday noon). Why not join in! Click here to find out more!
    Dismiss Notice

Is it okay to do a state system this way?

Discussion in 'Programming' started by Kamon145, Jul 17, 2019.

  1. Kamon145

    Kamon145 Member

    Joined:
    Jun 29, 2019
    Posts:
    50
    Hello everyone, I've been using a state system with a switch statement in my step event to keep things organized and only running what needs to run, Ive been doing it by setting up a variable in the "create" event thats something like
    state = "idle"
    with quotations indicating i am assigning a word, and in my step event:
    switch(state)
    {
    case "idle":
    {
    idle_script;
    }break;
    ect ect.. This system has been working for me but Ive been looking at how other people do it and most seem to include setting up enums or something similar. I have not found many examples of people doing it the way I have been doing it so that leads me to wonder, is there anything wrong with doing it the way Ive been doing it, with variables assigned to words? Will this cause me problems on bigger projects or is it just considered bad practice?
    Any input is appreciated, like I said I haven't really encountered any problems with this system.. yet.. But I would like to know ahead of time if there is a problem! Thanks!!
     
  2. Annoyed Grunt

    Annoyed Grunt Member

    Joined:
    Jun 20, 2016
    Posts:
    136
    It's better to use enums for the simple reason that doing so lets you take advantage of the syntax checking system. There are so many ways you can misspell a string, and if you do you'll see your switch jump to its default behavior for no apparent reason. You'll have to go in your code and find exactly where you typed it wrong. If you use an enum, instead, a nice syntax error will plop up when you try to compile telling you exactly where the issue is. It's simply more robust and, additionally, also cleaner and more aesthetically pleasing.
     
  3. Kamon145

    Kamon145 Member

    Joined:
    Jun 29, 2019
    Posts:
    50
    Ahh thank you, I will do some more research on enums and start switching to that method :)
    edit* One last thing though, are enums like global variables? Like if i had multiple player objects, all essentially coded the same, would I run into problems using the same enums for all players?
     
  4. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    I'd suggest a better approach.
    1. Have your states in scripts (ex: sm_idle)
    2. Create enums for each state and give script name as value
    Code:
    enum sm{
        idle = sm_idle,
        run = sm_run
    }
    
    3. Have variable that store current state:
    Code:
    state = sm.idle;
    
    4. And call your state in step event with one line:
    Code:
    script_execute(state);
    
    5. have conditions in state scripts for switching out to different state.

    That's all it takes to have a state machine.
     
  5. Annoyed Grunt

    Annoyed Grunt Member

    Joined:
    Jun 20, 2016
    Posts:
    136
    Yes, an enum is a global variable. There is functionally no difference between:

    Code:
    global.state_idle = 0;
    global.state_running = 1;
    global.state_jumping = 2;
    global.state_climbing = 3;
    ...
    
    And

    Code:
    enum State {
         idle,
         running,
         jumping,
         climbing
    }
    
    This is an ok method, but it falls short if you want to have objects with different behavior because you are essentially hardcoding the scripts. A more flexible way would be to add a sizeof entry to your enum:

    Code:
    enum State {
         idle,
         running,
         jumping,
         ...
         sizeof
    }
    
    Unless specified otherwise, enum entries are specified in order (the first one is 0, the second one is 1, etc), so adding a sizeof entry gives you the effective size of the enum. This lets us instantiate an array of the size of the enum. You can then by hand specify what script should be executed for each state.

    Code:
    ///@description Create Event of a Player
    state = State.idle;
    all_states = array_create(State.sizeof, noone);
    all_states[@ State.idle] = script_idle;
    all_states[@ State.running] = script_running;
    ...
    
    This is especially useful because it handles unused states automatically.

    Code:
    ///@description Step event (or wherever you execute the state machine) of Player
    var state_script = all_states[state];
    if state_script != noone {
         script_execute(state_script);
    }
    
    And you can also have default behavior if you replace noone with a default script.

    Code:
    all_states = array_create(State.sizeof, script_default);
    
     
  6. NeZvers

    NeZvers Member

    Joined:
    Mar 24, 2018
    Posts:
    320
    Well, that was an example. For myself I have different enums for different objects (ex: sm_camera.follow,sm_player.run).
     
  7. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,872
    Yeah enums are a much better choice as it is less error prone than strings due to autocomplete. As for state scripts, I generally do not create scripts for operations that need to be run in only once place ever, but may split its components into smaller parts if they are needed in multiple places. For example in a platformer, code fragments that are required by player and enemy instances both. So my state operation would look like:
    Code:
    // IN PLAYER STEP EVENT
    
    // Idle state.
    if(State == Player_State.Idle){
        // Check if standing on moving terrain tile.
        var On_Ground = scr_check_ground();
        var Move = scr_get_move();
        var Drop = scr_get_drop();
        var Jump = scr_get_jump();
        if(Move || Jump){
            scr_check_collision();
        }
        if(Move) State = Player_State.Move;
        if(Jump || Drop || !On_Ground) State = Player_State.Jump;
    }
    
    Getting those true/false return to the vars wouldn't be strictly necessary as I could do the tests inside other scripts too. I write it this way because it gives me a bit better overall view of how the states switch and what they do.
     
  8. Sabnock

    Sabnock Member

    Joined:
    Jul 21, 2016
    Posts:
    310
    if you declare your enums in a script called say ENUMS they are setup automatically when the program compiles
     
  9. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,872
    You can decalre the enums anywhere, basically. What the compiler does is, it sniffs out all the enum declarations (during a pass where it checks for code validity I suppose) then replaces all the references to enums with their actual values. The declarations themselves are dropped out as they're no longer needed. I used to declare all enums in init object but these days I do that in objects that use them as it feels a more proper context and makes it faster to find the exact declaration I want to change.
     
    Bentley likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice