nkk_kan: This is the commented source for a game of mine, where a very simple alpha based fading is used. Look on it, if you wish.
Code: Select all
' LASER PIPES by Mlok
#Include "fbgfx.bi"
Declare Function drawlines(tile As Any Ptr, ctile As Byte) As Any Ptr
Declare Sub drawbox (x1 As Integer, y1 As Integer ,x2 As Integer ,y2 As Integer)
ScreenRes 552,552,32,1,&h40
Randomize Timer
Dim Shared As Any Ptr hline, vline
Dim As Any Ptr tile, backtile, basetile, bomb, fadeout
Dim As UByte ctilex = 4, ctiley, state = 1
Dim As Byte ctile, temptile, fall, chart(8, -1 To 14), counter(3), stopcheck, nexttile, bonus(3)
Dim As Integer cola, colb, x, y, z, changex, score, tilecount=35, x1, x2, y1, y2, level = 0
Dim As String keypressed
Dim As Double speedtime, speed = 0.8, fallspeed = 0.02, rand
/'
For the start, let's make a quick list of what each varible is used for:
Ptrs HLINE and VLINE are image buffers for pipes drawn on top of the image of a basic
tile without any lines: BASETILE.
Ptr TILE is image buffer for the actal falling tile.
Ptr BACKTILE is the background image buffer.
Ptr BOMB is the image buffer for the "bomb" tile type.
Ptr FADEOUT is the image buffer used for alpha blending effects and for some general
image storage as well.
UBytes CTILEX and CTILEY store the position of the falling tile.
Ubyte STATE stores the current state, states will be discussed later.
Byte CTILE stores the information about pipes in the falling tile.
Byte TEMPTILE is just sort of swapping space.
Byte FALL = 1 if the down arrow was pressed and the tile is on its way down, otherwise
FALL = 0.
Byte array CHART stores information about all tiles and pipes on the board.
Byte array COUNTER is used in the process of checking for long-enough pipes.
Byte STOPCHECK is used in the same process.
Byte NEXTTILE stores information about pipes in the tile which will come next.
Byte array BONUS sgnifies which pipe has currently the bonus property.
Integers COLA and COLB are colors used in the creation of the background.
Integers X, Y and Z are general purpose variables, mostly used in various FOR-NEXT
loops etc.
Integer CHANGEX is used for to shift the falling tile right/left according to user's
input.
Integers SCORE and LEVEL don't need to be explained
Integer TILECOUNT stores the number of tiles falled from the beginning of the current
level.
Integers X1, Y1, X2 and Y2 are the dimensions for the drawbox sub
String KEYPRESSED is just a container for InKey
Doubles SPEEDTIME and SPEED are used for tile movement timing. The smaller SPEED is,
the faster game runs, so better naming would be someting like delay, but what the
hell.
Double FALLSPEED is the speed into which the game is temporarily switched once user
pressed down arrow.
'/
Const light = RGBA(255,240,200,64)
Const lighter = RGBA(255,240,200,128)
Const dark = RGBA(8,16,32,64)
Const darker = RGBA(8,16,32,128)
Const text = RGB(0,48,192)
Const brighttext = RGB(0,64,240)
Const red = RGB(160,0,0)
Const brightred = RGB (240,0,0)
tile = ImageCreate(32,32,32)
basetile = ImageCreate(32,32,32)
backtile = ImageCreate(32, 32, RGB(0,40,80), 32)
bomb = ImageCreate (32,32,32)
hline = ImageCreate (32,6,32)
vline = ImageCreate (6,32,32)
fadeout = ImageCreate(288,480,32)
' The following section just pre-generates the grapihics into the buffers
For x = 0 To 31
For y = 0 To 31
rand = CUByte((Rnd - 0.5) * 20)
PSet basetile,(x, y), RGB(128 + rand, 136 + rand, 144 + rand)
Next y
Next x
Line basetile,(0,0)-(31,0),lighter
Line basetile,(0,1)-(0,31),lighter
Line basetile,(1,1)-(30,1),light
Line basetile,(1,2)-(1,30),light
Line basetile,(1,31)-(31,31),darker
Line basetile,(31,1)-(31,30),darker
Line basetile,(2,30)-(30,30),dark
Line basetile,(30,2)-(30,29),dark
Get basetile,(0,0)-(31,31), bomb
Line bomb, (6,6)-(25,25),RGB(80,16,0),b
Line bomb, (7,7)-(24,24),RGB(128,24,0),b
Line bomb, (8,8)-(23,23),RGB(168,48,0),b
Line bomb, (9,9)-(22,22),RGB(192,64,0),b
Line bomb, (10,10)-(21,21),RGB(170,56,0),b
Line bomb, (11,11)-(20,20),RGB(144,32,0),b
Line hline, (0,0)-(31,0),RGB(144,32,0)
Line hline, (0,1)-(31,1),RGB(170,56,0)
Line hline, (0,2)-(31,2),RGB(192,64,0)
Line hline, (0,3)-(31,3),RGB(168,48,0)
Line hline, (0,4)-(31,4),RGB(128,24,0)
Line hline, (0,5)-(31,5),RGB(80,16,0)
Line vline, (0,0)-(0,31),RGB(144,32,0)
Line vline, (1,0)-(1,31),RGB(170,56,0)
Line vline, (2,0)-(2,31),RGB(192,64,0)
Line vline, (3,0)-(3,31),RGB(168,48,0)
Line vline, (4,0)-(4,31),RGB(128,24,0)
Line vline, (5,0)-(5,31),RGB(80,16,0)
For x = 0 To 31 Step 2
Line backtile,(0+x,0+x)-(31,0+x),RGB(0,60-x*2,165-x*5)
Line backtile,(0+x,1+x)-(0+x,31),RGB(0,60-x*2,165-x*5)
Next x
' drawing background...:
screenlock
For y = 1 To 16
cola=RGB(0+y*0,0+y*4,0+y*11)
colb=RGB(0+y*0,0+y*5,0+y*10)
For x = y - 292 To 900 Step 24
Line (x-300,0)-(x+300,600),cola
Line (x-300,600)-(x+300,0),colb
Next x
Next y
Line (48,35)-(337,516),RGB(0,24,64),b
' ...and drawing the "welcome" screen:
Get(337,36)-(384,515),fadeout
drawbox (49,36,505,515)
Draw String (193,75),"L A S E R P I P E S",brightred
Draw String (249,95),"by Mlok",red
Draw String (65,125),"The goal of this game is to arrange the falling tiles", text
Draw String (77,145),"so that the lines inside the tiles match. Once you", text
Draw String (85,165),"manage to put at least four lines in a row, they", text
Draw String (157,185),"disappear, raising your score.", text
Draw String (61,205),"The more lines are in the row, the higher is the score", text
Draw String (57,225),"bonus. Additionally, if the disappearing row is the one", text
Draw String (69,245),"shown in BONUS tile, your score increase is doubled.", text
Draw String (241,275),"Controls:",brighttext
Draw String (73,295),"RIGHT/LEFT ARROW - Move the falling tile right/left", text
Draw String (141,315),"UP ARROW - rotate the falling tile", text
Draw String (85,335),"DOWN ARROW - drop the falling tile on the ground", text
Draw String (221,355),"P - pause game", text
Draw String (217,450),"<Enter to play>",brightred
Draw String (225,470),"<Esc to Quit>",red
screenunlock
Do
keypressed = InKey
If keypressed = Chr(13) Then Exit do
If keypressed = Chr(255)+"k" Or keypressed = Chr(27) Then GoTo quit
Sleep 10
Loop
screenlock
Put (337,36),fadeout,pset
' drawing the info-box on the right:
drawbox (385,36,505,515)
Draw String (425,75),"LEVEL", red
Draw String (425,180),"SCORE", red
Draw String (409,285),"NEXT TILE", red
Draw String (425,390),"BONUS", red
Line (427,313)-(462,348),RGB(0,52,130),b
Line (425,311)-(464,350),RGB(0,40,100),b
Line (423,309)-(466,352),RGB(0,28,70),b
Line (427,418)-(462,453),RGB(0,52,130),b
Line (425,416)-(464,455),RGB(0,40,100),b
Line (423,414)-(466,457),RGB(0,28,70),b
' generating initial NEXTTILE:
Nexttile = 0
For x = 0 To 3
If Fix(Rnd*2) = 1 Then nexttile = nexttile Or (1 Shl (x*2))
Next x
' drawing the main game board:
For x = 1 To 7
For y = 0 To 14
Put(x*32+49, y*32+36), backtile, PSet
Next y
Next x
For y = 0 To 14
Put(49, y*32+36), basetile, PSet
Put(305, y*32+36), basetile, PSet
Next y
ScreenUnLock
' starting the stopwatch:
speedtime = timer
/'
Now we are entering the main loop and will never come back above again. It is good
time to say something about the STATEs. Most of the time, the STATE = 0 and the loop
is just making rounds doing nothing more then watching for user's input and the time.
When something happens, the STATE changes and the program reacts accordingly.
Though I admit that may be not ideal for a little game like this, I liked this
concept and wanted to use it even though I've only some 3 states of which one is huge,
and the rests are quite miniature. In the other hand, this kind of core is good for
the game's future expansion, as new states are quite easy to add.
Here is the list of special STATEs which are currently in use:
If STATE = 1 Then the falling tile just landed and it is necessary to check for
long-enough pipes and also to create a new current tile. If the long-enoug pipes
are found, they dissappear. If a whole tile disappear, it is also necessary to
check if there are some other tiles on top of it, and if that is true, bring them
down and do the whole check for pipes again. And of course, rise the score properly.
The check if the game is on its end is here too.
As you can see, lot of things are happening here and the code of this section is
probably more than half of the whole program. I could've broken it in some SUBs or
FUNCTIONs, but I don't like to do that with code which is used only in one place of
the program, so.. it is like this, for now.
If STATE = 2 Then... nothing. This poor state was abondoned during the development.
If STATE = 3 Then the user pressed left or right arrow key and it is time to shift the
current tile accordingly.
If STATE = 4 Then the TIMER reached the time stored in SPEEDTIME + SPEED, which means
that it is necessary to move the current tile one position lower.
'/
Do
keypressed = Inkey
Select Case state
Case 1
' So here we go. A tile just landed and this is what we do:
' Update the CHART array with the current tile:
chart(ctilex,ctiley) = ctile
' This is a loop for both checking for long-enough pipes, raising the score,
' clearing CHART, as well as the screen, from the disappearing pipes and
' subsequent shifting of the rest of the tiles on the screen down,
' if necessary.
Do
stopcheck = 1
' Now we look for the horizontal pipes:
For y = 0 To 14
counter(0) = 0
counter(1) = 0
For x = 0 To 8
If chart(x,y) And 1 Then
counter(0) += 1
Else
If counter(0) >= 4 Then score += ((counter(0) + counter(0)^2)/2) * bonus(0)
counter(0) = 0
End If
If chart(x,y) And (1 Shl 4) Then
counter(1) += 1
Else
If counter(1) >= 4 Then score += ((counter(1) + counter(1)^2)/2) * bonus(1)
counter(1) = 0
EndIf
If x = 8 Then
If counter(0) >= 4 Then score += ((counter(0) + counter(0)^2)/2) * bonus(0)
If counter(1) >= 4 Then score += ((counter(1) + counter(1)^2)/2) * bonus(1)
EndIf
If counter(0) = 4 Then
stopcheck = 0
chart(x-3,y) = chart(x-3,y) And Not 1
chart(x-2,y) = chart(x-2,y) And Not 1
chart(x-1,y) = chart(x-1,y) And Not 1
chart(x,y) = chart(x,y) And Not 1
End If
If counter(1) = 4 Then
stopcheck = 0
chart(x-3,y) = chart(x-3,y) And Not (1 Shl 4)
chart(x-2,y) = chart(x-2,y) And Not (1 Shl 4)
chart(x-1,y) = chart(x-1,y) And Not (1 Shl 4)
chart(x,y) = chart(x,y) And Not (1 Shl 4)
EndIf
If counter(0) >= 5 Then
chart(x,y) = chart(x,y) And Not 1
EndIf
If counter(1) >= 5 Then
chart(x,y) = chart(x,y) And Not (1 Shl 4)
EndIf
Next x
Next y
' Now we look for the vertical pipes:
For x = 0 To 8
counter(2) = 0
counter(3) = 0
For y = 0 To 14
If chart(x,y) And (1 Shl 2) Then
counter(2) += 1
Else
If counter(2) >= 4 Then score += ((counter(2) + counter(2)^2)/2) * bonus(2)
counter(2) = 0
End If
If chart(x,y) And (1 Shl 6) Then
counter(3) += 1
Else
If counter(3) >= 4 Then score += ((counter(3) + counter(3)^2)/2) * bonus(3)
counter(3) = 0
EndIf
If y = 14 Then
If counter(2) >= 4 Then score += ((counter(2) + counter(2)^2)/2) * bonus(2)
If counter(3) >= 4 Then score += ((counter(3) + counter(3)^2)/2) * bonus(3)
EndIf
If counter(2) = 4 Then
stopcheck = 0
chart(x,y-3) = chart(x,y-3) And Not (1 Shl 2)
chart(x,y-2) = chart(x,y-2) And Not (1 Shl 2)
chart(x,y-1) = chart(x,y-1) And Not (1 Shl 2)
chart(x,y) = chart(x,y) And Not (1 Shl 2)
End If
If counter(3) = 4 Then
stopcheck = 0
chart(x,y-3) = chart(x,y-3) And Not (1 Shl 6)
chart(x,y-2) = chart(x,y-2) And Not (1 Shl 6)
chart(x,y-1) = chart(x,y-1) And Not (1 Shl 6)
chart(x,y) = chart(x,y) And Not (1 Shl 6)
EndIf
If counter(2) >= 5 Then
chart(x,y) = chart(x,y) And Not (1 Shl 2)
EndIf
If counter(3) >= 5 Then
chart(x,y) = chart(x,y) And Not (1 Shl 6)
EndIf
Next y
Next x
If stopcheck = 1 Then
' If STOPCHECK = 1, it means that no long-enough lines were found, so
' we can update the score on the screen and exit the checking loop.
Line (400,210)-(490,226), RGB(0,16,40),bf
Draw String (445-4*Len(Str(score)),210),Str(score), brightred
Exit Do
EndIf
' This is where the found long-enough pipes fade out off the screen.
Get (49,36)-(336,515), fadeout
For y = 0 To 14
For x = 1 To 7
If chart(x,y) = 0 Then
Get backtile,(0,0)-(31,31), tile
Else
Get basetile,(0,0)-(31,31), tile
tile = drawlines(tile,chart(x,y))
EndIf
Put fadeout,(x*32,y*32), tile, PSet
Next x
Next y
For x = 1 To 20
Put (49,36),fadeout, alpha, 16
Sleep 12
Next x
Put (49,36),fadeout, PSet
' Here the remaining tiles with pipes are piled down, if they have
' some space under themselves:
ScreenLock
For x = 1 To 7
z = 0
For y = 14 To 0 Step -1
If chart(x,y) <> 0 Then
If y < 14-z Then
chart(x,14-z) = chart(x,y)
chart(x,y) = 0
Put(x*32 + 49, y*32 + 36), backtile, PSet
Get basetile,(0,0)-(31,31), tile
tile = drawlines(tile,chart(x,14-z))
Put(x*32 + 49, (14-z)*32 + 36), tile, PSet
EndIf
z += 1
EndIf
Next y
Next x
ScreenUnLock
Loop
' Now let's initialize the new current tile:
ctiley = 0
' If the last tile was dropped on the ground using the down arrow, this will
' set the speed back to normal:
If fall = 1 Then
swap speed, fallspeed
fall = 0
End If
ctile = nexttile
' If there is alredy a tile on the place where the new tile should appear,
' the game is over.
If chart(ctilex, ctiley) <> 0 Then
drawbox (49,36,336,515)
Draw String (192-4*Len("You reached level "+Str(level)),200),"You reached level "+Str(level), red
Draw String (192-4*Len("With score " + Str(score)),250),"With score " + Str(score), brightred
Draw String (112,430),"<Enter to play again>", brighttext
Draw String (140,460),"<Esc to quit>", text
Do
keypressed = InKey
If keypressed = Chr(13) Then
' setting up new game:
' - clear the CHART
For x = 1 To 7
For y = 0 To 14
chart(x,y) = 0
Next y
Next x
' - clear the board
screenlock
For x = 1 To 7
For y = 0 To 14
Put(x*32+49, y*32+36), backtile, PSet
Next y
Next x
For y = 0 To 14
Put(49, y*32+36), basetile, PSet
Put(305, y*32+36), basetile, PSet
Next y
ScreenUnLock
' - reintialize some variables
ctiley = 15
ctilex = 4
score = 0
level = 0
state = 1
tilecount = 35
changex = 0
speed = 0.8
speedtime = timer
' - Exit SELECT into the main loop
Exit select
EndIf
If keypressed = Chr(27) Or keypressed = Chr(255)+"k" Then Exit do
Sleep 10
Loop
Exit Do
EndIf
' set and display the bonus pipe:
For x = 0 To 3
bonus(x) = 1
Next x
x = Fix(Rnd*4)
bonus(x) = 2
Get basetile,(0,0)-(31,31), tile
Select Case x
Case 0
tile = drawlines(tile,1)
Case 1
tile = drawlines(tile,1 Shl 4)
Case 2
tile = drawlines(tile,1 Shl 2)
Case 3
tile = drawlines(tile,1 Shl 6)
End Select
Put(429,420),tile, PSet
' set and display the new NEXTTILE:
nexttile = 0
For x = 0 To 3
If Fix(Rnd*2) = 1 Then nexttile = nexttile Or (1 Shl (x*2))
Next x
If nexttile = 0 Then Get bomb,(0,0)-(31,31), tile Else Get basetile,(0,0)-(31,31), tile
tile = drawlines(tile,nexttile)
Put(429,315),tile, PSet
' display the current tile on the top:
If ctile = 0 Then Get bomb,(0,0)-(31,31), tile Else Get basetile,(0,0)-(31,31), tile
tile = drawlines(tile,ctile)
Put(ctilex*32 + 49, ctiley*32 + 36), tile, PSet
' increase the TILECOUNT and check if it isn't enough for the next level:
tilecount += 1
If tilecount = 36 + level*4 Then
level += 1
' draw the level announcement box:
Get (143,192)-(243,232),fadeout
drawbox(143,192,243,232)
Draw string (194-4*Len("Level "+Str(level)),209),"Level " + Str(level), brightred
While InKey = "":Wend
For x = 1 To 20
Put (143,192),fadeout, alpha, 16
Sleep 12
Next x
Put (143,192),fadeout, PSet
tilecount = 0
' update the speed accordingly to the level:
speed -= 0.6/(level+4)
If speed < 0.08 Then speed = 0.08
Line (400,105)-(490,121), RGB(0,16,40),bf
Draw String (445-4*Len(Str(level)),105),Str(level),brightred
EndIf
state = 0
speedtime = Timer
Case 4
' if we are here, it means it is time to move the current tile down by one.
If ctiley = 14 Or chart(ctilex,ctiley+1) <> 0 Then
' Here we check if the tile isn't alredy on top of some other tile or on
' the ground. If that is true, STATE changes to 1.
' If the tile is a bomb, it is handled accordingly.
state = 1
If ctile = 0 Then
Put(ctilex*32 + 49, ctiley*32 + 36), backtile, PSet
ctiley += 1
If ctiley = 15 Then ctiley = 14
Put(ctilex*32 + 49, ctiley*32 + 36), tile, PSet
screenunlock
For x = 1 To 20
Sleep 12
Put(ctilex*32 + 49, ctiley*32 + 36), backtile, alpha, 16
Next x
Put(ctilex*32 + 49, ctiley*32 + 36), backtile, PSet
EndIf
speedtime = Timer
Exit Select
End If
' update the tile position on the screen:
screenlock
Put(ctilex*32 + 49, ctiley*32 + 36), backtile, PSet
ctiley += 1
Put(ctilex*32 + 49, ctiley*32 + 36), tile, PSet
screenunlock
state = 0
Case 3
' right/left arrow was pressed.. no big deal..
screenlock
Put(ctilex*32 + 49, ctiley*32 + 36), backtile, PSet
ctilex = ctilex + changex
Put(ctilex*32 + 49, ctiley*32 + 36), tile, PSet
screenunlock
state = 0
End Select
If state = 0 Then
' user input business:
Select Case keypressed
Case Chr(255) + "M"
' right arrow...
If ctilex = 7 Then Exit Select
If chart(ctilex+1, ctiley) <> 0 Then Exit Select
changex = 1
state = 3
Case Chr(255) + "K"
' left arrow...
If ctilex = 1 Then Exit Select
If chart(ctilex-1, ctiley) <> 0 Then Exit Select
changex = -1
state = 3
Case Chr(255) + "H"
' up arrow: rotate the pipes in the current tile
temptile = ctile
ctile = 0
If temptile And 1 Then ctile = ctile Or (1 Shl 2)
If temptile And (1 Shl 2) Then ctile = ctile Or (1 Shl 4)
If temptile And (1 Shl 4) Then ctile = ctile Or (1 Shl 6)
If temptile And (1 Shl 6) Then ctile = ctile Or 1
If ctile <> 0 Then
Get basetile,(0,0)-(31,31), tile
Else
Get bomb,(0,0)-(31,31), tile
EndIf
tile = drawlines(tile,ctile)
Put(ctilex*32 + 49, ctiley*32 + 36), tile, PSet
Case Chr(255) + "P"
' down arrow: drop the tile on the ground (or stop the fall if a tile is
' alredy falling)
If fall = 0 Then fall = 1 Else fall = 0
swap speed, fallspeed
Case "p", "P"
' pause game
Get (49,36)-(336,515), fadeout
drawbox (49,36,336,515)
Draw String (156,200),"P A U S E",RGB(192,0,0)
Draw String (108,260),"<any key to continue>",RGB(0,48,144)
do
keypressed = InKey
If keypressed = Chr(255)+"k" Then GoTo quit
If keypressed <> "" Then Exit do
Sleep 10
loop
Put (49,36),fadeout, PSet
speedtime = Timer
End Select
End If
' check if it is not the time to move tha current tile
If Timer - speedtime >= speed Then
speedtime = Timer
state = 4
End If
Sleep 1
Loop Until keypressed = Chr(27) Or keypressed = Chr(255)+"k"
quit:
ImageDestroy tile
ImageDestroy backtile
ImageDestroy basetile
ImageDestroy bomb
ImageDestroy hline
ImageDestroy vline
ImageDestroy fadeout
End
Function drawlines (tile As Any Ptr, ctile As Byte) As Any Ptr
' this function returns a tile on which pipes specified by CTILE are drawn.
If ctile And 1 Then Put tile,(0,6), hline, PSet
If ctile And (1 Shl 4) Then Put tile,(0,20), hline, PSet
If ctile And (1 Shl 2) Then Put tile,(20,0), vline, PSet
If ctile And (1 Shl 6) Then Put tile,(6,0), vline, PSet
Return tile
End Function
Sub drawbox (x1 As Integer, y1 As Integer ,x2 As Integer ,y2 As Integer)
' this sub (surprise) draws a box :-p
Line (x1,y1)-(x2,y2),RGB(0,64,160),b
Line (x1+1,y1+1)-(x2-1,y2-1),RGB(0,16,40),bf
Line (x1+2,y1+2)-(x2-2,y2-2),RGB(0,52,130),b
Line (x1+4,y1+4)-(x2-4,y2-4),RGB(0,40,100),b
Line (x1+6,y1+6)-(x2-6,y2-6),RGB(0,28,70),b
End Sub