Introduction: Creating Animation and Games: Chapter 3 Lightcycles

Welcome to the third of a multi-part series: 
Creating Animation and Games: Chapter 3 Lightcycles

This series will dive into using Propeller microcontroller based systems to create your own graphics, animation, and video games.  I'll assume that you only have a very basic knowledge of microcontroller programming and take you step-by-step from beginning with a single dot to the creation of several video games which will provide you great examples for getting started with your own ideas.

If you haven't read the previous chapters, go back and review them first with the links above then continue with this Chapter.

In the last chapters you learned how to interact with game controllers and many basic Spin programming concepts.   This time we are going to take everything we've learned so far and create one of my favorite games, the Lightcycles game from Tron.   Lightcycles is a fun two player game which will require two controllers (and two players) to play the game.

I recommend the game controller / keyboard combination used with the Pocket Mini Computer/VGAplus boards, but two keyboards plugged into the Human Interface Board (use the mouse jack for the second keyboard) will also work just fine.   Remember the MIGS controller driver object we discussed in the last chapter is pretty flexible.   Almost any combination of controllers will probably be adaptable to this chapter.

As before, let's go full throttle and start creating the Lightcycles game.

First download the source code for this Chapter and extract it to a new empty folder.   We'll be working from that folder. 

Step 1: Lightcycles: CON Section

Open up the Propeller Tool again.   It's time to start creation of the Lightcycles game.

Start by typing the following eight lines:

Review: We are establishing settings which will remain CONstant throughout the operation of our program.

Be sure to choose the proper ColorMode.
(0 for standard vga color VGA, 1 for 256 color VGAplus256, TV can be either.)

Since we are using two controllers, set them to the starting I/O pins of the controllers you are planning to use:

Here are some examples:
  • Standard Propeller Demoboard, Human Interface Board, VGAplus or VGAplus256 keyboard = 26
  • Game controller on the VGAplus = 24
  • Game controller of the VGAplus256 = 26
  • Second Keyboard (using the mouse port) on the Human Interface Board = 24

It doesn't really matter which one is which.   MIGScontroller will be player 1, while MIGScontroller2 will be player 2.

Finally, right, left, up, down, and speed set some fixed variables required for the game itself.  
We'll talk about those later.

Step 2: Lightcycles: the OBJ Section

Next, type in the next nine lines.

Review: The OBJect section allows us to add additional code (objects) which can perform more complex tasks for our program.

The ' mark is used to create a comment or remark which is ignored by the program when run.

If you are using the Pocket Mini Computer (VGAplus or VGAplus256) this code will work perfectly without change.

If you are using the Human Interface Board with a second keyboard plugged into the mouse connection, change:

  • migs : "migs_wiiclassic"  to migs "migs_keyboard
(Don't forget the change the MIGScontroller and MIGScontroller2 to 24 and 26 as discussed on the last page.)

Also, change the video : line to use either the VGA driver or the TV driver depending on your video output.

Step 3: Lightcycles: the VAR Section

It's time to create the VAR section of our game.   Type in the next thirteen lines:

Review:  The VARiable section establishes containers which can store information during the operation of our program.  Unlike the definitions in the CON section, these containers may be emptied and refilled at any time.   

Since our game is a two player game, you will see a lot of repetition as we create duplicate code for each player. 

The "byte" sized boxes will contain the following:

one_x & two_x will contain the current x position of each player's lightcycle on the screen.
one_y & two_y will contain the current y position of each player's lightcycle on the screen.
one_color & two_color will contain the color of each player's lightcycle.

(If you are starting to think this sounds a lot like we are going to the use the video.plot command, you would be right!)

one_direction and two_direction to keep track of each player's possible direction on the screen.  (left,right, up and down)

We need a few extra byte boxes we can recycle here and there in our program, so we are also establishing x,y, and z.
....and of course we added the long MIGstack[40] was added for Wii controllers.  (If you are using two keyboards, you can omit it.)

Step 4: Lightcycles: the PUB Section

We are "almost" ready to start writing the core of our game.   Just a few more settings need to be established!

Type in the next seven lines:

Review: Indentation is important in SPIN programs. 

Once again we have established the speed of 80Mhz with the system.Clock(80_000_00) line.

migs.init(MIGScontroller) and migs2.init(MIGScontroller2) start the two game controllers.
(cognew(updateMIGS, @MIGSstack) can be removed again if you are not using a Wii controller.

video.start(ColorMode) starts the SLUG video driver

Finally, video.Cls($02) clears the screen with the second of 256 colors.  (A black that is friendly with both TV and VGA screens.)

Step 5: Lightcycles: the Title Screen

Every great game needs a great intro screen!   Limber up your fingers and type in the following:

This looks like a lot of code, but in truth once we understand the first three lines, the rest will make perfect sense!

Remember how repeat loops work?   Everything indented below the repeat will loop over and over again until acted on.

repeat until MIGS.A == 1 or MIGS2.A ==1 starts the repeat loop which can only be stopped when either the A button on the controller is pressed or the A key on the keyboard is pressed to break the loop.   Until we press either, both MIGS.A and MIGS2.A will be 0.

Remember our byte sized boxes?  Z is one of those boxes.  Each time we go around the repeat loop +1 is added to Z.  Because Z is only byte sized, it can hold numbers from 0 to 255.   (The neat part is once 255 is reached, it simply resets to 0 again!)

Finally, a new SLUG command!

video.DrawChar({xposition},{yposition},{character#},{color}) places a 3x4 character much like the video.plot command places a dot.

The character# actually starts a 0, with the letter A starting at number 33.  

See the Z+{color number} used in at the end of the video.DrawChar commands?   Guess what they do?   Write the answer down somewhere and we'll see if you are right later when we run the program.

Once the loop has broken by pressing A, we need to setup the start of the game.  

Type these three lines below what you have already entered:

We actually going to create two other PUB functions called, DrawGrid and SetupPlayers a little later in our code.

Step 6: Lightcycles: the Game Loop!

Finally!  It's time to start writing the main repeat loop which will control the game!

Take a deep breath, then carefully type in the following code for player 1.

The first line, repeat is starts the game loop.  All the action will happen in here!

The next eight lines check to see if the player has pressed the right, left, down, or up buttons.
It's a lot like the control code we used in the last chapter, except this time we only change the value in the byte box, "one_direction" when a button is pressed.  (Remember those settings in CON where we assigned right, left, down, and up a fixed value?    If the player pressed the right button we could have said, one_direction := 1, but isn't one_direction := right much nicer?)

So the first eight lines don't create activity, they only change the value of one_direction depending on the button pressed.

The next eight lines change the position of player one's x and y position on the screen by adding one or subtracting one from one_x and one_y depending on the direction the player is facing each time the loop repeats.  

This means that the x and y position will change each time the loop repeats even if the player hasn't pressed a button.
(Kinda sounds like the rules of Lightcycles doesn't it?)

It's time to add the same section for player 2.   Continue the game loop with the following:

Step 7: Lightcycles: Collision Detection

Up to now the program is a two player drawing program.  Lightcycles isn't a game unless one player can loose.

Type in the following section of code below what you have already typed:

x:=video.peek(one_x,one_y) is a new SLUG command!

Each time the game loop gets to this point, we "peek" at the color of the position our "Lightcycle" has just moved to.  (It's x and y).
If we find that the space contains a color other than $02 {if x <> $02) then we draw a bunch of letters on the screen.  (The code which in indented below the if condition statement.

With exception to the border of the game board (we'll draw that soon) and the lines drawn by each player's lightcycle, any valid move should be black.   If we encounter a color other than that, we can assume we have run into something.

After drawing the words, PLAYER ONE CRASHED, we start another repeat loop waiting for one of the players to press A, then go onto clearing the screen, re-drawing the game grid, and setting the players back their start positions.

You might have guessed it!  We need a similar block of code for player 2.

Step 8: Lightcycles: "End of the Line"

Up to this point:
  1. We have checked the player's controllers to see if they have pressed a button.
  2. Updated the position of each player's x and y position each time the loop repeated.
  3. Checked to see if either player has crashed and stopped the game momentarily if they have.

Now it's time to actually update the position of each player on the screen.

Type in the following four lines:

The first two lines you probably recognize from the last chapter.  We plot the x and y position of each player on the screen.

video.VWait allows the video driver to keep up with the game, don't omit it.

repeat 100000 - speed * 100 is a simple repeat loop that does nothing except delay the loop a little to slow down the game.
(Remember the speed setting in CON?   I'll bet you can do the math here.)

This concludes the main game loop!  We aren't quite done yet, but close!

Step 9: Lightcycles: Finishing Code Snippets

Remember when we called DrawGrid at the start of the game?

Time to create the PUB function that draws a box around the screen.

Type in the next seven lines:

We used two repeat loops!  

The first repeat loop, repeat x from 1 to 126 draws a line across the top and bottom of the screen.
The second repeat loop, repeat y from 1 to 95 draws a line down the right and left of the screen.

Remember those byte boxes we created in the VAR section?   SetupPlayers sets all the game values to their starting positions.

and finally..  updateMIGS is only required if you are using a Wii game controller.

Step 10: Playing Lightcycles!

Save, then send the program to your Propeller using F10.

  • Player one's lightcycle will start moving downward, while player two's lightcycle will move upward.
  • Try to crash the other player by boxing them in.

See you in the next chatper when we go from playing with pixels to building sprites made from pixels! 

Good stuff is in the works!