-
Notifications
You must be signed in to change notification settings - Fork 10
Event
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:
Other concept(s):
NOTE:
The following examples use the direct method of changing states. You can read more about it in Organizing States.
There are two built-in events:
-
enter
: Executes upon entering a state. Can be thought of as the "Create" event for a state. -
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:
- 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!"
- 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.
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
andleave
events are not declared in the "idle" state, andenter
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();
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.
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.