For the ADC, we use pin 0 to detect x-axis voltage, and pin 1 to detect y-axis voltage; ADMUX is altered each time to change the choice of analog inputs. Due to the time constraint of each frame, we use one frame to change ADMUX, and one frame to detect the voltage, which results in a 4-frame period for detection in both axes. However, due to the slow human reaction time, the long period is acceptable. As we are using TV as our output interface, we would like to avoid using interrupt; therefore, we stop the detection of voltage when the ADC Start Conversion bit in ADCSR becomes zero.
After we determine the horizontal x and y voltage from the calibration, we then divide the voltage range of each axis direction into 5 areas: fast decrement, slow decrement, unchanged, slow increment, and fast increment. The movement of the fighter can then be determined.
For the random appearing position of asteroids and monsters, we mainly use the function rand() to generate random numbers. However, as they are all pseudo-random numbers only, their pattern will be repeated. In order to avoid a repeated pattern, we have to change the seed irregularly. We have tried to use timer0 to trigger the change of seed, but it turns out that the pattern is still repetitive; therefore, we use the x-axis movement of the fighter to trigger it.
We generate one random number for each frame, and the following is the state diagram:
For the speed of various objects, we have a counter and a maximum value for each object. The counter increments every frame, and the object only moves if its counter value reaches the maximum value. The counter then resets to zero after the object has moved. For example, monRate (max. value) is set to 2. Monster will then move for every 3 frames.
The frequencies of the appearance of monsters or asteroids are set by the variables astFreq and monFreq. For example, for asteroid, a random number is generated within a range from 1 to astFreq. If the number is from 1 to maximum number of asteroids, then that number indicates which asteroid is going to appear, provided that asteroid is not present. In this way, if we increase the number of astFreq, asteroid will appear less frequently.
To avoid flickering, we try to avoid all monster or all asteroids to update at the same frame. Therefore, we introduce univCnt, which increments every frame. Only the monster or asteroid whose number is an even number can move when univCnt is even, and it’s the same case for odd number. In this way, the number of objects updated can decrease by half.
Speed of the components:
Bullet > Fighter (speed can be varied, according to user) > Monster > Asteroid
It is a 7X7 figure bitmap. It is the subject of our game, which is controlled by the user to avoid all the obstacles and monsters, shoot the monsters to get as many points as possible. It is allowed to go in 8 directions, with different speed settings.
The direction and speed is determined by the x-axis and y-axis voltage output from the accelerometer. The more the user tilts, the corresponding axis voltage will have a larger difference from the mean voltage, and thus a lower maximum counter value (faster speed). Calibration is needed upon reset to determine the horizontal voltage for both axes, which is necessary as it differs each time due to the noise.
It is a 16X16 figure which moves down (+y direction) with a speed specified by the variable astRate. As it is a big matrix which requires a lot of cpu time to redraw it every time, we only update the top 3 and bottom 3 rows as it moves. It serves as an obstacle that the fighter needs to avoid. It will move downward only.
It is an 8X8 figure. It basically chases the fighter, and the user dies if the fighter crashes with any monsters or asteroids. The monsters can only come out from the upper portion of the screen, and it will disappear when it reaches the bottom of the screen. Also, it will disappear when it is hit by a bullet, which is accounted for score.
Basically it moves in a direction that can approach the fighter. However, there are other constraints on top of this. It cannot go into any white cells or the wall. One special case is when the fighter is at the straight right direction of the monster, but there is an asteroid in-between. Taking account of the fact that the asteroid will move downward by itself, we would advise the monster to go upward instead of standing still so that it can climb through the asteroid faster. Another special case is that during the frame that the monster cannot move, an asteroid might crash into it. Therefore, if there are white objects above the monsters while the monster is not moving vertically, it will move downward.
When it reaches the bottom of the screen, it disappears, and the variables corresponding to this monster is available again for the next monster. As the fighter can only shoot upward, there is a big disadvantage for the fighter if it is chased by the monster at the back all the way. Therefore, if the monster is straightly behind the fighter and they are very far away, the monster will give up chasing, move to the bottom and get out of the screen.
To detect whether a monster is destroyed by a bullet, it needs to detect its bottom only. As a result, the monster disappears and score will be updated if there is a white cell behind the monster. To distinguish bullet from asteroids or other monsters, the moving algorithm is tailored such that it would not move to the top of any white objects. And if it is crashed by the fighter, it will still disappear, but at that time the game is over and it does not matter anymore.
It is a 5X1 figure. There are limited amount of bullets that the user can use (preset to 3), and we have one separate array of variables for each bullet. It always moves upwards, and will disappear upon reaching any white objects, including monsters, asteroids or the wall.
Each bullet has a corresponding variable. We set the maximum number of bullets be 3, which means there will be at most 3 bullets. It disappears when it hits any white objects.
Detecting crash: as every object can only move by 1 unit in each frame, if the fighter is moving in one direction, we do not have to take care of the objects at the opposite direction. Therefore, the algorithm is as follows: crash is signaled if there is a white cell next to the fighter along the direction the fighter is moving, excluding the wall. If the fighter is standing still, then we need to detect all four corners (as both monsters and asteroids are square shaped and larger than the fighter, detecting the corners is sufficient to see if they are next to the fighter). We detect the distance between the fighter and each monster in addition, due to the fact that the monster avoid white cells ( including asteroids and fighters), in some cases detecting white objects around the fighter is not enough.
Displaying score: for each frame, only the digit update will be drawn to avoid flickering.
When the fighter is hit, we will generate a series of figures, make the whole screen white and then black, and start off with the number of lives decreased by one. If the user has used up all lives (3 is predefined), we display “Game Over” and also the final score, and the user needs to press the “D” button again to play again, with the score being reset.
When we move to different stages after the fighter crashes, some simple tasks are being divided into a few stages due to time constraints and flickering.
State diagram for the whole program.
The trickiest part to write in the program is to generate a series of reasonably random numbers and to solve the problem of displaying large asteroids without flickering. One way to solve the asteroid problem is to reduce the size of the asteroids. However we would like to have larger obstacles to increase the difficulty of the game, therefore we turn to exploit the regularity of their shape. Flickering is also a problem. We solve those problems by splitting tasks into several frames.
To generate video signals and recognize keypad press result, we use part of the code on the ECE 476 website.
For this project, we originally tried to create a pen that can display what the user writes on paper on to the screen. However in order to make a pen, accurate movement detection is essential, and we have difficulties in finding inexpensive hardware for movement detection accurate enough for the use of a pen. Therefore, we change the project into a game that uses accelerometer control.