' Revenge of the Bricks! ' (C) 2010 Kristopher Windsor ' A game-in-a-day for the competition: ' http://games.freebasic.net/forum/index.php?topic=382.msg4428#msg4428 #include once "fbgfx.bi" Type Font w As Integer h As Integer d As Any Ptr End Type Extern Font8 Alias "fb_font_8x8" As Font Extern Font14 Alias "fb_font_8x14" As Font Extern Font16 Alias "fb_font_8x16" As Font #define seconds * fps #define randomColor() rgb(rnd * 256, rnd * 256, rnd * 256) #macro startDisplayLoop() Dim As Double displaytime = Timer() Dim As Integer displayframetotal = 0 Dim As Integer displaydropframe = false 'this method effectively gives 60fps or 30fps, nothing in between Do displayframetotal += 1 #endmacro #macro startDisplayFrame() If displaydropframe = false Then Screenlock() Line (0, 0) - (screen_width - 1, screen_height - 1), &H10000000, BF #endmacro #macro endDisplayFrame() Screenunlock() End If #endmacro #macro endDisplayLoop() var timeleft = Cint(1000 * (displaytime + displayframetotal / fps - Timer())) displaydropframe = (timeleft < 0) If timeleft > 0 Then Sleep(timeleft, 1) Loop #endmacro Const true = -1, false = 0, pi = Atn(1) * 4 Const screen_width = 800, screen_height = 600, fps = 60, accuracy_multiplier = 40 Enum brick_enum normal invincible levelup End Enum Type brick_object_type As Double x, y, xv, yv As brick_enum style As Uinteger Color As Integer garbage End Type Type brick_type Const start_lives = 5 Const max = 256 Const Width = 78, height = 38 Const line_step = 19 Declare Sub Reset() Declare Sub move() Declare Sub display() As Integer lives As Integer selection, selectionx, selectiony As Integer invincicount, invincicountoriginal As Integer total As brick_object_type object(1 To max) End Type Type enemy_type Const ball_radius = 12 Const paddle_width = 200, paddle_height = 8 Const start_lives = 5 Declare Sub Reset() Declare Sub move() Declare Sub display() As Integer lives 'number of hits the paddle can take (ball off the screen -> level won) As Double speed As Double ballx, bally, ballxv, ballyv As Uinteger ballcolor As Double paddlex, paddletx As Uinteger paddlecolor End Type Type game_type Declare Sub Reset() Declare Sub move() Declare Sub display() Declare Sub titlescreen(text1 As String, text2 As String = "") Declare Sub play() Declare Sub Run() As Integer level As Integer score As Integer mx, my, mb, mxp, myp, mbp End Type Dim Shared As brick_type brick Dim Shared As enemy_type enemy Dim Shared As game_type game Sub PrintXY3(Byref f As Font, _ Byval xpos As Integer, _ Byval ypos As Integer, _ Byref text As String, _ Byval fgcol As Integer=&HFFFFFF, _ Byval bgcol As Integer=-1, _ Byval Size As Integer=1, _ Byval Filled As Integer=1, _ Byval Round As Integer=0 ) 'this function is by DJ Peters Dim As Integer i,y,yend,l,code,x,bits,sx Dim row As Ubyte Ptr l=Len(text)-1:If l<0 Then Exit Sub yend=f.h-1:If Size<1 Then Exit Sub Screeninfo sx For i = 0 To l code=text[i]:code*=f.h:row=f.d+code If Size>1 Then If Filled=0 Then For y = 0 To yend bits=*row For x=0 To 7 If (bits And 1) Then If Round=0 Then Line (xpos+x*size,ypos+y*size)-Step(size,size),fgcol,b Else Circle (xpos+x*size+size*0.5,ypos+y*size+size*0.5),size*0.5,fgcol End If Elseif bgcol<>-1 Then If Round=0 Then Line (xpos+x*size,ypos+y*size)-Step(size,size),bgcol,b Else Circle (xpos+x*size+size*0.5,ypos+y*size+size*0.5),size*0.5,bgcol End If End If bits=bits Shr 1 Next row+=1 Next xpos+=f.w*Size::If (xpos-f.w*Size)>sx Then Exit Sub Else ' filled For y = 0 To yend bits=*row For x=0 To 7 If (bits And 1) Then If Round=0 Then Line (xpos+x*size,ypos+y*size)-Step(size,size),fgcol,bf Else Circle (xpos+x*size+size*0.5,ypos+y*size+size*0.5),size*0.5,fgcol,,,,f End If Elseif bgcol<>-1 Then If Round=0 Then Line (xpos+x*size,ypos+y*size)-Step(size,size),bgcol,bf Else Circle (xpos+x*size+size*0.5,ypos+y*size+size*0.5),size*0.5,bgcol,,,,f End If End If bits=bits Shr 1 Next row+=1 Next xpos+=f.w*Size:If (xpos-f.w*Size)>sx Then Exit Sub End If Else 'no Size For y = 0 To yend bits=*row For x=0 To 7 If (bits And 1) Then Pset (xpos+x,ypos+y),fgcol Elseif bgcol<>-1 Then Pset (xpos+x,ypos+y),bgcol Endif bits=bits Shr 1 Next row+=1 Next xpos+=f.w:If (xpos-f.w)>sx Then Exit Sub End If Next End Sub Sub brick_type.reset() Dim As Integer lx, ly, ok lives += 1 selection = 0 invincicount = 0 total = 0 'code isn't great, but it works lx = Int(Rnd() * 4) + 1 ly = Int(Rnd() * 4) + 1 For x As Integer = 0 To 5 For y As Integer = 0 To 5 total += 1 With object(total) .x = (x + 2) * (Width + 2) .y = (y + 2) * (height + 2) .xv = 0 .yv = 0 If x = lx And y = ly Then .style = brick_enum.levelup Else .style = Iif(Rnd() < .4, brick_enum.invincible, brick_enum.normal) End If If .style = brick_enum.invincible Then invincicount += 1 .color = randomColor() .garbage = false End With Next y Next x invincicountoriginal = invincicount End Sub Sub brick_type.move() Dim As Integer a Dim As Double dx, dy 'set selection If game.mb = 0 And game.mbp > 0 Then selection = 0 If game.mb > 0 And game.mbp = 0 Then For i As Integer = 1 To total With object(i) If game.mx > .x And game.mx < .x + Width Then If game.my > .y And game.my < .y + height Then If .style = brick_enum.levelup Then If total < max Then total += 1 object(total) = object(i) With object(total) .style = brick_enum.normal .color = randomColor() End With selection = total End If Else selection = i End If Exit For End If End If End With Next i If selection > 0 Then selectionx = game.mx - object(selection).x - Width / 2 selectiony = game.my - object(selection).y - height / 2 End If End If 'handle selection If selection > 0 Then With object(selection) dx = game.mx - selectionx - .x - Width / 2 dy = game.my - selectiony - .y - height / 2 .xv += dx / 5000 .yv += dy / 5000 End With End If 'move all For i As Integer = 1 To total With object(i) .xv *= .995 .yv *= .995 .x += .xv .y += .yv If i = selection Or Abs(.xv) + Abs(.yv) > .1 Then Continue For If .x < -Width Or .x > screen_width Then .garbage = true If .y < -height Or .y > screen_height Then .garbage = true End With Next i 'break colliding bricks For i As Integer = 1 To total With object(i) If .style = brick_enum.levelup Then Continue For If enemy.lives > 0 Then If Abs((.x + Width / 2) - (enemy.paddlex + enemy.paddle_width / 2)) < (Width + enemy.paddle_width) / 2 Then If Abs((.y + height / 2) - (screen_height - enemy.paddle_height / 2)) < (height + enemy.paddle_height) / 2 Then .garbage = true game.score += 1 enemy.lives -= 1 End If End If End If For j As Integer = i + 1 To total If object(j).style = brick_enum.levelup Then Continue For If Abs(.x - object(j).x) < Width And Abs(.y - object(j).y) < height Then 'the faster moving brick survives If Abs(.xv) + Abs(.yv) > Abs(object(j).xv) + Abs(object(j).yv) Then object(j).garbage = true Else .garbage = true End If End If Next j End With Next i 'cleanup a = 1 While a <= total If object(a).garbage Then If object(a).style = brick_enum.invincible Then invincicount -= 1 total -= 1 For i As Integer = a To total object(i) = object(i + 1) Next i If selection = a Then selection = 0 Elseif selection > a Then selection -= 1 End If Else a += 1 End If Wend End Sub Sub brick_type.display() For i As Integer = 1 To total With object(i) Select Case .style Case brick_enum.normal Line (.x, .y) - Step(Width, height), .color, B For j As Integer = 0 To Width - line_step * 2 Step line_step Line (.x + j, .y + height) - Step(line_step * 2, -height), .color Next j Case brick_enum.invincible Line (.x, .y) - Step(Width, height), .color, BF Case brick_enum.levelup Line (.x, .y) - Step(Width, height), .color, BF Draw String (.x + Width / 2 - Len(lives & " hits") * 4, .y + height / 2 - 8), lives & " hits", &HFFFFFFFF End Select End With Next i If selection > 0 Then Line (object(selection).x + Width / 2, object(selection).y + height / 2) - (game.mx, game.my), &H40FFFFFF End If End Sub Sub enemy_type.reset() lives = start_lives speed = Sqr(2) ^ game.level / accuracy_multiplier ballx = screen_width / 2 - ball_radius bally = screen_height - paddle_height - ball_radius * 2 ballxv = speed ballyv = -speed paddletx = screen_width / 2 - paddle_width / 2 paddlex = paddletx ballcolor = randomColor() paddlecolor = randomColor() End Sub Sub enemy_type.move() Dim As Double dx, dy ballx += ballxv bally += ballyv If ballx < 0 Then ballxv = Abs(ballxv) If ballx + ball_radius * 2 > screen_width Then ballxv = -Abs(ballxv) If bally < 0 Then ballyv = Abs(ballyv) If bally + ball_radius * 2 > (screen_height - paddle_height) And lives > 0 Then ballyv = -Abs(ballyv) For i As Integer = 1 To brick.total With brick.object(i) dx = brick.width / 2 + ball_radius - Abs((.x + brick.width / 2) - (ballx + ball_radius)) dy = brick.height / 2 + ball_radius - Abs((.y + brick.height / 2) - (bally + ball_radius)) If dx < 0 Or dy < 0 Then Continue For Select Case .style Case brick_enum.normal .garbage = true Case brick_enum.invincible If ballx < 0 Or ballx + ball_radius * 2 > screen_width Then .garbage = true If bally < 0 Or bally + ball_radius * 2 > (screen_height - paddle_height) Then .garbage = true Case brick_enum.levelup If brick.lives > 0 Then brick.lives -= 1 End Select If dx < dy Then ballx -= dx * Sgn((.x + brick.width / 2) - (ballx + ball_radius)) ballxv *= -1 Else bally -= dy * Sgn((.y + brick.height / 2) - (bally + ball_radius)) ballyv *= -1 End If Exit For End With Next i If lives <= 0 Then Return dy = screen_height - paddle_height - ball_radius * 2 If ballyv > 0 Then dy = (dy - bally) / ballyv Else dy = (dy + bally) / -ballyv End If paddletx = ballx + ball_radius + dy * ballxv - paddle_width / 2 If paddletx < 0 Then paddletx = 0 If paddletx + paddle_width > screen_width Then paddletx = screen_width - paddle_width paddlex += (paddletx - paddlex) / 10 / accuracy_multiplier End Sub Sub enemy_type.display() Circle (ballx + ball_radius, bally + ball_radius), ball_radius, ballcolor,,, 1, F If lives > 0 Then Line (paddlex, screen_height) - Step(paddle_width, -paddle_height), paddlecolor, BF End Sub Sub game_type.reset() brick.reset() enemy.reset() End Sub Sub game_type.move() For i As Integer = 1 To accuracy_multiplier mxp = mx myp = my mbp = mb If Getmouse(mx, my,, mb) Then mx = mxp my = myp mb = mbp End If Select Case Inkey() Case "r" brick.lives = 0 Case Chr(27), Chr(255, 107) System() End Select brick.move() enemy.move() Next i End Sub Sub game_type.display() brick.display() enemy.display() End Sub Sub game_type.titlescreen(text1 As String, text2 As String = "") #define x(text) screen_width / 2 - 32 * Len(text) #define show(text, y) PrintXY3(font8, x(text), y, text, &H20FFFFFF, -1, 8, true, true) startDisplayLoop() If displayframetotal > 2 seconds Then Exit Do startDisplayFrame() If displayframetotal > .5 seconds Then show(text1, screen_height * .3) show(text2, screen_height * .3 + 100) End If endDisplayFrame() endDisplayLoop() End Sub Sub game_type.play() 'loop for a level Dim As Integer finalframes = 2 seconds Reset() titlescreen("Level " & level, "Score " & score) startDisplayLoop() If brick.lives <= 0 Or (enemy.lives <= 0 And enemy.bally > screen_height) Then finalframes -= 1 If finalframes = 0 Then Exit Do move() startDisplayFrame() display() endDisplayFrame() endDisplayLoop() If brick.lives <= 0 Then titlescreen("Gameover!", "Score " & score) Else var percent = Cint(100 * brick.invincicount / brick.invincicountoriginal) var bonus = Cint(percent / 10) score += bonus titlescreen(percent & "% saved", "+" & bonus & " bonus") End If End Sub Sub game_type.run() 'loop for a whole game brick.lives = brick.start_lives level = 0 score = 0 titlescreen("Revenge of", "the bricks!") Do level += 1 play() Loop Until brick.lives <= 0 End Sub #define imgoingtocall do : #define forever : loop REM Screenres screen_width, screen_height, 32,, fb.GFX_ALPHA_PRIMITIVES Randomize(Timer()) imgoingtocall game.run() forever !!! :D