Walmart Mario Maker is a tool that allows users to create 2d platformer levels with a simple domain specific language.
To run this project perform the following steps:
- Navigate to platformer-game directory and run
npm install
- Run
tsc
- Run
npm start
- Open another terminal and navigate to the backend directory, and run
npm install
- Run
npm run build
to compile the backend - Run
npm run start
to start the server - A react project should open in your browser
- Create a text file using our language and save it with a
.gregor
extension - Upload the file into the file selector in the react project
- If the input file is correct, you will be redirected to the game, otherwise an error message will appear on the home page
A .gregor file is composed entirely of objects. We have pre-defined object types like terrain and enemies that will be placed within a special object type: the level.
NOTE: THE ORDER OF DECLARATIONS DOES MATTER.
Our levels must be defined at the very end of the file, after all other objects are declared. The player will start in the first level defined.
Example file:
Player player: {
speed: 1
health: 4
}
Enemy Slime: {
Behaviour: STILL
Speed: 2
colour: #042b2b
image: https://media.discordapp.net/attachments/969645894616096858/1028893886124412949/theTriangle.png
}
Enemy Goblin: {
Behaviour: FOLLOW
Speed: 0.4
colour: #042b2b
image: https://media.discordapp.net/attachments/969645894616096858/1028893886124412949/theTriangle.png
}
Terrain terrainType1: {
image: none
colour: #042b2b
}
Platform platformType1: {
image: none
colour: #008080
}
Door doorType1: {
image: https://creazilla-store.fra1.digitaloceanspaces.com/cliparts/33142/door-clipart-md.png
key: none
}
Door doorType2: {
image: https://creazilla-store.fra1.digitaloceanspaces.com/cliparts/33142/door-clipart-md.png
key: buttonType1
}
Coin coinType1: {
image: https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Racket-logo.svg/1200px-Racket-logo.svg.png
value: 1
}
Button buttonType1: {
image: https://media.discordapp.net/attachments/1017526051989106740/1027763213896515615/key-png-11.png
}
Level level1 {
player: (200, 50)
height: 900
width: 3000
background: https://media.discordapp.net/attachments/1019466411044765716/1029542966185971822/bg.png
Terrain:
terrainType1: [
(terrain1, 1500, 300, 500),
(terrain2, 0,0, 500),
(terrain3, 1000,0, 2000)
]
Platform:
platformType1: [
(plat1, 1000,300,500),
(plat2, 500,200,500),
(plat3, 2000,300,500)
]
Enemy:
Slime: [
(slime1, 2500, 50)
]
Goblin: [
(Goblin1, 1500, 50)
]
Door:
doorType1: [
(door1, level2, door2, 2000, 50)
]
Button:
buttonType1: [
(button1, 100,100)
]
Coin:
coinType1: [
(c1, 1200,500),
(c2, 700, 400)
]
Checks: [
IF: (MONEY > 1 OR buttonType1) {
Door: Add (d1spawn, doorType1, 100, 90, level2, door2)
Enemy: Add (gspawn1, Goblin, 10, 110)
}
]
}
Level level2 {
player: (500, 250)
height: 900
width: 2000
background: https://media.discordapp.net/attachments/1019466411044765716/1029542966185971822/bg.png
Terrain:
terrainType1: [
(terrain1, 1500, 300, 500),
(terrain2, 0,0, 500),
(terrain3, 1000,0, 2000)
]
Platform:
platformType1: [
(plat4, 900,300,400),
(plat5, 500,200,400),
(plat6, 1700,500,100),
(plat7, 1300,650,100),
(plat8, 750,800,200)
]
Enemy:
Goblin: [
(Goblin1, 1800, 350)
]
Door:
doorType1: [
(door2, level1, door1, 200, 50)
]
doorType2: [
(door3, win, win, 1550, 50)
]
Button:
buttonType1: [
(red1, 750,850)
]
Coin:
coinType1: [
(c1, 1200,500),
(c2, 700, 400)
]
Checks: [
]
}
The basis of a .gregor file. An object is declared as following:
Type subtype: {
property0: 1
property1: 2
property2: none
}
When declaring an object, ALL of its respective properties for the corresponding type of object
(see types below) must be defined: either with a value or none
.
The image
property will overwrite the colour property if given a valid image.
Only one of these may be defined. The thing the character controls.
speed
: Integer
- The speed of the character. Defined in tiles/tick (?)
health
: Integer
- The amount of hits our character can take.
Player player: {
speed: 1
health: 4
}
Hostile entities we can place within our level. If the player touches one, they take damage.
behaviour
: Behaviour
- How our enemy will function. Below are the current supported behaviours:
STILL
- Enemy will not moveFOLLOW
- Enemy will follow the player
speed
: Integer
- The speed of the given enemy. Only really matters if the behaviour is set to
FOLLOW
colour
: Hexidecimal colour value
- The colour of our enemy. If no image is given, the enemy will be a rectangle.
image
: URL
- Image representing our enemy. Overwrites the
colour
property if url given is valid
Enemy Slime: {
behaviour: STILL
speed: 2
colour: #042b2b
image: https://media.discordapp.net/attachments/969645894616096858/1028893886124412949/theTriangle.png
}
Solid ground for our player. NOTE: it's advised that you spawn the player on this. Without it, you will immediately fall to the bottom of the screen and die.
colour
: Hexidecimal colour value
- The colour of our terrain. If no image is given, the enemy will be a rectangle.
image
: URL
- Image representing our terrain. Overwrites the
colour
property if url given is valid
Terrain terrainType1: {
image: none
colour: #042b2b
}
Platforms for our player. Unlike terrain, we can jump through the bottom of platforms.
colour
: Hexidecimal colour value
- The colour of our platform. If no image is given, the enemy will be a rectangle.
image
: URL
- Image representing our platform. Overwrites the
colour
property if url given is valid
Platform platformType1: {
image: none
colour: #008080
}
A door leading to either a different level, or the win condition. The location the door leads to is defined in the Level
object.
image
: URL
- Image representing our door.
key
: Button
- A key required for our door to open. If button given exists in the same level and is collected, the door will spawn and allow the player to go through. If specified as "none", then the door will be spawned in at game start or level load.
Door doorType1: {
image: https://creazilla-store.fra1.digitaloceanspaces.com/cliparts/33142/door-clipart-md.png
key: buttonType1
}
Collectable coins for our player. Collecting these will increase MONEY
by value
image
: URL
- Image representing our coin.
value
: Integer
- Amount that
MONEY
will increase by when collected.
Coin coinType1: {
image: https://upload.wikimedia.org/wikipedia/commons/thumb/c/c1/Racket-logo.svg/1200px-Racket-logo.svg.png
value: 1
}
While a level itself is technically an object and is defined the same way, they are special objects that essentially serve as the program.
player
: (Integer, Integer)
- The spawn location for the player. If this is the first level defined, it is the start position. If not, then it is the location a player will be teleported to when entering a door that leads to this level. The first integer is starting x position, and the second integer is starting y position.
height
: Integer
- The height of the level in tiles.
width
: Integer
- The width of the level in tiles.
background
: URL
- Image that will be used as the level's background.
These are "properties." They look similiar, but more serve to group things that will be spawned. Inside a category, we will use the name of an object with the same type as the category as a subcategory. Inside a subcategory will be an array with individual instances of that object in question:
Type:
subtype: [
(name0, value, value),
(name1, value, value, value),
(name2, value, value, value)
]
subtype: [
(name0, value, value),
(name1, value, value, value),
(name2, value, value, value)
]
Terrain
: (name, XPOS, YPOS, LENGTH)
- Categorizer for terrain.
- Example Usage:
Terrain: terrainType1: [ (terrain1, 1500, 300, 500), (terrain2, 0,0, 500), (terrain3, 1000,0, 2000) ]
Platform
: (name, XPOS, YPOS, LENGTH)
- Categorizer for platforms.
- Example Usage:
Platform: platformType1: [ (plat4, 900,300,400), (plat5, 500,200,400), (plat6, 1700,500,100), (plat7, 1300,650,100), (plat8, 750,800,200) ]
Enemy
: (name, XPOS, YPOS)
- Categorizer for enemies.
- Example Usage:
Enemy: Slime: [ (slime1, 2500, 50) ] Goblin: [ (goblin1, 1500, 50) ]
Door
: (name, exit level, exit door, XPOS, YPOS)
- Categorizer for doors. If a player enters a given door, they will be teleported to an instance of
exit door
in theexit level
. Note that in order to place a door that will result in the player winning when they go through it,exit level
andexit door
MUST both bewin
. An example is provided below with doorType2. - Example Usage:
Door: doorType1: [ (door2, level1, door1, 200, 50) ] doorType2: [ (door3, win, win, 1550, 50) ]
Button
: (name, XPOS, YPOS)
- Categorizier for buttons.
- Example Usage:
Button: buttonType1: [ (red1, 750,850) ]
Coin
: (name, XPOS, YPOS)
- Categorizer for coins.
- Example Usage:
Coin: coinType1: [ (c1, 1200,500), (c2, 700, 400) ]
By using the keyword IF
we can have actions be triggered by checks: either a button press or a value comparison.
Checks
-
We store our events here. An event is defined by first using the
IF
keyword. -
Conditionals
- Following an
IF
, we put our conditional:- Up to a maximum of two conditions can be placed here, using an
OR
operator- A statement can be a logical comparison of values:
CONST OP value
- supported
OP
s are:<, >, <=, >=, ==
- supported
CONST
s are:HEALTH, MONEY
- supported
- Or a button check:
buttonName
buttonName
must be the name of a button already defined
- A statement can be a logical comparison of values:
- Up to a maximum of two conditions can be placed here, using an
- Following an
-
Events
- Follow a conditional, we can either
Add
orRemove
objects. The general structure is as follows: Type: Add (name, sub type, XPOS, YPOS)
- What's in the parentheses depends on the type of object. See above for syntax.
Type: Remove (name)
- Follow a conditional, we can either
-
Example usage:
- In this example, a door is spawned and an enemy goblin1 is removed when the player has MONEY value greater than 1 or when the button buttonType1 is collected.
Checks: [ IF: (MONEY > 1 OR buttonType1) { Door: Add (d1spawn, doorType1, 100, 90, level2, door2) Enemy: Remove (goblin1) } ]
Finally, we can put everything together:
Level level1 {
player: (200, 50)
height: 900
width: 3000
background: https://media.discordapp.net/attachments/1019466411044765716/1029542966185971822/bg.png
Terrain:
terrainType1: [
(terrain1, 1500, 300, 500),
(terrain2, 0,0, 500),
(terrain3, 1000,0, 2000)
]
Platform:
platformType1: [
(plat1, 1000,300,500),
(plat2, 500,200,500),
(plat3, 2000,300,500)
]
Enemy:
Slime: [
(slime1, 2500, 50)
]
Goblin: [
(Goblin1, 1500, 50)
]
Door:
doorType1: [
(door1, level2, door2, 2000, 50)
]
Button:
buttonType1: [
(button1, 100,100)
]
Coin:
coinType1: [
(c1, 1200,500),
(c2, 700, 400)
]
Checks: [
IF: (MONEY > 1 OR buttonType1) {
Door: Add (d1spawn, doorType1, 100, 90, level2, door2)
Enemy: Add (gspawn1, Goblin, 10, 110)
}
]
}