Thankfully, we were able to implement all of the code in C without having to resort to assembly language. We wrote the code one flow diagram chunk at a time. First we drew the barriers, and the player, followed by a 6 by 5 array of the invaders. Then, we interfaced the player's movement and shooting with the joystick hardware- this simply amounts to moving the player one pixel left or right at each poll and drawing blank lines to the left and right of the player (to erase the previous artifact of the player). Bullets were implemented with a 4 pixel long line that moves up one pixel each frame and terminates at 1) the top of the screen or 2) when the setpixel() function returns a value of 1 at the tip of the bullet (i.e. the bullet hit something).
Next was the daunting task of animating the invaders' march. Thirty invaders cannot be drawn each frame without flicker. This is for several reasons. First and foremost, we need to draw lines to the left and right of the invader to erase the previous position of the invader as it marches along (similar to the player draw). Secondly, when the invaders march down 4 pixels at the end-of-screen (i.e. they are descending towards earth), we need to erase the 4 lines above each invader's new position; this draw routine turned out to be so significant that other operations (such as player polling and bullet updates) are put in hold each time the invaders march down the screen to prevent flicker. The basic problem is all of this code needs to be executed in the idle portions of the frame; too much code means the microcontroller won't go to sleep in time for the interrupt- which means problems with artifacts and flicker. So the task is not as straightforward as one might imagine. But it proved doable without going to assembly- by drawing only 3 invaders each frame, we are able to draw all 30 invaders "slowly" over 10 frames without flicker. And the user can't even tell the difference.
Another major concern with the march occurs when an entire row or column is eliminated. This resets the effective bounds of the invader's block- leading to longer marches across the screen until an invader hits the screens edge, and longer times until the invaders effectively land on the ground. Basically, I just check for the elimination of a row or column each time an invader is killed and update boundary variables accordingly (dead_row_left, dead_col_top, etc...- see the code section for further details).
Once that nightmare was over, we linked the player bullet routine to killing off the invaders. This is accomplished with embedded for loops. We cycle through each (x,y) position of every invader and see if it is within a horizontal and vertical range of the bullet's tip (within 8 horizontally and 10 vertically); of course, this condition only happens when the setpixel() function- which actually gets the pixel value at the current screen position- returns a value of 1 (i.e. the bullet hit something). Subsequently, the hit invader is flagged as a newly dead invader (with the just_killed variable) and is removed from the invaders character array. Then, on the next draw cycle, the just_killed flag variable is reset to null (30) and a blank 8 by 10 character is drawn in place of the invader to erase it from the screen. The updated invaders array tells the invader draw routine to simply ignore that invader in subsequent draws (this avoids time consuming draws of unnecessary lines and characters).
Anyway, the next step was implementing the invader shoots. This is accomplished by generating a psuedo-random number and %ing (modulus) it by 6 (the number of total columns). Then we step down the invader rows of that column to see which (if any) is the bottom-most living invader in that column. This is where the bullet starts. If there is no living invader in that column, no bullet is fired that round.
Finally gaming mode operations- such as round advancement and point systems- was completely ironed out. A small bug with the shooting routine allowed for two invaders to be jointly hit at the same time, leaving an artifact (because the just_killed flag can only hold one pointer a dead invader at a time). This final bug was fixed of course. Sound and music code was also implemented, which takes advantage of the microcontroller's onboard hardware compare-on-match timers.
If we had more time to play with our code.... (see Results and Conclusions)