After thinking about tablets long and hard, I decided to try my hand at an extremely quick project in the unknown land of tablets. I decided that the RIM PlayBook is a solid platform for this, given its price, the fact that it's a local product, and the fact that it's neither an iPad nor an Android-based product. My plan was to make a small, but complete (music, sound, etc.) game, which could be put up on RIM's BlackBerry App World as a free download. I also thought that this would help RIM somewhat...
This time I actually logged my progress, thoughts, etc. I also describe the good and bad surprises of the platform and tools that I've encountered, hoping to ease the pain of other developers attempting to go down the same path I did. See the development log section below.
I was pleasantly surprised by the development kit options offered by RIM. I chose the Native SDK, which is C/C++ based because I was familiar to using C for game development, as well as OpenGL from back in my university years. And of course, being closer to the hardware is cool in itself.
My guiding design principles were simple:
- UI simplicity - user must be always clicking the playing field, and never any UI elements (buttons, selectors, etc.)
- whimsical graphics - preferrably created by myself
- music, sounds - many of my game projects don't include music and sound, but this one must be complete
- extremely fast production - ideally around two weeks (evenings and some weekends) to finish
It took exactly two weeks from the day I bought the PlayBook, until the day I wrapped up production for the game. The game is very simple; touch sheep to save them from the roaming bears. After enough sheep are saved, you get a bear horn powerup, and can scare a few bears away by touching them. Your attempts are graded from D to A+.
The game is available in the App World
- the source code. I built it using NDK 2.0.1
August 5 evening
- buy playbook
- configure playbook
August 6 morning
- chose and downloaded Native SDK (C/C++ with OpenGL)
- install SDK (had to give permission to the Everyone group to directory in Program Files, told me I shouldn't have spaces in installation directory and then closed down on me). Ended up installing somewhere else.
- request developer signing account (forced me to enter a company even though my development is not affiliated with my employer in any way)
- have to wait for up to two hours until my request is approved. playing video games until I get the email.
- 18 minutes later, the email comes
- firstapp is now running on the tablet in Debug mode, well integrated with the IDE
August 6 afternoon
- implemented rudimentary playfield scrolling via playbook screen events
- got texturing to work
- trying to get sound to work (playing an mp3)........ had to link to two additional libs as such:
# Add your required library names, here
LIBS+=bps screen EGL GLESv1_CM freetype png mmrndclient strm
(I had to add libraries "mmrndclient strm" at the end.)
- after some hair-pulling attempts, playing an mp3 finally works... had to do with an extra slash in how the asset path was built.
August 6 evening
- getting back into OpenGL (translations, rotations, etc.)
- brainstorm ideas. Tenets are: extremely simple UI/controls, whimsical graphics, semi-randomized levels, power ups.
- first idea: "Sheepish Bearings" - save sheep from bears (and other animals?). Bears spawn and chase sheep. Do they de-spawn? After X sheep, you get a "dog" power-up. Message box tells you your next Y clicks will place dogs. Message box fades away by itself. Banjo background music. Differently-coloured sheep and bears. Touch sheep to "save" them (they fly to the top of the screen, or to a corner maybe, while diminishing in size. Another power-up: bear horn. Next Z clicks on bears will scare them. Circle-based bounding box collision detection. User should only have to 1.scroll playfield 2.click game objects. This means there are no "game menu" button, and power-ups don't have to be selected. It's more rigid, but I believe it greatly improves the UI interaction. Set spawn points for bears on each level. Levels look differently. No collision detection between animals (only with background and edges). Fence at edge of playfield, no scrolling past it. Score is in sheep, and is overlaid in a corner. Current power-up overlaid near score. Pick up a "region", rather than ONE sheep?(with bonus for multiple sheep?). Should all touches affect a circular area?
- sound investigation. experimented with direct pcm playback, and then decided on using the mmr for sound effects as well, because it is much friendlier. Will use many mmr connections (for music, interface sounds, sheep sounds, bear sounds), OR a single connection for each type, and have the stop->start calls in a different thread, because stop->start sequences seem to lag quite a bit.
- transparency - used GIMP on standard PNGs, and soon my textured polygons were transparent!
- started drawing the textures. I wish I could draw.
- created the "good" project, and migrated everything from the scrap one. Forced orientation to landscape.
- description of sounds: "touch playfield"=short click "touch sheep"=no click "touch playfield during power-up"=bark! and horn!
- description of music: southern, banjo lead during gameplay (I will need a free sequencer). Should menu music be different?
- developed the audio module which provides functions to manage streams and initialize/terminate the audio system.
- build/ran using Release configurations for the first time. All was ok.
- TODO: Test stream closing/reopening
- TODO: Add a looping switch to stream_open
- There doesn't seem to be support for repeatable playback (loop) in libmmrndclient (via mmr calls). Fortunately, the stream_play function has no effect is the stream is already playing (and it re-plays the stream if it is stopped), so I'll probably call it every 30 frames or so, since it probably short-circuits early. The effect is at most one second of silence in the background music, which is acceptable if the mp3 fades in an out
- began writing the engine and graphics modules. The engine can spawn sheep, and the renderer draws them on screen
- Playfield is textured. Sheep use two animation frames to move around, confined by the playfield boundaries.
- Brainstorming, to add variety: both sheep and bears despawn by reducing in size to 0. Sheep despawn when eaten, bears despawn when scared by the bear horn. When bears and sheep spawn, they increase in size to the determined radius. With every eaten sheep, bears get bigger and faster. Saving sheep adds to score, eaten sheep detracts from score. Power-ups are based on a fixed number of saved sheep, and vary by level. Saved sheep fly off to the top of the screen.
touch (save or no save) - click
sheep eaten - baa!
bear spawn - growl!
acquire dog power-up, place dog - woof!
acquire bear horn power-up, use horn - horn sound!
August 11 afternoon
- IDE quirk: changing an included .h file won't cause the package to be updated upon a Build, perhaps only out of the box
- Brainstorming: sheep run away from closest bear, bears run away from closest dog
- sheep now turn around to run away from the closest bear, if they are within a configurable distance
- sheeps collide with objects (but are not handling it well just yet)
- Brainstorming: introduce a minimum number of frames before an entity can change direction
- TODO: Prevent against calling atan2 with (0.0, 0.0), as it may crash the program
August 12 morning
- sheep move away from obstacles properly
- bears chase sheep
- cleaned up obstacle generation to allow for better bear/sheep paths
- improved bear chase decision so that they are smoother around obstacles and boundary
- TODO: make bears head towards center of the playfield every now and then
August 12 evening
- created a safe wrapper for atan2 (arc tangent) defined in math.h
- bears that are near the boundary will sometimes wander towards the center of the playfield
- decided that bears do not get larger when they eat sheep, so that they don't get stuck behind objects
- de-sensitized scrolling code to allow for short involuntary playfield scrolls by the user to be treated as single touches, but not so much so that it makes scrolling feel delayed
- added a touchscreen to game co-ordinates converter and cleaned up move/touch events. It keeps track of where the viewport scrolled and will be very useful for user input. There was some difficulty with the proper calculations, since the OS reports the Y co-ordinate upside down, both X and Y are 0-based, and also because we only move the viewport when a touch event was followed by a move event.
- pulled input/scrolling/single touch code out in an "input" module, which accepts calls callbacks when scrolling or touching happens
- factored out all OpenGL and MMR logic from the main C file into their proper modules
- created a manager module
- more refactoring... main C file is now only in charge of reading events from the playbook, and delegating to the manager, which is now its only dependency
- introduced spawning/despawning sheep animation
- Brainstorming: change some of the obstacles to water, haystacks, logs, since they look good seen directly from above, and add variety to the backgrounds.
- added new textures and sound effects
- found some royalty free bluegrass music which will be perfect for the background music. Abandoned any delusion that I would be able to make awesome banjo music using a sequencer
- wired up sound events and continuous music playback
- fixed a nasty bug originating from entity radii being sometimes much lower than their final radii. The effect was bears and sheep getting spawned too close to objects and getting stuck
- TODO: add a second stream for the touch clicking
- added a second audio stream for when the screen is touched. This makes the "clicking" sound feel more responsive
- scrolling code now ignores scrolling by more than half the screen in ONE OS event. This is to prevent accidental jerking caused by touching the screen in two spots ALMOST at the same time
- the first time the two streams in charge of "clicking" are played, the sound is strange, and not the expected "click" at all. I can't seem to find a workaround, so I will need to hide it, possibly by having two things appear on the main screen as the game starts, and play those two streams once...
- re-drew all obstacle textures, and the playfield texture (green square with GIMP's noise filter applied)
- playfield boundary is shown
- added a circular indicator showing where the touch happened
- sheep are now saved by screen touches
- Brainstorming: possibly keep the "feeding mode"
- score will be rendered as a grade: D, C, B, A-, A, A+. Created textures for the grades (to be displayed on the main screen as "last attempt's score"
- wrote most of the powerup handling code (sound and icon)
- removed dogs completely from the game. It would have been funny to see the bears run from the dogs, but I think that it adds no strategy. The only powerup remains the bear horn
August 18 morning
- judging by the grease smudges on the playbook screen, it makes most sense to show the powerup icon in the top left corner of the screen, for minimal obstruction
- every now and then a huge sheep will spawn :D it has no special properties other than the fact that it's huge compared to all other sheep
- cleaned up a lot of duplicated code which drew simple polygons
- implemented menu, and how score is displayed
- added a stream just for the horn. The player must REALLY be made aware that they got the powerup
August 18 afternoon
- added a progress indicator for the bear horn so players can easily identify when they're about to receive it
- set game parameters in stone, so I can now begin creating the grading scale by gathering as much player performance data from play testing as possible
- registered with RIM, and created all images needed for a submission
- playtested a few scenarios, and decided on the grading scale
August 19 morning
- added boundary checking when scrolling
- added licence information to source files
August 19 afternoon
- last code touch-ups
- built project in Release mode, and prepared the release files
August 21 morning
- my RIM account was approved
- if using NDK 2.0.1, the blackberry-signer is found in bbndk-2.0.1\host\win32\x86\usr\bin
- if you get an error complaining that the Application-Development-Mode property is set to true while trying to sign your .bar file, you can manually edit the MANIFEST.MF inside the META-INF directory inside the .bar (after renaming it to .zip). Simply look for the Application-Development-Mode property, set it to false, repackage the .zip, and rename back to .bar
- package has been submitted for review. The process took about 45 minutes
August 23 morning
- Sheepish Bearings has been approved and is now up on BlackBerry App World!