Stages
Config
The Stage config file handles spawning units and the player, setting the bounds of the arena, and various other things.
Basic Settings
1 2 3 4 5 6 7 8 9 10 11 12 | { "menuCore": "misc/core/octopus/core0", // the layered sprite eye to show on menu "title": "#octopus.title", "description": "#octopus.description", "behaviour": ".fsm", // the behaviour state machine "song": "019", // the song config file to use "arena": { // arena position and size (this stage is 200 units wide, 200 units tall, and centered around x:0, y:0) "bounds": "rectCenter(vec2(0f, 0f), vec2(200f, 200f))", }, } |
Game Mode
Time Attack
This is the default mode. The goal is to destroy the boss(es) as quickly as possible.
1 2 3 4 | { // ... "gameMode": "TimeAttack", } |
Endless
In Endless
mode, the goal is to survive as long as possible.
1 2 3 4 | { // ... "gameMode": "Endless", } |
Note
When time is slowed down or sped up in Endless
mode, the game timer is affected too!
Medal Times
Choose the time in seconds that needs to be beat to earn each medal.
1 2 3 4 5 6 7 8 | { // ... "medals": { "bronze": 420, "silver": 300, "gold": 180, }, } |
An Endless
stage needs to specify the victory
time as well - that is, the time you need to last to beat the stage without even earning a bronze medal.
1 2 3 4 5 6 7 8 9 | { // ... "medals": { "victory": 250, "bronze": 350, "silver": 500, "gold": 650, }, } |
Player
1 2 3 4 5 6 7 8 9 | { "player": { // the path to the player config file "path":"player/defaultPlayer", // spawn the player here at the start of level "spawnPos": "vec2(0f, -20f)", }, } |
The player.path
property is used when overriding the default player ship - you can safely omit it otherwise.
Note
vec2(0f, -20f)
is a position with an x-coordinate of 0
and y-coordinate of -20
.
Most stages have (x: 0, y: 0)
as the center of the arena.
Units
Units are preloaded to avoid stuttering during gameplay, and therefore the type and max count of each unit needs to be decided on in advance.
1 2 3 4 5 6 7 8 9 | { // ... "units": { "boss": { "config": "mech/unit/boss", "requiredForVictory": true }, "turret": { "config": "mech/unit/turret", "count":5, }, "egg": { "config": "misc/unit/eggShield", "count":1, }, "trap": { "config": "mech/unit/trapLaser", "count":1, }, }, } |
To beat the level on Time Attack
stages, the player needs to destroy all requiredForVictory
units.
Cross-Unit Requirements
Unit parts can be protected from parts of other units.
1 2 3 4 5 6 7 8 | { // ... "units": { "boss": { "config": "octopus/unit/boss", "requiredForVictory": true, "requirements": { "form2:core": [{ "unit": "turret", "form": 0, "parts": [ "core" ] }] }}, "turret": { "config": "octopus/unit/turret", "count": "turretCount", "progressWeight": 0.25 }, "egg": { "config": "misc/unit/eggShield", "count":1, }, }, } |
Expanded for clarity:
1 2 3 4 5 6 7 8 9 10 11 12 13 | "boss": { // ... "requirements": { // the 3rd form core of the boss requires the turret unit's 1st form core "form2:core": [ { "unit": "turret", "form": 0, "parts": [ "core" ], }, ], }, }, |
Spawning
1 | { "action": "CallMethod", "method": "SpawnUnit", "params": { "name": "boss", "pos": "vec2(0f, 10f)", }}, |
There are a couple optional parameters:
1 2 3 4 5 6 7 8 | { "action": "CallMethod", "method": "SpawnUnit", "params": { "name": "boss", // the name refers to what you chose in the "units" json property "pos": "vec2(0f, 10f)", "force": "vec2(0f, -50f)", // force applied to unit upon spawn "facingDir": "UpLeft", // initial direction of unit } }, |
If you try to spawn a unit with too many active already, it will be ignored. The count
of a unit determines the max amount that can be active.
Arena
You'll probably want to choose your level size by setting bounds
, but the other arena
properties can be ignored if you're fine with the defaults for now.
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 | { "arena": { // a rect specifying the size and position of the level "bounds": "rectCenter(vec2(0f, 0f), vec2(220f, 200f))", // level background color "bgColor":"color(0.06f, 0.06f, 0.08f)", // what color hides the out-of-bounds areas? (setting opacity <1 is useful for debugging bullet behaviour) "letterboxColor":"color(0f, 0.025f, 0f, 1f)", // color of background grid "gridColor":"color(1f, 1f, 1f, 0.015f)", // how thick are the lines on the grid "gridThickness":2.2, // what dimensions are the grid diamonds "gridSpacing":"vec2(20f, 20f)", // how large are the edges of the grid "gridEdgeWidth":12, // how much to warp grid in the edges "gridEdgeWarp":1.25, // scale the grid lines in the edges "gridEdgeScale":3.5, }, } |
Behaviour
The stage has its own state machine like units do, where actions can be called in sequence.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | { "behaviour": ".fsm", // ... "fsm":{ "inactive": [ ], "start":[ // spawn clouds, boss, etc // without an indefinite Wait, the state machine will keep looping { "action": "Wait", }, ], }, } |
Warning
While most names can be safely changed in Chippy scripts, the start
state in a stage fsm will specifically be set at the beginning of a run, so make sure it exists.
Handlers
You can call Actions are certain points during a stage, besides the state machine.
1 2 3 4 5 6 7 8 9 | { "onUpdate":[ // called each frame { "action": "CallMethod", "target":"player", "method": "AddForce", "params": { "force": "vec2(0f, 1f)", }}, ], "onPlayerHit":[ /* called when player is hit but does not die */ ], "onPlayerDie":[ /* called when player takes lethal damage */ ], }, |
Custom Variables
Custom variables can be defined in the properties
structure of the stage config.
1 2 3 4 5 6 7 8 9 10 | { "properties": { "numBubblesPopped": { "type": "Int" }, "egg": { "type": "Unit" }, // player specific "attempts": { "type": "Int", "userData": true, "value": "progression.GetAttempts(stageId)" }, "victories": { "type": "Int", "userData": true, "value": "progression.GetVictories(stageId)" }, }, } |
These values can be used in any script func by the stage or any object (unit, player, bullets, etc) that exists on the stage.
To modify them, use the SetValue method:
1 | { "action": "SetValue", "target":"stage", "name": "numBubblesPopped", "type": "Int", "value": "numBubblesPopped + 1" }, |
When using the target
param so you can set the property of a different object (for example, a bullet setting the value of a stage property) you must also declare the type of the value.
Player Specific Properties
The player specific properties check the player's individual progression file for their attempts
(number of times playing the level) and victories
(number of times beating the level).
Typically these are only used to adjust which speech lines the bosses say, but there's no rule that they can't have gameplay implications.
Return Values
Some methods have a return value that you may want to save to a custom variable to access later.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | { "properties": { // when the level starts, the value of the bossUnit property is null "bossUnit": { "type": "Unit" }, }, "fsm": { "inactive": [ { "action": "Wait" }, ], "start": [ // spawn the boss unit and save the return value (of type Unit) to the custom bossUnit property { "action": "CallMethod", "method": "SpawnUnit", "params": { "name": "boss", "pos": "vec2(0f, 20f)" }, "return":"bossUnit", }, // now we can call actions directly on the bossUnit { "action": "CallMethod", "target":"bossUnit", "method": "Shake", "params": { "strength":5, "time":2, "easingType":"QuadIn", }}, ], }, } |
Screen Effects
Some visual effects can be applied to the screen.
1 2 3 4 5 6 7 8 | "onUpdate":[ { "action": "CallMethod", "method": "SetHueShift", "params": { "amount": "mapReturn(stageTime, 0f, 9f, 0f, 100f, 'QuadInOut')", }}, { "action": "CallMethod", "method": "SetContrast", "params": { "amount": "mapReturn(stageTime, 0f, 2f, 0f, -60f, 'QuadInOut')", }}, { "action": "CallMethod", "method": "SetSaturation", "params": { "amount": "mapReturn(stageTime, 0f, 8f, 0f, 200f, 'QuadInOut')", }}, { "action": "CallMethod", "method": "SetColorFilter", "params": { "color": "lerp(color(1f, 1f, 1f), color(1f, 1f, 0f) * 2f, mapReturn(stageTime, 0f, 4f, 0f, 1f, 'QuadInOut'))", }}, { "action": "CallMethod", "method": "SetTemperature", "params": { "amount": "mapReturn(stageTime, 0f, 5f, 0f, -100f, 'Linear')", }}, { "action": "CallMethod", "method": "SetChromaticAberration", "params": { "amount": "mapReturn(stageTime, 0f, 10f, 0f, 4f, 'ExpoInOut')", }}, ], |
Script Parameters
These parameters can be used inside any scriptfunc by the stage or any object in it (player, units, patterns, bullets, etc).
Info
Debugging
Any entity can call the Stage debug methods to draw lines or text.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | "onUpdate": [ { "action": "CallMethod", "target":"stage", "method": "DrawDebugLine", "params": { "a":"playerPos", "b":"playerPos + playerVel", "time":0.02, "color":"color(0f, 0f, 1f) * 2f", "width":0.2, "opacity":0.6, } }, { "action": "CallMethod", "target":"stage", "method": "DrawDebugText", "params": { "pos": "playerPos + vec2(0f, 3f)", "text": "${playerVel}", "fontSize":"2.5f + fastSin(stageTime * 4f) * 0.5f", "time": 0.02, "color":{"r":1,"g":1,"b":0,"a":0.25}, } }, ], |
Camera Zoom
Hold V to temporarily zoom out, or use + and - for finer control.