Le but et de détruire les immeuble avant de les toucher.
Code : Tout sélectionner
; ============================================
; Jeu de Bombardement - Style Années 80
; By MetalOS
; ============================================
EnableExplicit
; Constantes
#SCREEN_WIDTH = 800
#SCREEN_HEIGHT = 600
#GROUND_HEIGHT = 50
#BUILDING_WIDTH = 30
#MAX_BUILDINGS = 25
#HELICOPTER_SIZE = 20
#BOMB_SIZE = 6
#MAX_BOMBS = 10
; Structures
Structure Building
x.i
height.i
width.i
currentHeight.i
fullyDestroyed.i
EndStructure
Structure Helicopter
x.d
y.d
row.i
speed.d
EndStructure
Structure Bomb
x.d
y.d
active.i
velocity.d
EndStructure
; Variables globales
Global Dim Buildings.Building(#MAX_BUILDINGS - 1)
Global Dim Bombs.Bomb(#MAX_BOMBS - 1)
Global Heli.Helicopter
Global Window.i, Canvas.i, Font.i, FontBig.i
Global Score.i, BestScore.i
Global GameOver.i, GameWon.i
Global RowHeight.i
Global BuildingsDestroyed.i
Global TotalBuildings.i
; ============================================
; Initialisation de l'hélicoptère
; ============================================
Procedure InitHelicopter()
Heli\x = #SCREEN_WIDTH - 50
Heli\y = 50
Heli\row = 0
Heli\speed = -3 ; Négatif pour aller de droite à gauche
RowHeight = 30
EndProcedure
; ============================================
; Initialisation des immeubles
; ============================================
Procedure InitBuildings()
Protected i.i, currentX.i = 100
For i = 0 To #MAX_BUILDINGS - 1
Buildings(i)\x = currentX
Buildings(i)\height = Random(150) + 100
Buildings(i)\currentHeight = Buildings(i)\height
Buildings(i)\width = Random(20) + 25
Buildings(i)\fullyDestroyed = #False
currentX + Buildings(i)\width + Random(20) + 20
Next i
BuildingsDestroyed = 0
TotalBuildings = #MAX_BUILDINGS
EndProcedure
; ============================================
; Initialisation des bombes
; ============================================
Procedure InitBombs()
Protected i.i
For i = 0 To #MAX_BOMBS - 1
Bombs(i)\active = #False
Next i
EndProcedure
; ============================================
; Dessiner un immeuble pixelisé
; ============================================
Procedure DrawBuilding(x.i, height.i, width.i, currentHeight.i, fullyDestroyed.i)
Protected i.i, j.i, windowSize.i = 6
If fullyDestroyed Or currentHeight <= 0
ProcedureReturn
EndIf
; Corps de l'immeuble (hauteur actuelle)
DrawingMode(#PB_2DDrawing_Default)
Box(x, #SCREEN_HEIGHT - #GROUND_HEIGHT - currentHeight, width, currentHeight, RGB(50, 50, 50))
; Fenàªtres
For i = 1 To (currentHeight / 18) - 1
For j = 1 To (width / 12) - 1
If Random(100) > 30
Box(x + j * 12 - 4, #SCREEN_HEIGHT - #GROUND_HEIGHT - currentHeight + i * 18, windowSize, windowSize, RGB(255, 255, 150))
Else
Box(x + j * 12 - 4, #SCREEN_HEIGHT - #GROUND_HEIGHT - currentHeight + i * 18, windowSize, windowSize, RGB(70, 70, 70))
EndIf
Next j
Next i
; Contour
DrawingMode(#PB_2DDrawing_Outlined)
Box(x, #SCREEN_HEIGHT - #GROUND_HEIGHT - currentHeight, width, currentHeight, RGB(0, 0, 0))
EndProcedure
; ============================================
; Dessiner l'hélicoptère pixelisé (orienté vers la gauche)
; ============================================
Procedure DrawHelicopter(x.i, y.i)
Protected size.i = #HELICOPTER_SIZE
; Corps principal
DrawingMode(#PB_2DDrawing_Default)
Box(x - size, y - size/2, size * 2, size, RGB(200, 50, 50))
; Cabine
Box(x - size, y - size/2 + 2, size, size - 4, RGB(120, 120, 180))
; Queue (à droite maintenant)
Box(x + size, y - 3, size, 6, RGB(180, 50, 50))
; Rotor principal (animation)
Protected rotorFrame.i = (ElapsedMilliseconds() / 40) % 4
DrawingMode(#PB_2DDrawing_Default)
Select rotorFrame
Case 0, 2
Line(x - size * 1.5, y - size - 3, size * 3, 2, RGB(100, 100, 100))
Case 1, 3
Line(x, y - size * 1.5 - 3, 2, size, RGB(100, 100, 100))
EndSelect
; Rotor de queue
Circle(x + size * 2, y, 4, RGB(100, 100, 100))
; Contour
DrawingMode(#PB_2DDrawing_Outlined)
Box(x - size, y - size/2, size * 2, size, RGB(0, 0, 0))
EndProcedure
; ============================================
; Lancer une bombe
; ============================================
Procedure DropBomb()
Protected i.i
; Vérifier qu'il n'y a pas déjà une bombe active
For i = 0 To #MAX_BOMBS - 1
If Bombs(i)\active
ProcedureReturn ; Ne pas autoriser une nouvelle bombe
EndIf
Next i
; Trouver un slot libre
For i = 0 To #MAX_BOMBS - 1
If Not Bombs(i)\active
Bombs(i)\x = Heli\x
Bombs(i)\y = Heli\y + #HELICOPTER_SIZE
Bombs(i)\velocity = 0
Bombs(i)\active = #True
ProcedureReturn
EndIf
Next i
EndProcedure
; ============================================
; Mise à jour des bombes
; ============================================
Procedure UpdateBombs()
Protected i.i, j.i
Protected gravity.d = 0.4
Protected bombLeft.i, bombRight.i, bombTop.i, bombBottom.i
Protected buildingLeft.i, buildingRight.i, buildingTop.i
Protected damageAmount.i = 30 ; Montant de dégà¢ts par bombe
For i = 0 To #MAX_BOMBS - 1
If Bombs(i)\active
; Appliquer la gravité
Bombs(i)\velocity + gravity
Bombs(i)\y + Bombs(i)\velocity
; Vérifier si la bombe touche le sol
If Bombs(i)\y >= #SCREEN_HEIGHT - #GROUND_HEIGHT
Bombs(i)\active = #False
Continue
EndIf
; Vérifier collision avec les immeubles
bombLeft = Bombs(i)\x - #BOMB_SIZE
bombRight = Bombs(i)\x + #BOMB_SIZE
bombTop = Bombs(i)\y - #BOMB_SIZE
bombBottom = Bombs(i)\y + #BOMB_SIZE
For j = 0 To #MAX_BUILDINGS - 1
If Not Buildings(j)\fullyDestroyed And Buildings(j)\currentHeight > 0
buildingLeft = Buildings(j)\x
buildingRight = Buildings(j)\x + Buildings(j)\width
buildingTop = #SCREEN_HEIGHT - #GROUND_HEIGHT - Buildings(j)\currentHeight
If bombRight >= buildingLeft And bombLeft <= buildingRight
If bombBottom >= buildingTop
; BOOM ! Réduire la hauteur de l'immeuble
Buildings(j)\currentHeight - damageAmount
Bombs(i)\active = #False
; Vérifier si l'immeuble est complètement détruit
If Buildings(j)\currentHeight <= 0
Buildings(j)\currentHeight = 0
Buildings(j)\fullyDestroyed = #True
BuildingsDestroyed + 1
Score + 100
Else
Score + 10 ; Petit bonus pour chaque hit
EndIf
If Score > BestScore
BestScore = Score
EndIf
Break
EndIf
EndIf
EndIf
Next j
EndIf
Next i
EndProcedure
; ============================================
; Mise à jour de l'hélicoptère
; ============================================
Procedure UpdateHelicopter()
; Déplacer l'hélicoptère
Heli\x + Heli\speed
; Si l'hélicoptère sort de l'écran à gauche
If Heli\x < -50
Heli\x = #SCREEN_WIDTH + 50
Heli\row + 1
Heli\y + RowHeight
; Augmenter légèrement la vitesse (en valeur absolue)
If Heli\speed > -6
Heli\speed - 0.2
EndIf
EndIf
EndProcedure
; ============================================
; Vérifier les collisions
; ============================================
Procedure CheckCollisions()
Protected i.i
Protected heliLeft.i = Heli\x - #HELICOPTER_SIZE
Protected heliRight.i = Heli\x + #HELICOPTER_SIZE
Protected heliTop.i = Heli\y - #HELICOPTER_SIZE/2
Protected heliBottom.i = Heli\y + #HELICOPTER_SIZE/2
; Collision avec le sol
If heliBottom >= #SCREEN_HEIGHT - #GROUND_HEIGHT
ProcedureReturn #True
EndIf
; Collision avec les immeubles
For i = 0 To #MAX_BUILDINGS - 1
If Not Buildings(i)\fullyDestroyed And Buildings(i)\currentHeight > 0
If heliRight > Buildings(i)\x And heliLeft < Buildings(i)\x + Buildings(i)\width
If heliBottom > #SCREEN_HEIGHT - #GROUND_HEIGHT - Buildings(i)\currentHeight
ProcedureReturn #True
EndIf
EndIf
EndIf
Next i
ProcedureReturn #False
EndProcedure
; ============================================
; Dessiner le jeu
; ============================================
Procedure DrawGame()
Protected i.i
If StartDrawing(CanvasOutput(Canvas))
; Ciel
DrawingMode(#PB_2DDrawing_Default)
Box(0, 0, #SCREEN_WIDTH, #SCREEN_HEIGHT - #GROUND_HEIGHT, RGB(135, 206, 235))
; Sol avec damier
For i = 0 To #SCREEN_WIDTH / 20
If (i % 2) = 0
Box(i * 20, #SCREEN_HEIGHT - #GROUND_HEIGHT, 20, #GROUND_HEIGHT, RGB(100, 200, 100))
Else
Box(i * 20, #SCREEN_HEIGHT - #GROUND_HEIGHT, 20, #GROUND_HEIGHT, RGB(80, 180, 80))
EndIf
Next i
; Dessiner les immeubles
For i = 0 To #MAX_BUILDINGS - 1
DrawBuilding(Buildings(i)\x, Buildings(i)\height, Buildings(i)\width, Buildings(i)\currentHeight, Buildings(i)\fullyDestroyed)
Next i
; Dessiner les bombes
DrawingMode(#PB_2DDrawing_Default)
For i = 0 To #MAX_BOMBS - 1
If Bombs(i)\active
; Bombe (cercle noir)
Circle(Bombs(i)\x, Bombs(i)\y, #BOMB_SIZE, RGB(0, 0, 0))
; Aileron
Line(Bombs(i)\x - 3, Bombs(i)\y - 8, 6, 0, RGB(50, 50, 50))
EndIf
Next i
; Dessiner l'hélicoptère
If Not GameOver And Not GameWon
DrawHelicopter(Heli\x, Heli\y)
ElseIf GameOver
; Explosion
DrawingMode(#PB_2DDrawing_Default)
Circle(Heli\x, Heli\y, 40, RGB(255, 100, 0))
Circle(Heli\x, Heli\y, 30, RGB(255, 200, 0))
Circle(Heli\x, Heli\y, 20, RGB(255, 255, 100))
EndIf
; Afficher le score et les stats
DrawingMode(#PB_2DDrawing_Transparent)
DrawingFont(FontID(Font))
DrawText(20, 20, "SCORE " + Str(Score), RGB(0, 0, 0))
DrawText(#SCREEN_WIDTH - 220, 20, "MEILLEUR " + Str(BestScore), RGB(0, 0, 0))
DrawText(20, 50, "BÂTIMENTS: " + Str(BuildingsDestroyed) + "/" + Str(TotalBuildings), RGB(0, 0, 0))
; Message Game Over
If GameOver
DrawingFont(FontID(FontBig))
Protected textWidth.i = TextWidth("GAME OVER")
DrawText((#SCREEN_WIDTH - textWidth) / 2, #SCREEN_HEIGHT / 2 - 60, "GAME OVER", RGB(255, 0, 0))
DrawingFont(FontID(Font))
Protected restartText.s = "Appuyez sur ESPACE pour redémarrer"
textWidth = TextWidth(restartText)
DrawText((#SCREEN_WIDTH - textWidth) / 2, #SCREEN_HEIGHT / 2, restartText, RGB(0, 0, 0))
EndIf
; Message Victory
If GameWon
DrawingFont(FontID(FontBig))
textWidth = TextWidth("VICTOIRE!")
DrawText((#SCREEN_WIDTH - textWidth) / 2, #SCREEN_HEIGHT / 2 - 60, "VICTOIRE!", RGB(0, 200, 0))
DrawingFont(FontID(Font))
restartText.s = "Tous les bâtiments sont détruits ! Appuyez sur ESPACE pour rejouer."
textWidth = TextWidth(restartText)
DrawText((#SCREEN_WIDTH - textWidth) / 2, #SCREEN_HEIGHT / 2, restartText, RGB(0, 0, 0))
EndIf
StopDrawing()
EndIf
EndProcedure
; ============================================
; Réinitialiser le jeu
; ============================================
Procedure ResetGame()
InitHelicopter()
InitBuildings()
InitBombs()
Score = 0
GameOver = #False
GameWon = #False
EndProcedure
; ============================================
; Programme principal
; ============================================
; Initialiser
BestScore = 0
; Créer la fenàªtre
Window = OpenWindow(#PB_Any, 0, 0, #SCREEN_WIDTH, #SCREEN_HEIGHT, "Bombardier - Années 80", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If Window
Canvas = CanvasGadget(#PB_Any, 0, 0, #SCREEN_WIDTH, #SCREEN_HEIGHT)
; Charger les polices
Font = LoadFont(#PB_Any, "Courier New", 18, #PB_Font_Bold)
If Not Font
Font = LoadFont(#PB_Any, "", 18, #PB_Font_Bold)
EndIf
FontBig = LoadFont(#PB_Any, "Courier New", 40, #PB_Font_Bold)
If Not FontBig
FontBig = LoadFont(#PB_Any, "", 40, #PB_Font_Bold)
EndIf
; Ajouter les raccourcis clavier
AddKeyboardShortcut(Window, #PB_Shortcut_Escape, 1)
AddKeyboardShortcut(Window, #PB_Shortcut_Space, 2)
; Initialiser le jeu
ResetGame()
; Timer pour l'animation (60 FPS)
AddWindowTimer(Window, 1, 16)
; Boucle principale
Define Event.i, quit.i = 0
Define spacePressed.i = 0, lastSpaceState.i = 0
Define currentSpaceState.i
Repeat
Event = WaitWindowEvent(10)
Select Event
Case #PB_Event_CloseWindow
quit = 1
Case #PB_Event_Timer
If EventTimer() = 1
If Not GameOver And Not GameWon
UpdateHelicopter()
UpdateBombs()
; Vérifier les collisions
If CheckCollisions()
GameOver = #True
EndIf
; Vérifier la victoire
If BuildingsDestroyed >= TotalBuildings
GameWon = #True
EndIf
EndIf
DrawGame()
EndIf
Case #PB_Event_Menu
Select EventMenu()
Case 1 ; à‰chap
quit = 1
Case 2 ; Espace
If GameOver Or GameWon
ResetGame()
Else
; Larguer une bombe
spacePressed = 1
EndIf
EndSelect
EndSelect
; Détecter l'appui sur Espace pour larguer une bombe
If Not GameOver And Not GameWon
currentSpaceState = GetAsyncKeyState_(#VK_SPACE) & $8000
If currentSpaceState And Not lastSpaceState
DropBomb()
EndIf
lastSpaceState = currentSpaceState
If spacePressed
DropBomb()
spacePressed = 0
EndIf
EndIf
Until quit
; Nettoyage
RemoveWindowTimer(Window, 1)
If Font
FreeFont(Font)
EndIf
If FontBig
FreeFont(FontBig)
EndIf
EndIf
End