I've been working on-and-off since the spring on a little zelda-like adventure game. I thought id share what i have so far, maybe that will start a discussion, maybe not at all.
I've mostly been working on the foundations of the engine and tools. I have zero gameplay element, that will come next. Everything you see if obviously a placeholder (my character is a litteral crash test dummy to make this extra clear). I am not an artist in the slightest. I eventually hope to reach a point where I have enough of a game to partner up with a real artist to make this look real nice.
So here is what i've got so far. I'll cover some of the details of each in this post:
- 4-way scrolling (100% artefact free)
- basic assets (metasprites/tiles, animations, levels, etc.)
- basic editor
- small scripting language
4 way scrolling
Using vertical mirroring and assuming an overscan of 8px on the top and bottom of the screen, that leaves us with 16px to hide all of the attributes defects. This mean that if we are pixel-perfect, we can get really nice 4-way scrolling without using any special mapper (I use an MMC3)
Here is it running in a small C# version of the game I use for debugging. I use black bars to hide the overscan. When I switch to the debugging mode, there is 2 sets of red lines, one with the overscan and one without. Notice how all the artefacts are kept outside of the visible area. Note that the red/yellow squares are kept on screen for a few milliseconds, i'm not updating that many tiles.
Same thing, in Mesen.
It is a small level but it has been tested on huge maps and supports up to 8 screens on each axis (assuming you have the ROM/RAM to hold the data).
If you are planning to reproduce this, I *highly* advise that you create yourself a reference version in a language that is more "flexible" than ASM. The final ASM version is about 2000 lines of codes (including the code to prime the screen initially, and render some background animations). There are some nasty edge cases to handle, especially when it comes to stitching the attributes of the top and bottom rows, and on edges of name/att tables. Doing this directly in assembly would have been very time-consumming.
Basic assets
Here is a quick overview of all my asset types.
Here is what each of them are:
- Animation: A series of keyframe, each of them being a Metasprite.
- AnimationSet: A bunch of animation together. This both represents a 1KB switchable bank of CHR ROM and the PRG ROM data for the keyframes.
- BackgroundAnimation: Allows animating the background.
- Bank: Represents an switchable 8KB bank of PRG ROM. You can dump assets in there as long as you dont go over 8KB. Right now only 8 are displayed because I have so little content. Ultimately all 64 might be there.
- Level: More of a "room" than a level really. Comes with things litle triggers and scripts. More on that later.
- Metasprite: Bunch of sprites stuck together.
- MetaTile: a 4x4 grid of sprites. So my metatiles are 16x16.
- MetaTileSet: a bunch of MetaTiles togheter. This both represents a 2KB switchable bank of CHR ROM and the PRG ROM data.
- Palette: Duh
- Sprite: Duh
Basic editor
If you every worked in the game industry, you know how tools are much more important than whatever fancy tech you may have. That's why engines like Unreal are so popular. Their tech is by no mean outstanding, but their toolsets are super flexible and allows artists to have total control over their content. So I decided to spend some times on tools.
The tools handles all the packing in CHR ROM, updates everything automatically. You can safely delete stuff without worrying about your level being completely messed up. It works pretty well.
While you *can* paint sprites and stuff in my tools, there is no way I am going to be able to compete with Photoshop. So I added support for copy and pasting images from external applications. It automatically creates sprites, assigns palettes, detects flips, etc. Here it is in action. Notice how it detects that the hat is a flipped version of the same sprite and how it matches the rest of the body to existing sprints.
You can also compile and launch the game from the level editor:
When you export the data from the editor, you simply need to include a couple of ".inc" file in your code and you are ready to go.
Scripting
My game will not be 100% systemic. By this I mean I want to be able to create unique moments like in Zelda games. Things like:
- You enter a room, the music changes, a big bad guy appear, you kill him, them a chest appear in the corner, etc.
- In a room you have 3 switches on the wall, if you dont press them in the right order, a monster appear, if you solve the puzzle, a door opens.
This also allows me to prototypes functionality that I am still not sure how it is going to work. Here is an example of me using it to prototype a door opening and a room transition. As the character hit the trigger next to the keypad, it plays a background animation of a door opening (thus changing the collision) and the room transition is done by another trigger.
Please understand: NOBODY IN THEIR RIGHT MIND would use scripting to open a door and do a room transition like this if you are going to have 3 doors in every room. Of course you would want to make that code part of the engine. But is it good enough for a quick prototype? Absolutely.
The level has 3 types of objects that the script knows about: locators, routes and areas which are respectively 0D, 1D and 2D objects.
- Locators are simple points, simply to represent a coordinate
- Routes are paths, which will be used to assign path to AIs, for example.
- Areas are rectangles, which can be used as trigger (and other stuff later).
- on_level_init: Called after a level is loaded, but before it is rendered. This is where I will be spawning AIs, setting up the inital state of things like doors.
- on_trigger_touched: Called when the hero enters a trigger. The id of the trigger is passed as an argument.
Anyway, that's it for now. Hopefully I will keep working on it a have more to report.
-Mat