Inspired by @filmote’s thread, I want to share progress of an FX-powered RPG I’ve been working on. Hopefully this will produce design feedback or story ideas to make it a better game.
The working title that I’m not entirely happy with is “Return of the Ardu”.
The story so far is full of tropes: it features a boy who discovers that he is descended from an ancient people called the Ardu (so he is an “Ardu boy”, right??) who had magic/technology that only a fellow Ardu is able to interface with. The big bads are the Old Dark empire, who is slowly conquering the area and seeking to acquire Ardu items.
The game story is controlled by a bytecode interpreter that executes scripts stored on the flash chip. The scripts are stored alongside map data, and execute every frame, controlling sprites, dialog, tiles, party, battle encounters, items, story flags, etc.
Battle encounters are turn based, up to 4v4. They are not random, but happen by running into an enemy on the map or as a part of the story. Most encounters are avoidable, though many have rewards for defeating them. There is a philosophy of no RNG in the battle mechanics themselves (all damage is deterministic). Attack order is determined by a speed stat. Actions are:
Attack a specific enemy. If an enemy is defending, only the defender may be targeted.
Defend until your next turn. While defending, all enemies target you, but you take half damage from all attacks.
Use item: use a defensive or offensive consumable item.
You made a bytecode interpreter just to run story elements? That is ridiculously impressive; I guess you didn’t trust the logic to fit in the basic space? Gosh… such dedication
A major element of the game will be rewarding exploration. Dungeons, some puzzle-based, some reflex-based, and some combat-based, offer rewards when completed.
Examples:
Yes – now that the fun stuff (engine coding and optimization) is pretty much done, making the game content is proving to be much more monotonous. I don’t want to let up in quality however.
Yes, all interactivity, whether dungeon behavior, enemies, looting items, storyline… is entirely from scripts.
The scripts can react to a bunch of stuff: what tile the player is standing on or selecting, what direction he’s facing, what sprite he is contacting or selecting, what items are equipped, etc.
Then the scripts can modify game state in response: change a tile, spawn/remove a sprite, start a battle, teleport/heal/kill the player, grant items, perform dialog, etc.
The way things are organized is the map is divided into chunks the size of the screen, and each chunk has a script that runs each frame. Only visible chunks run their scripts, so up to four chunks can execute. At the beginning of each frame, the chunk is reset to its default state, and then its script executes, which can modify stuff. This allows chunks to react to the game state continuously.
The primary reason I wanted to develop an Arduboy profiler was for grayscale dev. This game really stretches the Arduboy’s performance limit.
The game renders at 156 Hz and all graphics except for the font are stored on the FX chip. Music is played using a stripped down ATMlib2 modified to stream from the FX chip and compute two channels instead of four. The music ISR tends to take up 10-15% of CPU time.
Interestingly enough, the title screen is the most CPU-intensive. This is because everything that normally happens during gameplay (map/sprite rendering, map script processing, game logic updates) is still happening, as it merely simulates a game running in the background. But also, there are two large masked sprites rendering for the title and blinking “Press A”.
With music enabled the frame times are near the breaking point:
With music disabled:
Saves
I modified the save system to use Mr. Blinky’s new FX save methods. They are much better than my old version – less code and a kind of built-in “wear leveling” on the save block.
Since pretty much all graphics reside on the FX chip, nothing can be rendered while erasing/programming. Normally, a monochrome game could just leave the display buffer untouched. But with grayscale, it would be jarring to briefly leave a monochrome image of one of the grayscale planes on the display while saving. Thus saving involves a fade to black to smooth it over:
Pause Menu Darken Effect
Speaking of which, the pause menu renders the background darkened.
This effect comes easily with grayscale, as grayscale is accomplished with a kind of PWM on each pixel:
Plane 0
Plane 1
Plane 2
Black
.
.
.
Dark Gray
X
.
.
Light Gray
X
X
.
White
X
X
X
While rendering the pause menu, the map’s plane 0 is skipped:
Plane 0
Plane 1
Plane 2
Black
.
.
.
Dark Gray
.
.
.
Light Gray
.
X
.
White
.
X
X
This effectively causes all pixels to be rendered one shade darker: white pixels as light gray, light gray pixels as dark gray, and dark gray and black as black.
I might take you up on that. However, I’ve been considering just doing a rewrite of the whole command/synth logic on top of the base osc code. That was also my motivation for supporting timer4 and sound in the sim.
The original design intent seems to have been optimizing the song encoding to save prog, which isn’t a concern anymore. Stuff like looping and subroutines aren’t needed. Performance-wise, I wanted to investigate changing the ISR from a constant 16 kHz to a scheduling based approach to save CPU: assuming only additive square waves, schedule the next interrupt for the next transition in any channel. I also want to make the FX data transfer more robust.
I think at least a few games could render that fast. I just looked into your game “Kong”:
Looks like it runs at 70fps while only using ~50% CPU. With only a slight focus on performance I’d bet it could easily render at 156 Hz.
Even if the sprites are on the FX chip it’s not too much of an issue. For this game I have my own sprite routines which sacrifice code size and flexibility (limited draw modes, height must be multiple of 8) for speed. The FX versions maintain the minimal 18 cycles/byte cadence which is competitive with the prog versions in the Sprites lib. Drawing lots of tiny sprites has a penalty due to the seek overhead so I keep the dialog font in prog for that reason and text rendering has its own specialized method as well.
OK … that’s interesting. I am trying to recall whether Kong has lots of little sprites or less, big ones.
Is your game using tile sheets to render the landscape? If so, this would be similar to Prince of Persia and probably give me some confidence that it might be achievable.