Like items and entities, mission information is stored in a JSON file. This file is called missions.json, and it specifies the mission settings.
Unlike items and entities, missions don’t have presets (at least not yet). They just have a few properties that can be customized using the mission maker.
Stats
Here are the stats of a mission:
- Entities: the entities
- Size: number of entities
- Speed: delay between entities
- Level: level of entities
- Ally faction: faction of rewards
- Enemy faction: faction of entities
- World: background image
I’ll talk more about how the mission maker works in the next episode. In the meantime, here’s how a mission is launched:
The player selects and activates the menu option that launches a mission…
1 2 3 4 5 |
// Launch a mission var launchMission = function(node) { // Pass in the node's parameters, which is the index for the mission we want to launch MissionFactory.launchMission(node.params); }; |
The mission factory then starts the play state…
1 2 3 4 5 6 7 8 |
// Launch a mission var launchMission = function(index) { // Set the current mission _currentMission = getMission(index); // Start the play state GameSystem.game.state.start('play', true, false); }; |
The reason that the menu doesn’t directly launch the play state is that we want each factory to be responsible only for its own stuff. If you think about it, the menu factory shouldn’t really be launching missions – it should be asking the mission factory to launch a mission.
After figuring out how to store missions as objects, I ended up storing all of the missions in a single file, but I originally had the mission factory pass the index into the play state so that we could read the JSON file for that specific mission. Here’s how that would work:
From the mission’s init function, we remember the index parameter…
1 2 3 4 5 |
// Accept parameters and store them in the play state init: function(missionIndex) { // Set the mission this.missionIndex = missionIndex; } |
Then we ask the mission factory to load the mission by index from the preload function…
1 2 |
// Read mission file GameSystem.MissionFactory.readMissionFile(this.missionIndex); |
This would probably be more useful for large numbers of large files, but the missions are pretty small and simple.
Entities
Whatever way we choose to lead the mission, we update the mission factory from the play state’s update function…
1 2 |
// Update the mission factory GameSystem.MissionFactory.update(); |
The mission factory’s update method will create the mission’s entities, which are read row-by-row…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// Update mission during gameplay var update = function() { // Scroll the background scroll(); // If the mission hasn't started, don't do anything if (!_currentMission.ready) { return; } else if (!_currentMission.outOfEnemies) { // Otherwise check if we still have entities to create checkMissionEnded(); // Check if the next row is ready if (_currentMission.rowReady) { // Get the next row var entityRow = getEntityRow(); // Draw it drawEntityRow(entityRow); // Reset the delay setRowDelay(); } } else { // If we have no more enemies to create, check if any are still alive var enemies = EntityFactory.getEnemyGroup(); if (enemies.children.length <= 0) { // If they're all gone, end the mission after a short delay var delay = GameSystem.data.missions.endDelay; GameSystem.game.time.events.add(delay, completeMission, this); } } }; |
It may not be pretty, but it works.
Size
The mission’s entities are read row-by-row, like a two-dimensional array or a grid. The mission’s size determines how the width and number of rows. Here are the size presets listed in mission.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
"sizes": [ { "key": "tiny", "name": "Tiny", "rows": 20, "columns": 5 }, { "key": "small", "name": "Small", "rows": 30, "columns": 6 }, { "key": "normal", "name": "Normal", "rows": 40, "columns": 7 }, { "key": "large", "name": "Large", "rows": 50, "columns": 8 }, { "key": "massive", "name": "Massive", "rows": 60, "columns": 9 } ], |
Speed
The mission’s speed determines the delay between the rows as well as the delay at the start of the mission. Here’s what the presets look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
"speeds": [ { "key": "sluggish", "name": "Sluggish", "multiplier": 1.66 }, { "key": "leisurely", "name": "Leisurely", "multiplier": 1.33 }, { "key": "normal", "name": "Normal", "multiplier": 1 }, { "key": "quick", "name": "Quick", "multiplier": 0.66 }, { "key": "chaotic", "name": "Chaotic", "multiplier": 0.33 } ], |
I’ve also considered having the mission’s speed determine the speed of scrolling entities as well as the background, but I haven’t decided how to implement that.
Level
The mission’s level just determines the level of the entities. For enemies, this determines the level of their items. For obstacles and drops, it affects the stats directly.
The rest of the mission stats are pretty self-explanatory. The enemy faction, like the level, determines the faction of entities. As it stands, obstacles aren’t affected by faction, but that could change.
Stay tuned for the next episode, when I’ll show you how missions are created using the mission maker!