And so, the 3 week programming-course I’d been working with is over. The report is written, the program compiled (and worked!) flawlessly – although the last compile was done 1½ hour before the actual exam – and the board that ran our program is returned. I’m actually going to miss the thing, it was rather fun to work with – and game development is fun, especially when the idea is rather unique, and as thus, easy to write a lot about.
To give a quick rundown of the project, it was done by writing a program in C, that was sent via a serial port to a ZiLOG Z8 Encore! Z8F6403, and from there we could listen via a Telnet-based Terminal (from another serial port), and/or via the on-board LED display (which I got a nice example of here: The Failboard), and get inputs by pressing the 3 buttons. The first week was various exercises to get used to how it reacted to various things, how to control its register-calls, and coding C in general. The various exercises was naturally elements that would all be used in one way or the other in the final project. The last two weeks however, was where the interesting stuff started happening, as we finally got to know the final objectives: Create a game based on “ReflexBall” (which is basically ArkaNoid, without any objects to hit), and develop it into either (you guessed it) ArkaNoid, or something else entirely – pretty much freely chosen, but it had to satisfy certain criteria.
For the fun of it, we chose the latter, and got the idea for a – potentially – pretty fun idea: Gwardar. Naturally, that name doesn’t say much, but it should help a lot when looking at what a Gwardar actually is: a snake. So, our idea was a hybrid game of ReflexBall with Snake elements, which ended up being quite fun, and the actual game was – in fact – pretty fun as well.
I mainly worked on the gamefield – where the snake bounces around, collision detection – which was a much more essential part than for an ArkaNoid-game, as the ball/snake shouldn’t be able to hit itself, and react differently when hitting different things, and the ball/snake itself – which made sense to do together with collision, as that should be based upon where the ball was.
The first had some interesting challenges, as we only had a practical resolution of 63 x 21 “blocks” (columns and rows in the terminal-window, respectfully), and still wanted the ball/snake to be able to move with more than 8 different directions. As thus, we gave each block a 10×10 background, essentially giving us a gamefield of 630 x 210, which gave many more possibilities in terms of directions (early screen here, showing it). However, to properly do that, we had to ensure that the ball/snake always moved to a new block, which was done by scaling the directional vector, so that the numerically longest of x or y was exactly 10 (or: 1 block). Any more, or any less, would mean that it could potentially skip, or end up in the same block.
In regards to collision-detection, it was done by first detecting what was on the target block, judged from the directional vector, change it in case the target was a wall or the “striker” (the board the player controls), grow in length if objects was eaten, or die, in case it was itself, or the void below the striker. In the case it was hitting something that would change the vector, the new target block was checked, and the ball would only continue moving in the case that there wasn’t anything there – or it was an edible object. The tricky part about the collision was detecting when it was hitting itself, and let that be handled properly. To explain that, it’s probably best to explain the properties of the ball/snake first.
The ball was given a “history”, of up to 50 blocks, that kept track of up to the previous 50 positions it had been placed on the detailed gamefield (that is, in the 630 x 210 grid), which initially served as a way to “erase” the balls previous position when it was redrawn at a new position, but later – when the ball turned into a snake – also a way to show the tail itself, by only erasing the tail-length’th object in its history. In the end, the history was also used to place objects whenever eaten, at the very last position of the history – which turned out to look like it was random, especially when the tail length was short.
Getting back to the collision, it was obvious that low angles (meaning a directional vector of (10,1), for instance), would most likely cause the ball to “hit itself” upon bouncing against a wall, which would make it more or less impossible to ever reach the maximum length, or simply get very far at all. Still, it should naturally be possible to hit the tail, so we decided to simply ignore the first few parts of the history, when checking collision, so that the ball/snake had “time” to get free of itself. Hitting directly into a corner, would however still result death, as the overlap would be too great.
The other collision-based problem that surfaced was when “crossing itself”. A problem we never actually experienced exactly, but would look incredibly awkward if it did. Basically, it could happen as it would never actually hit itself, but on both sides, on points where both the “rough” x and y coordinates had changed (that is, on the 63 x 21 grid). Basically, it was done so that every time a situation like that happened, the collision-detection would check if both the coordinates (current_x, target_y) and (target_x, current_y) was in the ball’s history. In that case, it would have struck itself.
Now, going away from all the technical matter, the game proved to be very fun to play as well. The idea has been tried before, and there are quite many possible ways of combining the two basic games. In my personal opinion, ours was a success – but that’s always easy to say as one of the developers.
As a last word, here’s another screenshot, which should catch the idea pretty well. Try to imagine it with the tail being up to 50 “blocks” long.
Permalink
Minor show-casing, which I uploaded recently, can be seen here: http://www.youtube.com/watch?v=BZDS_8UvTLI