Skip to content
Sohom Sahaun edited this page Nov 15, 2021 · 21 revisions

Type : Function

 

Events are functions that define the sets of behavior for each state. Events are declared in the state struct for each state.

Conceptually, events can be seen as GameMaker events (e.g. Create, Clean Up, Step, Draw GUI End), except user-defined events in SnowState needs to be called manually. Built-in events execute automatically, but you can choose to manually execute them or not execute them at all.

As you might already guess, there are two types of events:

  1. Built-in Events
  2. User-defined Events

Other concept(s):

 

NOTE:
The following examples use the direct method of changing states. You can read more about it in Organizing States.

 

Built-in Events

There are two built-in events:

  1. enter: Executes upon entering a state. Can be thought of as the "Create" event for a state.
  2. leave: Executes upon leaving a state. Can be thought of as the "Destroy" event for a state.

 

Built-in events execute automatically in two cases:

 

  1. After defining the initial state using .add().
fsm = new SnowState("idle");
fsm.add("idle", {
  enter: function() {
    show_debug_message("Hello!")
  }
}); // "Hello!"

You can choose to not execute that automatically using the optional second argument in the SnowState constructor.

fsm = new SnowState("idle", false);
fsm.add("idle", {
  enter: function() {
    show_debug_message("Hello!")
  }
});

And of course, the enter event can be invoked manually.

fsm.enter();  // "Hello!"

 

  1. Upon changing the state using .change().
fsm.change("yeet");

This executes the leave event of the current state, changes the state to "yeet", and executes the enter event of the "yeet" state. You can override both of these events using the optional arguments in the method.

fsm.change("yeet", function() {
  dead = true;
});

This overrides the default leave event of the current state and executes a different function, setting a variable dead to true. The default enter event of the "yeet" state is executed.

fsm.change("yeet", undefined, function() {
  yeetLevel = 99;
});

This executes the default leave event of the current state, but overrides the default enter event of the "yeet" state and executes a different function, setting a variable yeetLevel to 99.

fsm.change("yeet", function() {}, function() {});

This does not execute any of the enter and leave events.

 

User-defined Events

You can define your own events which need to be called manually. The event names could not be similar to the built-in members of SnowState. It will throw an error if you try to do so.

The intended use for events is to organize what will happen in a GameMaker object event.

/// Create
fsm = new SnowState("idle");

fsm.add("idle", {
  enter: function() {
    color = c_blue;
  },
  step: function() {
    angle = point_direction(x, y, mouse_x, mouse_y);
    if (player_has_moved) fsm.change("walk");
  },
  draw: function() {
    draw_sprite_ext(sprite_index, image_index, 0, 0, 1, 1, angle, color, image_alpha);
  }
});

fsm.add("walk", {
  step: function() {
    angle = point_direction(x, y, mouse_x, mouse_y);
    if (!player_has_moved) fsm.change("idle");
  },
  end_step: function() {
    x = player.x;
    y = player.y;
  },
  draw: function() {
    draw_sprite_ext(sprite_index, image_index, 0, 0, 1, 1, angle, color, image_alpha);
  },
  leave: function() {
    color = c_white;
  },
});

step, end_step and draw are user-defined events, so those have to be executed manually. In the actual GameMaker events in the object, we call the events:

/// Step
fsm.step();

/// End Step
fsm.end_step();

/// Draw
fsm.draw();

Note that:

  • You do not need to declare the events in every state. It's enough to declare the events in the states where you need them. For example, end_step and leave events are not declared in the "idle" state, and enter event is not declared in the "walk" state.

  • You do not need to name the events the same as the GameMaker events. You don't even need actual events to execute the events!

/// Create
fsm = new SnowState("idle");

fsm.add("idle", {
  enter: function() {
    color = c_blue;
  },
  whatever: function() {
    angle = point_direction(x, y, mouse_x, mouse_y);
    if (angle == 60) fsm.something_weird();
    if (player_has_moved) fsm.change("walk");
  },
  something_weird: function() {
    show_debug_message("Woah!");
  }
  name_it: function() {
    draw_sprite_ext(sprite_index, image_index, 0, 0, 1, 1, angle, color, image_alpha);
  }
});

fsm.add("walk", {
  whatever: function() {
    angle = point_direction(x, y, mouse_x, mouse_y);
    if (!player_has_moved) fsm.change("idle");
  },
  i_want_to: function() {
    x = player.x;
    y = player.y;
  },
  name_it: function() {
    draw_sprite_ext(sprite_index, image_index, 0, 0, 1, 1, angle, color, image_alpha);
  },
  leave: function() {
    color = c_white;
  },
});

/// Step
fsm.whatever();

/// End Step
fsm.i_want_to();

/// Draw
fsm.name_it();

 

Arguments in Event Functions

You can pass arguments in event functions!

/// Create
fsm.add("count_up", {
  count: function(_something) {
    show_debug_message(_something);
  }
});

/// Step
fsm.count(counter++);

This will show the value of counter increasing in the output log when the system is in "count_up" state.

 

Default Event Functions

Notice the first example in the previous section. We used the same draw event for all the states. That's a bit redundant, right? No worries, we can fix this.

Introducing... .event_set_default_function()!

The example can be updated to:

fsm = new SnowState("idle");

fsm.event_set_default_function("draw", function() {
    draw_sprite_ext(sprite_index, image_index, 0, 0, 1, 1, angle, color, image_alpha);
});

fsm.add("idle", {
  enter: function() {
    color = c_blue;
  },
  step: function() {
    angle = point_direction(x, y, mouse_x, mouse_y);
    if (player_has_moved) fsm.change("walk");
  }
});

fsm.add("walk", {
  step: function() {
    angle = point_direction(x, y, mouse_x, mouse_y);
    if (!player_has_moved) fsm.change("idle");
  },
  end_step: function() {
    x = player.x;
    y = player.y;
  },
  leave: function() {
    color = c_white;
  }
});

You can also override the default function.

fsm.add("invisible", {
  draw: function() {}
});

This will not draw anything in the "invisible" state.