Platformer 2D Opengl
Posted: Sun Jan 18, 2026 3:47 pm
An improved for my 2d platform game
Here the code :
And the link for free asset is here : https://opengameart.org/content/hero-sp ... rs-notoria
Here the code :
Code: Select all
EnableExplicit
UsePNGImageDecoder()
; =========================================================
; CONSTANTES
; =========================================================
#WIN_W = 800
#WIN_H = 600
#GROUND_Y = 520
#GRAVITY = 0.6
#JUMP_FORCE = -13
#SPEED = 4
#FRAME_W = 46
#FRAME_H = 50
#ANIM_IDLE = 0
#ANIM_WALK = 1
#ANIM_JUMP = 3
Define *pixels, event
; =========================================================
; STRUCTURE JOUEUR
; =========================================================
Structure Player
x.f
y.f
vx.f
vy.f
w.f
h.f
onGround.b
frame.i
frameTimer.i
anim.i
facing.i ; 1 = droite, -1 = gauche
EndStructure
Global player.Player
Global texID, imgW, imgH
; =========================================================
; FENETRE OPENGL
; =========================================================
OpenWindow(0, 0, 0, #WIN_W, #WIN_H, "Platformer 2D OpenGL - PureBasic",
#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenGLGadget(0, 0, 0, #WIN_W, #WIN_H)
glMatrixMode_(#GL_PROJECTION)
glLoadIdentity_()
glOrtho_(0, #WIN_W, #WIN_H, 0, -1, 1)
glMatrixMode_(#GL_MODELVIEW)
glLoadIdentity_()
glEnable_(#GL_TEXTURE_2D)
glDisable_(#GL_DEPTH_TEST)
; =========================================================
; TRANSPARENCE
; =========================================================
glEnable_(#GL_BLEND)
glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
; =========================================================
; CHARGEMENT SPRITE
; =========================================================
If LoadImage(0, "player-spritemap-v9.png") = 0
MessageRequester("Erreur", "Image player.png introuvable")
End
EndIf
imgW = ImageWidth(0)
imgH = ImageHeight(0)
StartDrawing(ImageOutput(0))
*pixels = DrawingBuffer()
StopDrawing()
glGenTextures_(1, @texID)
glBindTexture_(#GL_TEXTURE_2D, texID)
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MIN_FILTER, #GL_NEAREST)
glTexParameteri_(#GL_TEXTURE_2D, #GL_TEXTURE_MAG_FILTER, #GL_NEAREST)
glTexImage2D_(#GL_TEXTURE_2D, 0, #GL_RGBA,
imgW, imgH, 0,
#GL_BGRA_EXT, #GL_UNSIGNED_BYTE, *pixels)
; =========================================================
; INIT JOUEUR
; =========================================================
player\x = 100
player\y = #GROUND_Y - #FRAME_H
player\w = #FRAME_W
player\h = #FRAME_H
player\facing = 1
; =========================================================
; DESSIN JOUEUR
; =========================================================
Procedure DrawPlayer(*p.Player)
Protected u0.f, u1.f, v0.f, v1.f
; UV horizontales pour la frame
u0 = (*p\frame * #FRAME_W) / imgW
u1 = u0 + #FRAME_W / imgW
; UV verticales pour la ligne d'animation
v0 = ((*p\anim - 1) * #FRAME_H) / imgH
v1 = v0 + #FRAME_H / imgH
; flip horizontal : gauche = inversé, droite = normal
; If *p\facing = 1
; Swap u0, u1 ; regarder à gauche
; EndIf
glBindTexture_(#GL_TEXTURE_2D, texID)
glBegin_(#GL_QUADS)
If *p\facing = 1
; regarde à droite → UV normales
glTexCoord2f_(u0, v1) : glVertex2f_(*p\x, *p\y)
glTexCoord2f_(u1, v1) : glVertex2f_(*p\x + *p\w, *p\y)
glTexCoord2f_(u1, v0) : glVertex2f_(*p\x + *p\w, *p\y + *p\h)
glTexCoord2f_(u0, v0) : glVertex2f_(*p\x, *p\y + *p\h)
Else
; regarde à gauche → inverser UV X
glTexCoord2f_(u1, v1) : glVertex2f_(*p\x, *p\y)
glTexCoord2f_(u0, v1) : glVertex2f_(*p\x + *p\w, *p\y)
glTexCoord2f_(u0, v0) : glVertex2f_(*p\x + *p\w, *p\y + *p\h)
glTexCoord2f_(u1, v0) : glVertex2f_(*p\x, *p\y + *p\h)
EndIf
glEnd_()
EndProcedure
SetFrameRate(30)
; =========================================================
; BOUCLE PRINCIPALE
; =========================================================
Repeat
; -------------------
; EVENTS
; -------------------
Repeat
If WindowEvent() = #PB_Event_CloseWindow
End
EndIf
Until Event = 0
; -------------------
; INPUT
; -------------------
player\vx = 0
If GetAsyncKeyState_(#VK_LEFT)
player\vx = -#SPEED * 0.63
player\facing = -1
EndIf
If GetAsyncKeyState_(#VK_RIGHT)
player\vx = #SPEED * 0.63
player\facing = 1
EndIf
If GetAsyncKeyState_(#VK_SPACE) And player\onGround
player\vy = #JUMP_FORCE * 0.3
player\onGround = #False
EndIf
; -------------------
; PHYSIQUE
; -------------------
player\vy + #GRAVITY * 0.1
player\x + player\vx
player\y + player\vy
; collision sol
If player\y + player\h >= #GROUND_Y
player\y = #GROUND_Y - player\h
player\vy = 0
player\onGround = #True
EndIf
; -------------------
; ANIMATION
; -------------------
If player\onGround = 0
player\anim = #ANIM_JUMP
ElseIf player\vx <> 0
player\anim = #ANIM_WALK
Else
player\anim = #ANIM_IDLE
EndIf
; Avancer frames seulement pour walk et jump
If player\anim = #ANIM_WALK Or player\anim = #ANIM_JUMP
player\frameTimer + 1
If player\frameTimer > 6
player\frame + 1
player\frameTimer = 0
EndIf
EndIf
; Boucle frames selon animation
Select player\anim
Case #ANIM_IDLE : player\frame = 0 ; idle statique
Case #ANIM_WALK : player\frame = player\frame % 8
Case #ANIM_JUMP : player\frame = 4
EndSelect
; -------------------
; RENDER
; -------------------
glClearColor_(0.2, 0.2, 0.25, 1)
glClear_(#GL_COLOR_BUFFER_BIT)
glLoadIdentity_()
; sol
glDisable_(#GL_TEXTURE_2D) ; sol unie, pas de texture
glColor3f_(0.0, 0.8, 0.0)
glBegin_(#GL_QUADS)
glVertex2f_(0, #GROUND_Y)
glVertex2f_(#WIN_W, #GROUND_Y)
glVertex2f_(#WIN_W, #WIN_H)
glVertex2f_(0, #WIN_H)
glEnd_()
; joueur
glEnable_(#GL_TEXTURE_2D)
glColor3f_(1, 1, 1)
DrawPlayer(@player)
SetGadgetAttribute(0, #PB_OpenGL_FlipBuffers, #True)
;Delay(16)
ForEver