**_Baby Bat Becomes a Hero_** **Game Design Document** Morgan McGuire, http://casual-effects.com Revised 2015-12-27 [Click Here to Play](play.html) _Baby Bat_ is a game that I wrote from scratch in about 10 hours during December 2015 for the #1GAM game jam. My children provided playtesting and design ideas throughout the development process. This specification represents the game at the time of its completion and was continuously written and revised during development. See the Changelog Section to see how the game evolved. Overview =================================================================== Title: : Baby Bat Becomes a Hero Tag Line: : "Find Mommy Bat" Platform: : Web (touch screen, keyboard, gamepad) Target Audience: : Ages 5-12 Plays Like: : _Metroid_ meets _Flappy Bird_ Goal: : Find Mommy Bat Key Mechanics: : Traversal/Discovery, Targeting, Rhythm Flying, Lock and Key Setting: : Gothic castle and caves at night Art Style: : Retro-console pixel art Audio Style: : Solemn, naturalistic Art Style =================================================================== Pixel art, enlarged by nearest neighbor 4x for a 1920x1080 screen to show the pixels. Uses a pseudo 8-color palette. This choice is made for practicality--a lot of open conent is available and it is relatively easy to draw well. Tiles are all monochrome, since they are "seen" through echolocation. They have a cyan tint to emphasize that action takes place at night. The bat and insects are physically accurate (within the restrictions of the medium and scale), not stylized. There are three significant colors in the game: Brown : The bat, its energy, and its viewport on the minimap Yellow : Medium-sized objects: bat's echolocation and HUD element on growth level 1, the Medium Key, and the Medium Lock Red : Large-sized objects: bat's echolocation and HUD element on growth level 2, the Large Key, and the Large Lock Some artwork is derived from open content by surt from http://opengameart.org (see credits in the source). In practice, every pixel has been redrawn but the solid tiles and medium-bat silhouettes still match the originals. Background Research =================================================================== Bats are flying mamals. Most look sort of like mice or foxes with wings and are cute. Some have compressed faces that are scary-looking. Bat wings are formed by the fingers of their hands and feet, with membranes stretched between them. The wings run the length of the body. Bats: - are efficient fliers, requiring only 60% of the energy of birds - can maneuver like helicopters, including flying backwards and hovering - have reasonable eyesight and can see in the day - have two size categories: - 'megabats' (fox-sized) - 'microbats' (mouse through squirrel-sized) - have different diets, depending on the species: - insects (insectavore) - fruit (herbivore) - cow blood (hemataphore...the vampire bat) - tend to be brown and furry (some are so dark that they appear black) - live in trees or caves - tree bats: - land by smashing into tree limbs at great force - cave bats: - land by complex acrobatics to minimize landing force - mostly can't walk well because their rear legs are attached to their wings - vampire bats are the only ones that can run...and do so primarily driven by their front legs - can see reasonably well. Some have exceptional eyesight Predators: - Owls and hawks are predators in flight (and fish, when close to water) - Racoons and snakes are predators when resting Echolocation: - Extremely high frequency in a narrow band - Bats account for the doppler shift due to flight - Shut off their own ears during emission to avoid deafening themselves...have to time the pulses to avoid missing the returning ones Bat flight reference video: https://www.youtube.com/watch?v=Upq7LyhCGXE Mechanics =================================================================== The player will traverse the world several times, acquiring new movement abilities or seeking new power ups each time. - Lock-and-Key + Traversal: - Small bat can pass through large Grilles - Medium and Large bat can carry Medium Gold Key - Large bat can carry Large Red Key - The Moths needed to grow are behind Medium Gold Locks - Controls: - Vertical acceleration based on the rate of tapping the FLAP button plus gravity. A constant upwards acceleration is also applied during the wing-downward part of the animation. - One tap = one flap - Horizontal acceleration based on the left/right arrows (no arrow = desired zero speed) - On a surface, dpad moves slowly by crawling - Holding still for too long on a surface reverts to "hang" or "stand" - Energy: - Flapping consumes energy - Eating insects restores energy quickly - Resting restores energy slowly - Echolocation: - Runs continuously on a timer - Launches a dense set of dim echo projectiles in a forward arc of about 135 degrees - Echo projectiles that hit a surface reflect off at diminished energy, eventually disappearing - When an echo hits a surface, its "visibilityTime" is set to max(gameTime() + echo.energy, surface.visibilityTime) - Surfaces are visible until their visibilityTime expires, and then fade out - Can pass through some permeable surfaces such as grilles - NPCs are visible based on distance, not echolocation - Growth: - Bat moves faster but consumes energy more quickly when larger - Size affects traversal - Messages: - On-screen text fades in based on context to inform the player how to resolve situations - e.g., "grow so that you can lift this key" Targeting moths and mosquitos requires some moderately tricky flying. There is an optional side quest to the 2nd, "secret" cave at the top of the map in the final game. State =================================================================== Entity Properties ------------------------------------------------------------------- NPCs (insects), pulses, and the bat are codeheart.js `Entity`s. - *Entity properties*: - position : vec2 - sprite : Sprite or Image - size : vec2 (for collision bounds) - rotation : Number - isDisk : Boolean - visibleSize : vec2 (for rendering) - opacity : Number - *Game specific*: - velocity : vec2 - *Character (NPCs + bat) specific*: - facing : String ("left" or "right") - animationFrame : Number - growthStage : Number (size with regard to passing through apertures, on [0, 2]) - animationTable : Object - animation : Array of Sprites - *Bat specific*: - energy : Number - maxVelocity : vec2 - lastPulseTime : Number - pulseInterval : Number - currentKeyWeight : Number (0 = none, 1 = medium, 2 = large) The "aperture", "growthStage", and "weight" variables refer to the same concept, which is "size". I didn't use "size" at the time to distinguish from `Entity.size`, which is the pixel size of the collision bounds. Were I going to work on the mechanics further, I would rename everything for consistency now that these ideas have emerged in the design. Cell Properties ------------------------------------------------------------------- The `grid` is a 2D grid of `Cell`s, with the following properties: - *Cell properties*: - pixelSourceX : Number - pixelSourceY : Number - visibleTime : Number - minimapColor : String - seenBefore : Boolean (used to determine when to draw to the minimap) - aperture : Number (see NPC growthStage) - type : String or Number (if a Number zero, this is a key) Cell defines the following types: - `PORTCULLIS_TYPE` - `MEDIUM_LOCK_TYPE` - `LARGE_LOCK_TYPE` - `MEDIUM_KEY_TYPE` - `LARGE_KEY_TYPE` - `NORMAL_TYPE` - `MOMMY_TYPE` Movement =================================================================== The implementation assumes that all Entitys move a small number of pixels per frame with respect to the size of the objects and tiles, so that axis-independent and static dection can be employed for `Entity`-`Cell` collisions. The `slideMove(entity)` function attempts to move the object first in x and second in y. For each move, if the object hits a tile its position is unchanged and its velocity is set to zero. In addition, if the argument to `slideMove` is the global `bat`, then the `onBatTileCollision` function is invoked on the cell. This is a hook to allow messages explaining why movement is blocked and to detect unlock events. If I were extending the game further, I would generalize this to a callback on the `Entity` to allow overloading and avoid special-casing the bat. Tools =================================================================== - Emacs for text editing - [Markdeep](http://casual-effects.com/markdeep) for specification formatting - [codeheart.js](http://codeheartjs.com) framework - Javascript language + Chrome browser and debugger - SVN for revision control - Audacity for audio editing and encoding - Photoshop for image editing - [bfxr](http://www.bfxr.net/) for sound effect synthesis Changelog =================================================================== _Newest entries are at the bottom, all are grouped by 20-min development session_ 1. *Initial Game Ideas* 1. Brainstorming: - 2D platformer - Skateboarding game - RTS - Tetris extended with a character on the blocks - Turn-based strategic spaceship combat 1. Began with a minimalist 2.5D RTS inspired by Rymkdapsl 1. Switched to Gradius-style space sidescroller when time became short and hit graphics limitations 1. Switched from space sidescroller spaceship-in-cave to bat-in-cave for accessibility and inspired by Ludum Dare's 2-button theme 1. *Created Overall Game Design* - Drafted this specification - Researched bats 1. *Designed Initial Bat Mechanics* - Controls: - Hold button down to bring down wings (multiple frames of animation), release to let them rise again - Flapping perfectly gives elevation and acceleration up to max speed - Hold down to glide - Constant drag and gravity - Left and right buttons to turn to a direction - Echo button - On a surface, dpad moves slowly by crawling - Holding still for too long on a surface reverts to "hang" or "stand" - Energy: - Flapping and echo consume energy - Eating bugs restores energy quickly - Resting restores energy slowly 1. *Drew Initial Artwork* - Drew pixel art for tiles and bat based on opengameart work by surt - Made tiles monochrome, since echolocation will indicate distance (and a bit of texture) but not color - Reserved color versions for a later extension to light 1. *Implemented Initial Specification* - Implemented map loading from strings - Implemented map rendering - Implemented bat flapping mechanic (coarse) - Implemented map visibility fading - Implemented pulse generation and rendering 1. *Redesigned Echolocation* - Switched to automatic pulse based on a timer because manual pulsing while also flapping is too hard. - Implemented pulse tracing against map - It is too hard to see under the current echolocation model because you can overfly visibility - Sigificiantly increased pulse rate, velocity, and range - Made pulses fill a 270-degree arc (instead of 190 degrees) - Made pulses illuminate a 3x3 grid on impact 1. *Added Map Mechanics* - Implemented camera for scrolling - Implemented collisions against map - Implemented gravity (when not flapping) - Created spawn code for bat - Drew larger, cave-like map - Switched map to using Unicode characters for clarity when editing 1. *Redesigned Flying Interaction* (see above) - Extended full flap animation from 5 to 8 frames - Shifted animation start frame to gliding position 1. *Implemented new Flying Interaction* - One tap = one flap feels good - Shifted flap animation to start from upward wing. This feels like a stronger correlation between tapping the button and the animation (even though it is a less logical place for the bat to pause). - Thought process: 1. queue of timestamps for tap events ==> effective but inelegant; lots of state 1. some kind of exponentially-weighted moving average of tap time ==> unclear and hard to tune 1. Each tap increments `tapRate`, which continuously decreases over time ==> elegant with single variable - Tuned constants for a while until it was reasonable to hover, ascend, and descend - Added energy display - Added bounds to world - Only allow flapping when the bat has energy 1. *Implemented Minimap* - Dynamic canvas and HUD display - Show the screen's viewport bounds as an overlay - Show empty space as it is discovered - Culled map tiles during rendering against the screen to increase performance 1. *Designed NPCs* (Non-Player Characters) - Originally planned for Gauntlet-style spawners that produce NPCs, but had no elegant way to ensure a continuous supply of food without flooding the game...lots of back pointers were needed. - Switched to a Metroid/Castlevania-style respawning enemy, where NPCs have a dormant, invisible state when dead that resets after the viewport moves far away from them: - On death, reset `npc.position = vec2(npc.spawnPosition)` - Respawn when `! npc.alive && (distance(bat.position, npc.position) > screenWidth))` - Opacity of an NPC - Implemented mosquito - Implemented eating NPCs 1. *Implemented Mosquito Flying* - Velocity is a clamped random walk - abstracted `slideMove` for moving with collision for use on both NPCs and the bat 1. *Tuned Bat* - Made tapRate decrease faster to avoid getting stuck against ceilings temporarily while trying to move - Increased vertical acceleration from flapping to make it easier to fly upwards - Slightly increased horizontal velocity to keep up with mosquitos 1. *Debugging Options* - Unified all debugging options to be enabled by a single `DEBUG` global variable - Collision bounds rendering - Extra on-screen messages - Skip title screen 1. *Designed Overarching Metroid-Style Mechanic* - Progression: Eath Moths ==> Small Key ==> Eat Moths ==> Medium Key ==> Large Key ==> Medium Key ==> Small Key ==> Mommy - Failure Messages: - "Grow more to lift this Small Key" - "Grow more to lift this Large Key" - "Find a Small Key to open this Small Lock" - "Find a Large Key to open this Large Lock" 1. *Added Grille Element* - Allows small bat to pass through, but not large bat - Marked as `permeable = true` to allow small objects and sound through - `slideMove` selects whether objects can move through based on size - Drew graphics - Added to map 1. *Implemented Moths* - Drew moth animation - Fly in straight lines with random direction change - Moths have a continuous rotation instead of a discrete direction - Design: eating moths grows the bat 1. *Drew Full Game Map* - Drew wood block type - Used large grilles to force the player to enter an area small but then exit in a different way after growing - Multiple small keys + locks to extend game, but they are placed so as to force retracing steps and to prevent entering areas out of order 1. *Changed* `cell.permeable` *to* `cell.apertureSize` - If greater than 0, sound can pass through - An Entity can pass through a Cell with `entity.growthStage < cell.aperture` - Allows small grilles that can be seen through but not flown through, as well as large grilles that can be flown through when small - Mosquitos have `growthStage = 0.001` 1. *Added More Artwork* - Drew custom pixel font for HUD and added growth display for the bat - Drew portcullis bars - Drew large (red) and small (gold) keys and locks - Tinted world tiles cyan for more of a "night" look; contrasts with the bat and makes insects stand out more 1. *Implemented Bat Growing* - Redrew bat at 24px, 32px, and 48px scales by resizing in Photoshop and then repainting over the outline - Added `growthStage` state to bat, a real number on the range [0, 2]. Fractional amount tracks growth status, integers are the bat's current size - Set `bat.visibleSize` and `bat.size` every frame in `simulateBat` based on `floor(growthStage)` 1. *Made Growing More Obvious, Tied to Color* - Re-colored pulse based on size (green, yellow, red) - Modified HUD to show growth and status with color-coded bars - Prevented moths from respawning to force the player to hunt _all_ moths 1. *Implemented picking up keys* - Keys are map cells with `keyWeight > 0` and large aperture size - On collision with such a cell, the bat picks it up and removes the cell from the map, or triggers a message - The bat has a `currentKey` property that is 1 or 2 for the key size carried - If the bat is carying a key, it can't pick up another one (the map also prevents this for the current game) - Added a graphic to the bat when carying a key - Made the carried key tilt slightly based on velocity to better appear that the bat is carying it 1. *Added Message System* - One global message may be displayed to the player at a time - Fades in and out - Setting the same message resets the fade out timer - Applied IM Fell font from https://www.google.com/fonts - Added intro messages: - Added "Eat insects to regain energy" when energy is less than 25% - Added message on growing - Added message when trying to fly through a large grille after growing - Added message when hitting a portcullis - Added message on trying to pick up a key that is too large for current growthStage - Added intro message "Flap your wings to fly" 1. *Refactored* `Cell` - The Cell now has a `type` field instead of separate `keyWeight`, `isPortcullis`, and `lockWeight` mutually-exclusive fields - Renamed "small" to "medium" throughout the game text, implying that the original bat is "small". This way, the "medium" bat lifts a "medium" key to unlock a "medium" lock and the size names appear consistent to the player. 1. *Opening Portcullises* - Implemented applying keys to locks - Portcullis animation is accomplished by an invisible object that sits on a portcullis and slowly consumes it. - *Game is now playable and feature complete* 1. *Playtest and Changes* - Player discovered a path through the map that allowed growing at the wrong time and thus getting locked out - Players were confused when they ran out of energy because they ignored the "eat insects" message. Added a new message at very low energy saying to rest. - Prevented the "rest" and "eat" messages from overriding the "key" messages - Players kept getting stuck with low energy, so decreased energy consumption rate and increased the food value of moths and mosquitos - Enlarged the minimap scale to 4px per tile to make it easier to see - Made the minimap "room" highlight smaller than the actual screen would be to help players identify their locations when in caves 1. *Debugging Options* - Added special debug spawn spot on the map to avoid moving the spawn point when debugging 1. *Win Condition* - Added new class of 2x2 tile graphics - Added Mommy Bat - Added `Cell.MOMMY_TYPE` - Kept Mommy Bat constantly highlighted to guarantee that she is visible at the end of the game - Twisted the path into Mommy Bat's cave to ensure that the player has cleared the portcullis and always approaches Mommy from the side instead of below 1. *Title screen* - Changed title to _Baby Bat Becomes a Hero_ at the request of my child playtesters - Added stylized text-only title screen - Added credits 1. *Audio* - Added royalty-free background music from http://www.bensound.com - Synthesized echo sound using Audacity and http://www.bfxr.net/ - Extracted flapping sounds from http://www.freesound.org/people/digifishmusic/sounds/43824/ - Used a random selection of flapping sounds to avoid repetition - Added sounds for close NPCs and for eating them - Added low-energy breathing sound - Made pulse rate decrease when at low energy