An adventure game for the Arduboy
Website for the game is at https://www.city41.games/ardynia
see https://www.city41.games/ardynia/help
It should build just as-is in the Arduino IDE. If not, please let me know. I have had success building the game with 1.8.5 and 1.8.6. I now use 1.8.6 for developing the game.
The makefile is expecting to find the Arduino IDE at $HOME/.arduino_ide
. I followed this blog post to set it all up.
I am building the game on Ubuntu. I also suspect Mac OSX would work fine. No idea about Windows.
If all is setup correctly, then make
will build the game, and make clean
deletes the build artifacts. There is also make emu
to launch the game in ProjectABE, but that is specific to my machine and unlikely to work for anyone else (TODO, fix this)
There are three tools in the repo for generating the various assets for the games. These tools are all written in JavaScript and require node to run. If you have a recent version of node installed (I am using v8.9.4), then you should be able to just invoke these tools via the makefile:
make map
: generatesrc/overworld.h
andsrc/dungeons.h
from the Tiled data (see below)make bmp
: generatesrc/tileBitmaps.h
andsrc/spriteBitmaps.h
from the pngs intilePngs
andspritePngs
make strings
: generatessrc/strings.h
fromstrings.json
After changing any assets, the resulting C++ .h
files should be checked into the repo.
The maps for the game are built using the Tiled Map Editor. If you load tiled/overworld.tmx
and/or tiled/dungeons.tmx
into Tiled, it should just work. Each map has three layers:
-
guidelines: this layer is read only and just drops in Rectangles that are the size of the rooms. This helps to see where the room boundaries are.
-
entities: all of the game's enemies, chests, switches, etc are defined in this layer. More on entities below
-
Tile Layer 1: this layer contains the actual map tiles. With this layer selected, you should be able to grab a tile from the tileset and "paint" with it.
After making any needed changes to one of the map files, save it, then export it to tiled/overworld.json
or tiled/dungeons.json
. Once exported run make map
.
See the existing entities in the map for reference. All of the available entity types are defined in src/entityTypes.h
. For example, if you want to add a blob to a room:
- with the entities layer selected, choose the "insert point" tool, and click where you want the blob.
- from the Properties panel in Tiled, set the name to something descriptive (anything you want) and the type to
BLOB
.
Entities can also sport various custom properties depending on the entity and goal of the room. This custom property is stored in the top 3 bits of the entity, so it can have a max value of 7.
CONTAINED_TYPE
: used byPOT
andCHEST
. This should be a string type set to another entity type, such asKEY
. See the existing pots or chests for reference. Only entities with value 7or less can be used.DEST_ROOM_X
andDEST_ROOM_Y
: used byTELEPORTER
. These are how the player goes from the overworld to a dungeon, and vice versa. These are integer values and are the x/y coordinates of a room. For example, on the overworld, the TELEPORTER for dungeon one goes to(0,7)
, and if you look on dungeons.tmx, you'll see the room at(0,7)
is the first room of dungeon 1. There can only be a total of 8 teleporters per map.MISC
: this is one of these string values:VERTICAL
: used forTRIGGER_DOOR
to tell the door to lay it self out vertically instead of horizontally. This is needed if the trigger door is on a east or west wall.SLAM_SHUT
: can be placed on any entity that otherwise would not use its top 3 bits (for example, you can't set SLAM_SHUT on a chest, as it would wipe outCONTAINED_TYPE
. If this is set, that room will have the TRIGGER_DOORs shut once the player enters. The player must defeat all the enemies for the doors to open again.LAST_ENEMY_HAS_KEY
: if set, then once the player defeats all the enemies in the room a chest will appear containing a keyLAST_ENEMY_HAS_HEART_CONTAINER
: same as above, but chest will have a heart containerLAST_ENEMY_HAS_BOSS_KEY
: again, but this time chest has the boss keyTHREE_SWITCHES_ONE_BOOMERANG
: sets the room up to be a puzzle involving switches and the player's boomerang. Despite its name, any number of switches can be set. The player must trip all of the switches with a single boomerang throw, and when they do a chest with a key in it will appear.OPEN_CHESTS_IN_RIGHT_ORDER
: a puzzle involving chests. Place several chests in the room, the player must open them in order. If they do, they get a key. If they don't, they get shocked and take damage. You can change the order of the chests by dragging them around in Tiled.LAST_TORCH_OPENS_DOORS
: a puzzle involving the magic ring. Once the player lights all the torches in the room, the trigger doors will open.
NOTE: if you just want a room to only be the chest puzzle, just drop a SUNKEN_BRIDGE in the room and set OPEN_CHESTS_IN_RIGHT_ORDER on the sunken bridge. The bridge will never appear to the player. Otherwise, usually set the puzzle flag on a blob or a bat.
If the maps change size, these constants need to be updated, at the top of src/game.h
- OVERWORLD_WIDTH_IN_ROOMS
- OVERWORLD_HEIGHT_IN_ROOMS
- DUNGEONS_WIDTH_IN_ROOMS
The graphics for Ardynia are custom generated to work with src/drawBitmap.cpp
. This is a different draw bitmap function from what is found in Arduboy2 or ArdBitmap. The main difference is for plus mask
mode, the entire masks are interlaced between the frames. Arduboy2 interlaces mask bytes with frame bytes instead. make bmp
will generate the proper sprite data to feed to src/drawBitmap
.
poorly named, these are really graphics that need a mask. The resulting variable name will be <filename>_plus_mask
.
poorly named, these are graphics that don't need a mask. The resulting variable name will be <filename>_tiles
Some things that really are sprites are found in tilePngs, such as explosion. This is to save bytes by only generating masks when they are really needed.
Edit the strings strings.json
then run make strings
. The resulting src/strings.h
will have arrays in it suited for rendering with Renderer#drawString
- The code is pretty bad in some areas, my apologies. I figured this game out as I went. Also sometimes hard to follow/read code is chosen due to byte savings.
Hopefully nothing. The game is finished. But always the chance of a bug cropping up.