Main sections
10 The First Game
One More
About the Game
The original game (I think) was part of a game called LOGO by Starbyte for the Amiga500. The aim is to remove all the colored dots from a playfield. Whenever the player clicks a block, this block and the four blocks surrounding the block toggle their state.
Thus, clicking the center point of this playfield:
###
###
###
Would cause it to look like:
#+#
+++
#+#
This game is pretty easy to program and leaves a lot of space for your own ideas to finish it. It's also nice since we can have computer generated levels. We simply have the computer randomly click some points. It's rather difficult to play once the computer has clicked more than 10 times or so...
New Project
After starting GLBasic, select the button "new project" and give it a name and a path for the project. e.g. "..\GLBasic\Projects\OneMore"
The Main Program
The basic code will look like this (pseudo-code):
main:
IF level_complete THEN create_new_level
IF mouse_click THEN change_clicked_stones
show_playfield
GOTO main
First we need a playfield to store whether a block is activated or deactivated (cleared). We use the value 0 for deactivated since the DIM command always sets all values to 0 automatically. Thus, the first IF statement will be evaluated and a new level will be created for us.
// --------------------------------- //
// Project: OneMore
DIM playfield[10][10]
level = 0
Now, we have an array called "playfield" that is 10x10 numbers in size. We can address them with the indices 0-9. See the DIM command.
// Main game
main:
MOUSESTATE mx, my, b1, b2
PRINT "<=", mx, my-8
SHOWSCREEN
GOTO main
END
Compile and run it. It looks nice, but it doesn't do much. We have a mouse pointer that we can move using the mouse. Take a look at the reference for all the commands we used here. The PRINT line is our mouse-pointer. You can load and use a nice sprite image for it later. The my-8 is because the font is 16 pixels high, and I subtracted half of it. Don't forget the SHOWSCREEN!
Showing the Playfield
Now we want to show the playfield data so we add a new subroutine (SUB). Press the SUB-button and enter the name: ShowPlayfield
// ------------------------------------------------------------- //
// -=# SHOWPLAYFIELD #=-
// ------------------------------------------------------------- //
SUB ShowPlayfield:
LOCAL x, y, color[]
DIM color[2]
color[0] = RGB( 50, 50, 255) // Not set
color[1] = RGB( 50, 255, 50) // Set
DRAWRECT 0,0, 320, 320, RGB(255,255,255)
FOR x=0 TO 9
FOR y=0 TO 9
DRAWRECT x*32+1, y*32+1, 30, 30, color[playfield[x][y]]
NEXT
NEXT
PRINT "Clicks: "+clicks, 360, 120
PRINT "Level: "+level, 360, 160
ENDSUB // SHOWPLAYFIELD
Here we create a local array called color and assign a blue color (50,50,255) to the first index [0] and a green color (50,255,50) to the second index [1]. Next, a white rectangle gets drawn that blanks out the playfield area.
We then do a double FOR loop, One for x and one for each y of each x.
In this loop we draw a filled rectangle for each cell of our playfield-array. We use color[ playfield[x][y] ] for the RGB value. Thus a zero in that array location causes a blue colored rectangle, a 1 causes a green colored rectangle.
Also we inform the user about the current level and the number of times they clicked for this level.
Add this line to the main game below the "MOUSESTATE" line:
GOSUB ShowPlayfield
and run the game. Looks better now, but there's not much interactivity here, right?
Interactivity
Next, add a function with the FUNCTION button and give the name "Change" and the arguments: x, y
This is the point where we want to change the playfield array.
// ------------------------------------------------------------- //
// -=# CHANGE #=-
// ------------------------------------------------------------- //
FUNCTION Change: x, y
// These values are defined LOCAL:
// x, y
IF x>=0 AND x<10 AND y>=0 AND y<10
set = playfield[x][y] // Get old state
IF set = TRUE
set=FALSE
ELSE
set=TRUE
ENDIF
// or simply:
// set = 1-set
playfield[x][y]=set // Set new state
ENDIF
ENDFUNCTION
In this function we will try to make the playfield[x][y] be 1 if it was 0 and vice versa. Before we change it though, we check if the point (x, y) is out of the 0-9, 0-9 bounds. If it is out of this range, we don't change anything or we will get an error from the running program: DIM out of range. This error means we've tried to update a value in our array which doesn't exist (the position we tried to update is "out of (the) range" of the array.
Now add another function with the FUNCTION button. Give it the name "Click" and the argument list: x, y
This is the point where the player clicks will be processed.
// ------------------------------------------------------------- //
// -=# CLICK #=-
// ------------------------------------------------------------- //
FUNCTION Click: x, y
// These values are defined LOCAL:
// x, y
clicks=clicks+1
Change(x-1, y)
Change(x+1, y)
Change(x, y)
Change(x, y-1)
Change(x, y+1)
ENDFUNCTION
Here, we Change() the value of the clicked point, as well as the points surrounding it. Also we increase a variable (clicks) indicating how often the player has clicked in this level.
Now change the main program, so it looks like:
DIM playfield[10][10]
level = 0
// Main game
start:
MOUSESTATE mx, my, b1, b2
IF b1
IF mousefree THEN Click(mx/32, my/32)
mousefree=FALSE
ELSE
mousefree=TRUE
ENDIF
GOSUB ShowPlayfield
PRINT "<=", mx, my-8
SHOWSCREEN
GOTO start
END
The mousefree variable tell us whether the user is still holding the mouse button down from the last time we processed the Click() function. If the player is still holding the button down, we don't reprocess the click again and again, but wait until they have released the mouse and then re-clicked it.
Now run the program. It should work nicely now. Get a feeling for how the game works. Click randomly a few times and try to clear the board again. Is it fun?
Levels
Add a new SUB called "NewLevel":
// ------------------------------------------------------------- //
// -=# NEWLEVEL #=-
// ------------------------------------------------------------- //
SUB NewLevel:
LOCAL x, y, i
// Clear playfield - just to be sure
FOR x=0 TO 9
FOR y=0 TO 9
playfield[x][y]=FALSE
NEXT
NEXT
level=level+1
// Do random clicks
FOR i=0 TO level
Click(RND(9), RND(9))
NEXT
clicks=0
GOSUB ShowPlayfield
PRINT "Level: "+level + " - get ready", 0, 360
SHOWSCREEN
MOUSEWAIT
ENDSUB // NEWLEVEL
In this subroutine, we first clear the playfield to really make sure it's cleared. Next we increase the level variable. The computer then clicks some random points (more are clicked as the level being played increases) in the playfield and we reset the number of clicks occurred back to 0.
The computer can now create a level but it doesn't know when the level is cleared. We need a function that tells us when this has occurred.
Add a function called "IsLevelComplete":
// ------------------------------------------------------------- //
// -=# ISLEVELCOMPLETE #=-
// ------------------------------------------------------------- //
FUNCTION IsLevelComplete:
LOCAL x, y
FOR x=0 TO 9
FOR y=0 TO 9
IF playfield[x][y]=TRUE THEN RETURN FALSE
NEXT
NEXT
RETURN TRUE
ENDFUNCTION
Here we simply loop through all the locations in our playfield and return FALSE if any of the playfield's cells is set to 1 (=TRUE). If the loop finishes without returning from the function, there must be no more green dots left, thus the board is clear and we return TRUE at the end of the function.
In order to test the whole game insert this code:
IF IsLevelComplete()
GOSUB NewLevel
mousefree=FALSE
ENDIF
to the main program after the main: jumpmark. Run the game. How does it feel to have written a complete computer game? If you add
BLENDSCREEN "images"+level".bmp"
to the NewLevel subroutine, the game is even better than the original Amiga game was back then! Doesn't that feel great? You are the master of the computer now - you tell it what to do and it follows your commands. You can create worlds with a few lines of code.
Here's the complete source code in case you might have missed something:
// --------------------------------- //
// Project: OneMore
DIM playfield[10][10]
level = 0
// Main game
start:
IF IsLevelComplete()
GOSUB NewLevel
mousefree=FALSE
ENDIF
MOUSESTATE mx, my, b1, b2
IF b1
IF mousefree THEN Click(mx/32, my/32)
mousefree=FALSE
ELSE
mousefree=TRUE
ENDIF
GOSUB ShowPlayfield
PRINT "<=", mx, my-8
SHOWSCREEN
GOTO start
END
// ------------------------------------------------------------- //
// -=# SHOWPLAYFIELD #=-
// ------------------------------------------------------------- //
SUB ShowPlayfield:
LOCAL x, y, color[]
DIM color[2]
color[0] = RGB( 50, 50, 255) // Not set
color[1] = RGB( 50, 255, 50) // Set
DRAWRECT 0,0, 320, 320, RGB(255,255,255)
FOR x=0 TO 9
FOR y=0 TO 9
DRAWRECT x*32+1, y*32+1, 30, 30, color[playfield[x][y]]
NEXT
NEXT
PRINT "Clicks: "+clicks, 360, 120
PRINT "Level: "+level, 360, 160
ENDSUB // SHOWPLAYFIELD
// ------------------------------------------------------------- //
// -=# CLICK #=-
// ------------------------------------------------------------- //
FUNCTION Click: x, y
// These values are defined LOCAL:
// x, y
clicks=clicks+1
Change(x-1, y)
Change(x+1, y)
Change(x, y)
Change(x, y-1)
Change(x, y+1)
ENDFUNCTION
// ------------------------------------------------------------- //
// -=# CHANGE #=-
// ------------------------------------------------------------- //
FUNCTION Change: x, y
// These values are defined LOCAL:
// x, y
IF x>=0 AND x<10 AND y>=0 AND y<10
set = playfield[x][y]
IF set = TRUE
set=FALSE
ELSE
set=TRUE
ENDIF
// or simply:
// set = 1-set
playfield[x][y]=set
ENDIF
ENDFUNCTION
// ------------------------------------------------------------- //
// -=# NEWLEVEL #=-
// ------------------------------------------------------------- //
SUB NewLevel:
LOCAL x, y, i
// Clear playfield - just to be sure
FOR x=0 TO 9
FOR y=0 TO 9
playfield[x][y]=FALSE
NEXT
NEXT
level=level+1
// Do random clicks
FOR i=0 TO level
Click(RND(9), RND(9))
NEXT
clicks=0
GOSUB ShowPlayfield
PRINT "Level: "+level + " - get ready", 0, 360
SHOWSCREEN
MOUSEWAIT
ENDSUB // NEWLEVEL
// ------------------------------------------------------------- //
// -=# ISLEVELCOMPLETE #=-
// ------------------------------------------------------------- //
FUNCTION IsLevelComplete:
LOCAL x, y
FOR x=0 TO 9
FOR y=0 TO 9
IF playfield[x][y]=TRUE THEN RETURN FALSE
NEXT
NEXT
RETURN TRUE
ENDFUNCTION