Code : Tout sélectionner
; Kanoid Version 1.10 - Falsam
EnableExplicit
Enumeration
#ScoreFont
#BrickFont
#BigFont
#BigFontOutLine
#NormalFont
#Mainform
#Grid
; Pour environnement OSX
#VK_N = 78
#VK_PAUSE = 19
#VK_ESCAPE = 27
EndEnumeration
Structure DefBrick
Actif.b ; La brique n'est pas détruite
Col.i ; Position X
Lig.i ; Position Y
life.i ; Nombre de vie de la brique
Color.l ; Couleur : Depend du nombre de vie restant
BonusMalus.i ; Bonus ou Malus (Exemple: Ajout d'une vie, Augmentation de la vitesse de la balle)
Point.i ; Nombre de points ajouté au score quand la brique est détruite
EndStructure
Global NewList Brick.DefBrick()
Define.l Event, WEvent, MEvent, GEvent, TEvent, ActualTime, PreviousTime.d
Global WindowStyle.i = #PB_Window_ScreenCentered | #PB_Window_SystemMenu
; Grid
Global GridW.i, GridH.i
; Raquette : Position X,Y, Largeur/hauteur de la raquette, Vitesse
Global RacquetX.i, RacquetY.i, RacquetW.i, RacquetH.i
; Balle :Position X,Y, Largeur et hauteur de la balle
Global BallX.i, BallY.i, BallR.i, SpeedH.i, SpeedV.i, MinSpeed.i, MaxSpeed.i
Global OldBallX.i, OldBallY.i, OldSpeedV.i, OldSpeedH.i
; Affichage Score : Points obtenus et vie restante, Message
Global Score.i, life.i, Message.s
; Compteurs : Nombre de briques restantes, maximum de scenes , Maximum Random
Global Brick.i, MaxStage.i, MaxRnd.i
; Indicateurs : Brique en mouvement vers le bas, Scene en cours, Glue, Balle inactive, Balle perdu
Global BrickDown.b, Stage.i, Glue.b, Inactif.i, LostBall.i
Procedure Open_MainForm()
OpenWindow(#Mainform, 0, 0, GridW, GridH, "Kanoid", WindowStyle)
CanvasGadget(#Grid, 0, 0, GridW, GridH, #PB_Canvas_Keyboard)
SetActiveGadget(#Grid)
AddWindowTimer(#Mainform, 1, 10)
EndProcedure
Procedure MessageBox(Message.s)
DrawingMode(#PB_2DDrawing_AlphaBlend) ; Fond
RoundBox(50, 150, GridW - 100, GridH - 300, 8, 8, RGBA(245, 245, 245, 155))
DrawingMode(#PB_2DDrawing_Outlined) ; Contour
RoundBox(50, 150, GridW - 100, GridH - 300, 8, 8, RGB(254, 244, 253))
DrawingMode(#PB_2DDrawing_Transparent)
DrawingFont(FontID(#BigFont))
DrawText((GridW - TextWidth(Message)) / 2, (GridH - TextHeight(Message)) / 2, Message, RGB(189, 19, 172))
EndProcedure
Procedure SetDefault()
RacquetW = 101
RacquetH = 10
BallR = 7
SpeedH = 0
SpeedV = 0
Inactif = 0
Glue = #False
LostBall = #False
EndProcedure
Procedure SetBrickColor(life)
Select life
Case 1
ProcedureReturn RGB(204, 205, 242)
Case 2
ProcedureReturn RGB(204, 120, 242)
Case 3
ProcedureReturn RGB(248, 120, 43)
Case 4
ProcedureReturn RGB(255, 199, 64)
EndSelect
EndProcedure
; Correction de la vitesse
Procedure SetSpeed(Value1.i, Value2.i)
Protected Result
If Value1 = 0 And Value2 = 0 ; La balle est stoppée
SpeedH = 0
SpeedV = 0
Result = #True
Else
If Abs(SpeedH + Value1) >= MinSpeed And Abs(SpeedH + Value1) <= MaxSpeed And Value1 <> 0
SpeedH + Value1
Result = #True
Else
Result = #False
EndIf
If Abs(SpeedV + Value2) >= MinSpeed And Abs(SpeedV + Value2) <= MaxSpeed And Value2 <> 0
SpeedV + Value2
Result = #True
Else
Result = #True
EndIf
; La vitesse ne peut pas etre nul
If Abs(SpeedH) = 0
SpeedH = MinSpeed
EndIf
If Abs(SpeedV) = 0
SpeedV = MinSpeed
EndIf
EndIf
ProcedureReturn Result
EndProcedure
Procedure NewStage(Value.i)
Protected Lig.i, Col.i, N.i
ClearList(Brick())
Select Value
Case 1 ; Niveau 1
For Lig = 80 To 200 Step 25
For Col = 50 To 700 Step 50
AddElement(Brick())
Brick()\Actif = #True
Brick()\Col = Col
Brick()\Lig = Lig
Brick()\life = Random(3) + 1
Brick()\Color = SetBrickColor(Brick()\life)
Brick()\Point = Brick()\life * 100
Brick()\BonusMalus = Random(MaxRnd)
Next
Next
Case 2 ; Niveau 2
N = 0
For Lig = 50 To 425 Step 25
For Col = 5 To N Step 50
AddElement(Brick())
Brick()\Actif = #True
Brick()\Col = Col
Brick()\Lig = Lig
Brick()\life = Random(3) + 1
Brick()\Color = SetBrickColor(Brick()\life)
Brick()\Point = Brick()\life * 100
Brick()\BonusMalus = Random(MaxRnd)
Next
N + 50
Next
Case 3 ; Niveau 3
For Lig = 150 To 375 Step 25
If Lig = 150 Or Lig = 375
For Col = 80 To 700 Step 50
AddElement(Brick())
Brick()\Actif = #True
Brick()\Col = Col
Brick()\Lig = Lig
Brick()\life = 4
Brick()\Color = SetBrickColor(Brick()\life)
Brick()\Point = Brick()\life * 100
Brick()\BonusMalus = Random(MaxRnd)
Next
Else
Col = 80
AddElement(Brick())
Brick()\Actif = #True
Brick()\Col = Col
Brick()\Lig = Lig
Brick()\life = 4
Brick()\Color = SetBrickColor(Brick()\life)
Brick()\Point = Brick()\life * 100
Brick()\BonusMalus = Random(MaxRnd)
Col = 680
AddElement(Brick())
Brick()\Actif = #True
Brick()\Col = Col
Brick()\Lig = Lig
Brick()\life = 4
Brick()\Color = SetBrickColor(Brick()\life)
Brick()\Point = Brick()\life * 100
Brick()\BonusMalus = Random(MaxRnd)
EndIf
Next
For Lig = 175 To 355 Step 25
For Col = 130 To 630 Step 50
AddElement(Brick())
Brick()\Actif = #True
Brick()\Col = Col
Brick()\Lig = Lig
Brick()\life = 2
Brick()\Color = SetBrickColor(Brick()\life)
Brick()\Point = Brick()\life * 100
Brick()\BonusMalus = Random(MaxRnd)
Next
Next
EndSelect
; Nombre de briques à détruire pour le niveau en cours
Brick = ListSize(Brick())
; Initialisation raquette et ball
SetDefault()
EndProcedure
; la raquette renvoie la ball
Procedure BrickCollision()
If Brick()\life = 0
Brick()\Actif = #False
Score + Brick()\Point
Brick - 1
Select Brick()\BonusMalus
Case 0, 1
Message = ""
Case 2 ; Balle plus grande
If BallR < 10
BallR + 1
Message = "Ball + "
EndIf
Case 3 ; Balle plus petite
If BallR > 5
BallR - 1
Message = "Ball -"
EndIf
Case 4 ; Augmentation de la vitesse verticale
If SetSpeed(0, 1)
Message = "Speed + 1"
EndIf
Case 5 ; Diminution de la vitesse verticale
If SetSpeed(0, -1)
Message = "Speed - 1"
EndIf
Case 6 ; Les briques commence à descendre
BrickDown = #True
Message = "Bricks down"
Case 7 ; Les briques arretent leurs progressions vers le bas
If BrickDown = #True
BrickDown = #False
Message = "Brick down stop"
EndIf
Case 8 ; Ajout d'une vie
life + 1
Glue = #False
Message = "Life + 1"
Case 9 ; Une vie en moins
If life > 3 ; On laisse au moins trois vie
life - 1
Message = "Life - 1"
EndIf
Case 10 ; Diminution de la raquette
If RacquetW > 100
RacquetW - 50
Message = "Racquet -"
EndIf
Case 11 ; Augmentation de la raquette
If RacquetW < 401
RacquetW + 50
Glue = #False
Message = "Racquet +"
EndIf
Case 12 ; Colle active
Glue = #True
Message = "Glue Actif"
Case 13 ; Colle inactive
If Glue = #True
Glue = #False
Message = "Glue Inactif"
EndIf
EndSelect
EndIf
Inactif = 0
; Toutes les briques sont détruites
If Brick = 0
Stage + 1
NewStage(Stage)
Message = "Stage " + Str(Stage) + "/" + Str(MaxStage)
EndIf
EndProcedure
Procedure Game_Refresh()
If IsGadget(#Grid)
If SpeedH = 0 And SpeedV = 0
; La vitesse de la balle est nulle : Elle est positionnée sur la raquette
If Glue = #False
BallX = RacquetX + RacquetW / 2
BallY = RacquetY - BallR
Else
BallX = RacquetX + OldBallX
BallY = RacquetY - BallR
EndIf
Else
;- La balle en cours de déplacement
BallX = BallX - SpeedH
BallY = BallY - SpeedV
EndIf
;- La balle atteint le cotes gauche ou droit du canvas
If BallX <= 0 + BallR Or BallX + BallR >= GridW
SpeedH * -1 ; Inversion de la direction de la balle
Inactif + 1 ; Aucune brique est touché
EndIf
;- La balle atteint le haut du canvas
If BallY <= 40 + BallR
SpeedV * -1 ; Inversion de la direction de la balle
Inactif + 1 ; Aucune brique est touché
EndIf
;- La balle percute une brique
ForEach (Brick())
If Brick()\Actif = #True
; La balle touche le cotes bas ou haut de la brique
If BallX >= Brick()\Col And BallX <= Brick()\Col + 40
If BallY <= Brick()\Lig + 25 And BallY > Brick()\Lig
Brick()\life - 1 ; La brique perd une vie
Brick()\Color = SetBrickColor(Brick()\life)
SpeedV * -1 ; Inversion de la direction de la balle
BrickCollision()
EndIf
Else
; La balle touche le cotes gauche ou droit de la brique
If BallY >= Brick()\Lig And BallY <= Brick()\Lig + 25
If BallX <= Brick()\Col And BallX > Brick()\Col + 40
Brick()\life - 1 ; La brique perd une vie
Brick()\Color = SetBrickColor(Brick()\life)
SpeedH * -1 ; Inversion de la direction de la balle
BrickCollision()
EndIf
EndIf
EndIf
EndIf
Next
;- La balle atteint le bas du canvas
If (BallY + BallR) >= RacquetY And SpeedH <> 0
Inactif + 1 ; Aucune brique est touché
Message = ""
; Mémorisation des vitesses atteintes
OldSpeedH = SpeedH
OldSpeedV = SpeedV
; Si le malus BrickDown est actif, chaque brique descend de 5 pixels
If BrickDown = #True And LostBall = #False
ForEach (Brick())
If Brick()\Actif
Brick()\Lig = Brick()\Lig + 5
If Brick()\Lig > RacquetY - 25
Message = "The bricks have reached the bottom of the screen !"
Stage + 1
SetDefault()
NewStage(Stage)
EndIf
EndIf
Next
EndIf
;- La balle arrive sur la raquette
If (BallX + BallR) >= RacquetX And BallX < (RacquetX + RacquetW / 3) And LostBall = #False
; Extemité gauche de la raquette
If Glue = #False
SpeedV * -1 ; Inversion de la direction de la balle
If SpeedH < 0
SpeedH * -1
EndIf
SetSpeed(2, 0)
Else
SetSpeed(0, 0)
OldBallX = BallX - RacquetX
EndIf
ElseIf (BallX + BallR) >= RacquetX And BallX <= (RacquetX + RacquetW / 2) And LostBall = #False
; Moitié gauche de la raquette
If Glue = #False
SpeedV * -1 ; Inversion de la direction de la balle
If SpeedH < 0
SpeedH * -1
EndIf
Else
SetSpeed(0, 0)
OldBallX = BallX - RacquetX
EndIf
ElseIf BallX > (RacquetX + RacquetW - RacquetW / 3) And (BallX - BallR) <= (RacquetX + RacquetW) And LostBall = #False
; Extrémité droite de la raquette
If Glue = #False
SpeedV * -1 ; Inversion de la direction de la balle
If SpeedH > 0
SpeedH * -1
EndIf
SetSpeed(-2, 0)
Else
SetSpeed(0, 0)
OldBallX = BallX - RacquetX
EndIf
ElseIf BallX >= (RacquetX + RacquetW / 2) And (BallX - BallR) <= (RacquetX + RacquetW) And LostBall = #False
; Moitié Droite de la raquette
If Glue = #False
SpeedV * -1 ; Inversion de la direction de la balle
If SpeedH > 0
SpeedH * -1
EndIf
Else
SetSpeed(0, 0)
OldBallX = BallX - RacquetX
EndIf
Else
;- La balle est perdu
LostBall = #True
SpeedV = 0 ; On evite le déplacement verticale
SpeedH = 1 ; La balle repart vers le cotes gauche
BallY = GridH - 2 * BallR
If BallX = 0
SpeedH = 0
life - 1
Message = "Ooooops : Life - 1"
SetDefault()
EndIf
EndIf
EndIf ; End Grid actif
If Inactif > 10 And SpeedV <> 0
Glue = #False
Inactif = 0
SetSpeed(0, 1)
Message = "No broken bricks for a long time : Speed +"
EndIf
;- Mise à jour du canvas
StartDrawing(CanvasOutput(#Grid))
; Efface l'image précédente
Box(0, 0, GridW, GridH, RGB(128, 128, 128))
; Affichage de l'entete
Box(0, 0, GridW, 40, RGB(241, 215, 221))
; Affichage des briques
ForEach Brick()
If Brick()\Actif = #True
DrawingMode(#PB_2DDrawing_Default)
RoundBox(Brick()\Col, Brick()\Lig, 45, 20, 5, 5, Brick()\Color)
DrawingMode(#PB_2DDrawing_Outlined)
RoundBox(Brick()\Col, Brick()\Lig, 45, 20, 5, 5, RGB(0, 0, 0))
DrawingMode(#PB_2DDrawing_Transparent)
DrawingFont(FontID(#NormalFont))
DrawText(Brick()\Col + (45 - TextWidth(Str(Brick()\life))) / 2, Brick()\Lig + 2, Str(Brick()\life), RGB(0, 0, 0))
EndIf
Next
; Affichage de la raquette
DrawingMode(#PB_2DDrawing_Default)
If Glue = #True
DrawingMode(#PB_2DDrawing_AlphaBlend)
RoundBox(RacquetX - 5, RacquetY - 5, RacquetW + 10, RacquetH + 5, 4, 4, RGBA(242, 161, 239, 155))
EndIf
DrawingMode(#PB_2DDrawing_Default)
RoundBox(RacquetX, RacquetY, RacquetW, RacquetH, 4, 4, RGB(169, 169, 169))
DrawingMode(#PB_2DDrawing_Outlined)
RoundBox(RacquetX, RacquetY, RacquetW, RacquetH, 4, 4, RGB(0, 0, 0))
; Affichage de la balle
DrawingMode(#PB_2DDrawing_Default)
Circle(BallX, BallY, BallR, RGB(255, 140, 0))
DrawingMode(#PB_2DDrawing_Outlined)
Circle(BallX, BallY, BallR, RGB(0, 0, 0))
; Affichage du bandeau (Score, Message, Vie)
DrawingMode(#PB_2DDrawing_Transparent)
DrawingFont(FontID(#ScoreFont))
DrawText(10, 10, "Score : " + Str(Score), RGB(0, 0, 0))
DrawText(150, 10, Message, RGB(0, 0, 0))
DrawText(GridW - 80, 10, "Life : " + Str(life), RGB(0, 0, 0))
; **Debug Vitesse et position de la balle ***
; DrawText(10, GridH-100, "Speed : " + Str(Abs(SpeedH))+"/"+Str(Abs(SpeedV))+" X/Y : "+Str(BallX)+"/"+Str(BallY), RGB(0,0,0))
; Message
If life = 0
BallR = 0
MessageBox("Game Over !")
EndIf
If Stage > MaxStage
MessageBox("Winner")
EndIf
StopDrawing()
EndIf
EndProcedure
Procedure Game_Start()
; Fonts
LoadFont(#NormalFont, "Arial", 10)
LoadFont(#ScoreFont, "Arial", 12)
LoadFont(#BigFont, "Arial", 70)
LoadFont(#BigFontOutLine, "Arial", 75)
; Affichage fenetre & canvas
GridW = 800
GridH = 700
If Not IsWindow(#Mainform)
Open_MainForm()
EndIf
SetDefault()
; Positionnement de la raquette (Px)
RacquetX = (GridW - RacquetW) / 2
RacquetY = GridH - 50
; Score
Score = 0
life = 3
; Bonus Malus
MaxRnd = 14
; Vitesse Minimum et maximum
MinSpeed = 1
MaxSpeed = 4
; Scene
Stage = 1
MaxStage = 3
; Premiere scene
NewStage(1)
EndProcedure
Procedure Game_Stop()
End
EndProcedure
Game_Start()
Repeat
Event = WaitWindowEvent()
WEvent = EventWindow()
MEvent = EventMenu()
GEvent = EventGadget()
TEvent = EventType()
Select Event
Case #PB_Event_Timer
Select EventTimer()
Case 1
Game_Refresh()
EndSelect
Case #PB_Event_Gadget
Select GEvent
Case #Grid
Select TEvent
Case #PB_EventType_LeftButtonDown
If SpeedH = 0 And life > 0 And Brick > 0
; La balle n'est pas encore lancé
If Glue = #True
; La colle est actif (Glue = #True)
SpeedH = -OldSpeedH
SpeedV = -OldSpeedV
Else
; La colle est pas active (Glue = #False)
SetSpeed(MinSpeed, MinSpeed + 2)
If BallX > GridW / 2
If SpeedH > 0
SpeedH * -1
EndIf
EndIf
EndIf
; Je force la glue pour test
; Glue=#True
EndIf
Case #PB_EventType_RightButtonDown
SpeedH * -1
Case #PB_EventType_MouseMove
; Cache le cursor
SetGadgetAttribute(#Grid, #PB_Canvas_Cursor, #PB_Cursor_Invisible)
; Récupération de la position horizontale (Cotes gauche) de la raquette
RacquetX = GetGadgetAttribute(#Grid, #PB_Canvas_MouseX)
If RacquetX + RacquetW > GridW
RacquetX = GridW - RacquetW
EndIf
Case #PB_EventType_KeyDown
Select GetGadgetAttribute(#Grid, #PB_Canvas_Key)
Case #VK_N ; Nouvelle partie
Game_Start()
Case #VK_PAUSE ; Partie en pause
SetSpeed(0, 0)
Case #VK_ESCAPE ; Fin du jeu
Game_Stop()
EndSelect
EndSelect ; End TEvent
EndSelect ; End Gevent
Case #PB_Event_CloseWindow
Game_Stop()
EndSelect ; End Event
ForEver