-
Notifications
You must be signed in to change notification settings - Fork 19
3. Recipes
First, you should create a controller object that will handle our stage
- Create a new object, for example
obj_rm_stage_test - Set its parent object to
obj_rm_stage - Override User Event 0
User Event 0 is where we set up the stage. Start by calling setup_stage():
setup_stage(_name, _act_index, _bgm, _animals, _next_room, _progress_flag);Here's what each parameter does:
-
_name: stage name shown on the title card -
_act_index: act number starting from0-
0= Act 1 -
1= Act 2 -
2= Act 3 - Use
ACT_SINGLEif you don't want to display an act number
-
-
_bgm: background music -
_animals: array of animals dropped by badniks -
_next_room: room loaded after finishing the stage -
_progress_flag: unique value from1to255saved into the save file after completing the stage- Set it to
-1if you don't need to save progress
- Set it to
For example:
setup_stage("TUTORIAL", ACT_SINGLE, snd_bgm_ehz, [spr_animal_flicky, spr_animal_ricky], rm_level_select, 99);Now create a room for the stage. We'll call it rm_stage_test
- Create a separate instance layer for room controllers and place it at the very top of the layer list. GameMaker already creates one by default, so you can simply rename it to "System" if you want
- On this layer, outside the room boundaries, place:
obj_game-
obj_rm_stage_test
Make sure they're placed exactly in this order. These need to be the first instances created in the room
- Lock the layer. You most likely won't need to touch it again
- Create two tile layers:
- "Collision_Main"
- "Markers_Main"
- Assign the collision tile set to "Collision_Main", for example,
ts_collision_default. For your own tilesets, note that collision data must be generated in thescr_game_setup()script before it can be used - Assign
ts_markersto "Markers_Main" - Create another instance layer for gameplay objects
- Place
obj_player_spawnon this layer wherever you want the player to spawn
Your stage should now appear in the default menu! Load into it and see if everything works as expected. You can also change global.start_room inside scr_game_setup() if you want the game to load directly into the stage
You're done!
If you want loops or branching paths, you should create additional collision and marker layers:
- "Collision_A"
- "Collision_B"
- "Markers_A"
- "Markers_B"
You can look at the default Orbinaut stages to see how things like backgrounds, dynamic palettes and extra stage effects are set up.
All game objects in the framework should inherit from obj_gameobject or from another object that already inherits from obj_gameobject. Orbinaut provides four base parent types out of the box:
- Regular object
- Solid object
- Enemy object
- Projectile object
For all game objects, you can call event_animator() and event_culler() in the Create event to enable the animator and culling modules respectively. These functions should be called after event_inherited()
- Create a new object
- Set its parent object to
obj_gameobject - Inherit the Create event
The object's collision box will be used as its hitbox for interactions with other objects. To check for collision with the player, use collision_player()
- Create a new object
- Set its parent object to
obj_solid - Inherit the Create event
- Call
solid_object(_player, _type)in the Step event so the object can run its solid collision checks
The object's collision box will be used as the solid area the player collides with
If you want the solid to form a custom shape, override the solid_offsets array with values that shift the collision surface vertically across the full width of the solid's collision box
If you want to prevent the player from balancing on the edges of the object, set solid_balance to false
- Create a new object
- Set its parent object to
obj_enemy - Inherit the Create event
The enemy object will follow the default rules for how badniks react to players and to other conditions under which they can be destroyed. If you want custom behaviour, override the Step event
Bosses should also inherit from this base object, then override the Step event with their own behaviour and call react_to_players(REACT_TYPE.BOSS) to check for collisions with players
- Create a new object
- Set its parent object to
obj_projectile - Inherit the Create event
Projectile objects automatically react to all players. You can configure projectile's movement using vel_x, vel_y, and grv
You should add a character slot and register the character's type first. To do this:
- Open
obj_player's Create Event. - Find the
PLAYERenum. - Add a new enum entry and manually assign an index to it. For example, if we were to add Shadow, we would do this:
enum PLAYER
{
SONIC = 0,
TAILS = 1,
KNUCKLES = 2,
AMY = 3,
SHADOW = 4,
NONE = 255
}To make your character selectable from the Dev Menu, all you need to do is add two lines of code:
- Open
obj_rm_dev_menu's Create Event - Scroll all the way down and locate the initialisation function calls for category ID 4 (Player 1 Select) and category ID 5 (Player 2 Select)
- Add your character's name to both of these. They must strictly follow the order in which they are defined in the
PLAYERenum
add_category // ID 4
(
"PLAYER 1 SELECT",
[
"SONIC",
"TAILS",
"KNUCKLES",
"AMY",
"SHADOW"
]
);
add_category // ID 5
(
"PLAYER 2 SELECT",
[
"SONIC",
"TAILS",
"KNUCKLES",
"AMY",
"SHADOW",
"NO PLAYER 2"
]
);The character's presentation will default to Sonic's, i.e. its sprites and HUD elements. To make the character use its own set of sprites and animations, do the following:
- Create a copy of the
scr_player_animate_sonicscript and rename it to include your character's name (or however you wish to name it; it doesn't matter) - Open the
scr_player_animatescript and add a case for your character (in our case,PLAYER.SHADOW, i.e. the enum we created) and call the newly created animation script from it. Make sure your case comes before thedefaultcase, as thedefaultcase is used as a fallback - Modify your animation script as needed
First, register a new ability by opening obj_player's Create Event once again and adding a new ACTION enum entry:
enum ACTION
{
NONE,
SPIN_DASH,
DASH,
DROP_DASH,
GLIDE,
CLIMB,
FLIGHT,
TRANSFORM,
HAMMER_DASH,
HAMMER_SPIN,
CARRIED,
MY_NEW_COOL_ACTION
}Create a script that will contain your ability code. The general structure would be as follows:
if action != ACTION.MY_NEW_COOL_ACTION
{
return;
}
/* your action code */If your ability should be triggered when the player is grounded, you'll need to add its initialisation code here:
if action != ACTION.MY_NEW_COOL_ACTION
{
if action == ACTION.NONE && player_type == PLAYER.SHADOW && /*your conditions*/
{
action = ACTION.MY_NEW_COOL_ACTION;
/*your action initialization code*/
}
else
{
return;
}
}
/* your action code */If your ability should be triggered mid-jump, you'll need to initialise the ability under a new case in the scr_player_jump script instead:
case PLAYER.SHADOW:
if action != ACTION.NONE
{
break;
}
if /*your conditions*/
{
action = ACTION.MY_NEW_COOL_ACTION;
/*your action initialization code*/
}
break;The best place to inject your script call into obj_player's state machine would be:
- before the
if animation == ANIM.SPINcheck for the grounded substate; - before the
scr_player_movement_airfunction call for the airborne substate.