Video raster generation: Our program outputs an NTSC video signal. We modified the code that we used for Lab 4 (TV oscilloscope) to implement our video game. For the NTSC video signal, the code puts out a sync pulse every 63.625us (actual NTSC standard is 63.5us but 63.625us still works and is conveniently 1/60 of a second) and then draws one line of video. NTSC video signals run off of 2 frames, interlaced at 30 frames per second each. In our case we are just using one frame. Between line 231 and 262 our state machine runs to update the program and the pixels to be displayed. Then the screen will be refreshed as the video signal is drawn again.
The heart of our software is run from the state machine. The behavior of the program in each state is as listed below:
The setup state is used to draw the current hole. The drawHole function is used to draw the different pieces of the hole with the color parameter set to 1 so that the pixels will be drawn in white. The game starts at hole 1 to begin play. The drawing of the hole is split up into multiple frames to preserve the quality and timing of the video signal. Each wall in the course is drawn and then a pixel is drawn for the starting point of the ball and a 3x3 square of pixels is drawn for the hole. The setup state also writes the par for the current hole and the hole number at the bottom of the screen and displays “shot 1.” Once these tasks are completed the state machine goes to state input1.
The input1 state reads the angle input from the user. There are 48 possible angles programmed into our game, one for directly right, one for directly up, one for directly left, one for directly down and then 11 in each of the 4 quadrants. Pressing button1 will move the angle one in the clockwise direction and pressing button2 will move the angle one in the counterclockwise direction. A pixel is drawn on the screen in the direction that the user is currently aiming. Once button0 is pressed the state machine goes to state input2.
After the angle is read from the user, the power needs to be set. As long as button0 is held down a power meter will scroll from left to right and then repeat. The farther the meter is to the right when the button is released the more power the shot will have. So as soon as button0 is released the current power (a number between 1 and 8) will be recorded and the state machine will enter state rolling.
In the rolling state the ball will move, reflect off of obstacles, decrease in speed and determine at each point if it has reached the hole. If the ball comes to a complete stop then the machine will increment the number of shots and go back to the input1 state to get ready for the next shot. If the ball enters the hole at any point then the state machine will go to the finish state to show that the hole has been completed and save the score for the current hole in an array. There are several different components of determining where the ball goes next: current speed, direction, changes in speed and possible obstacles.
Velocity and direction algorithm: The ball will start with a velocity between 1 and 8. Every frame a v_incr variable will count up from v (the magnitude of the velocity) to 8, trigger a signal and then start over. So if the velocity is 8 (highest power), the signal will be triggered every frame and if the velocity is 1 (lowest power), the signal will be triggered every 7 frames. Each time the signal is triggered, x_incr (which starts at 0) is increased by x_init and y_incr (which starts at 0) is increased by y_init. The ball will move in the x direction one pixel every time x_incr reaches 8 and the ball will move in the y direction one pixel every time y_incr reaches 8. X_init and y_init are values between 1 and 8 that are set according to the angle found in the input2 state. Because x_incr and y_incr have values between 1 and 8 added to them every time, they will jump past the value of 8, not just reach it. So whenever x_incr or y_incr go over 8, the ball is moved in the appropriate direction and 8 is subtracted from the variable. This will allow the ball to move in a direction at speeds other than multiples of frames (example: it can move 2 out of every 3 frames instead of just every frame, every 2 frames, every 3 frames, etc.). We found this algorithm to be a much better representation of a rolling ball than when we tried moving the pixel only at multiples of frames. Example of movement: if velocity = 8, x_init = 8 and y_init = 1, the ball will move one pixel in the x direction every single frame and will move one pixel in the y direction every 8 frames. If the xdir bit is high then the ball moves in the positive x direction, otherwise it will move in the negative x direction. The same is true for the ydir bit.
Slowing down: We have a counter that counts how many frames the ball has been moving at a certain velocity and then decrements v (the magnitude of the velocity) by 1. We found that decrementing the speed when the speed was high showed a much larger difference than decrementing the speed when the speed was low. So we made our algorithm change speeds slower at high speeds and change speeds sooner at low speeds (by counting up to a number that was proportional to v before changing speeds). Once v = 0 the state machine leaves the rolling state and goes to input1 state for the next shot.
Bouncing off of obstacles: Our find_obs function is used to detect obstacles. It searches through all of the lines in the flash memory for the current hole to see if there are any walls next to the ball. The holes are organized by groups of 4 coordinates representing x1, y1, x2, and y2 for each wall. The find_obs function uses the coordinates of every wall to set the radar1 bit high whenever there is a vertical wall to the right of the ball, radar2 bit high whenever there is a horizontal wall above the ball, radar3 bit high whenever there is a vertical wall to the left of the ball and radar4 bit high whenever there is a horizontal wall below the ball. Ydir flips when the ball hits a horizontal wall and xdir flips when the ball hits a vertical wall.
Sound: We output an audio signal that beeps when the ball is rolling. The spacing between the beeps becomes larger as the ball slows down to imitate the sound of a rolling ball.
In the finish state the hole has just been completed. When the ball first goes in the hole a quick scale is played to the audio signal to show that the ball went in the hole. Then “good job” is displayed on the screen. The state machine then waits until the user presses button0. As soon as the user presses button0, the machine goes into the delete state.
The delete state is used to clear the current hole before the next one is drawn. The deleting of the hole and the clearing of the “good job” on the screen is broken into multiple frames to preserve the video signal. The holes are deleted by calling the drawHole function with a value of 0 for the color so that it will overwrite all of the pixels with black. If it is the 9th hole then the machine will go to the scorecard state. Otherwise the machine will increment the current hole and return to setup to draw the next hole.
The scorecard state draws the scorecard so that the user can see his/her score on each hole, par for each hole, par for the course and the total score. The state machine will remain in the scorecard state until button0 is pressed, at which point the hole number will start over at 1 and the state machine will go to the setup state to play again.