-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathTestApp.lean
More file actions
191 lines (156 loc) · 5.41 KB
/
TestApp.lean
File metadata and controls
191 lines (156 loc) · 5.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
import SDL
structure Color where
r : UInt8
g : UInt8
b : UInt8
a : UInt8 := 255
structure EngineState where
window : SDL.SDLWindow
renderer : SDL.SDLRenderer
deltaTime : Float
lastTime : UInt64
running : Bool
playerX : Int32
playerY : Int32
texture : SDL.SDLTexture
font : SDL.SDLFont
mixer : SDL.SDLMixer
track : SDL.SDLTrack
audio : SDL.SDLAudio
def SCREEN_WIDTH : Int32 := 1280
def SCREEN_HEIGHT : Int32 := 720
def TEXTURE_SIZE : Float := 64.0
inductive Key where
| W | A | S | D | Left | Right | Space | Escape
def keyToScancode : Key → UInt32
| .W => SDL.SDL_SCANCODE_W | .A => SDL.SDL_SCANCODE_A | .S => SDL.SDL_SCANCODE_S
| .D => SDL.SDL_SCANCODE_D | .Left => SDL.SDL_SCANCODE_LEFT | .Right => SDL.SDL_SCANCODE_RIGHT
| .Space => SDL.SDL_SCANCODE_SPACE | .Escape => SDL.SDL_SCANCODE_ESCAPE
def isKeyDown (key : Key) : IO Bool := SDL.getKeyState (keyToScancode key)
def setColor (renderer : SDL.SDLRenderer) (color : Color) : IO Unit :=
SDL.setRenderDrawColor renderer color.r color.g color.b color.a *> pure ()
def fillRect (renderer : SDL.SDLRenderer) (x y w h : Int32) : IO Unit :=
SDL.renderFillRect renderer x y w h *> pure ()
def renderScene (state : EngineState) : IO Unit := do
setColor state.renderer { r := 135, g := 206, b := 235 }
let _ ← SDL.renderClear state.renderer
setColor state.renderer { r := 255, g := 0, b := 0 }
fillRect state.renderer state.playerX state.playerY 100 100
let _ ← SDL.renderEntireTexture state.renderer state.texture 500 150 64 64
let _ ← SDL.renderTexture state.renderer state.texture 0 0 10 30 100 150 64 100
let message := "Hello, Lean SDL!"
let textSurface ← SDL.textToSurface state.renderer state.font message 50 50 255 255 255 255
let textTexture ← SDL.createTextureFromSurface state.renderer textSurface
let textWidth ← SDL.getTextureWidth textTexture
let textHeight ← SDL.getTextureHeight textTexture
let _ ← SDL.renderEntireTexture state.renderer textTexture 50 50 textWidth textHeight
pure ()
private def updateEngineState (engineState : IO.Ref EngineState) : IO Unit := do
let state ← engineState.get
let currentTime ← SDL.getTicks
let deltaTime := (currentTime - state.lastTime).toFloat / 1000.0
let mut playerX := state.playerX
let mut playerY := state.playerY
if ← isKeyDown .A then playerX := playerX - 1
if ← isKeyDown .D then playerX := playerX + 1
if ← isKeyDown .W then playerY := playerY - 1
if ← isKeyDown .S then playerY := playerY + 1
engineState.set { state with deltaTime, lastTime := currentTime, playerX, playerY }
partial def gameLoop (engineState : IO.Ref EngineState) : IO Unit := do
updateEngineState engineState
let eventType ← SDL.pollEvent
if eventType == SDL.SDL_QUIT || (← isKeyDown .Escape) then
engineState.modify (fun s => { s with running := false })
if eventType == SDL.SDL_MOUSEBUTTONDOWN then
let (mouseX, mouseY) ← SDL.getMousePos
if ← SDL.isLeftMousePressed then
IO.println s!"Left click at ({mouseX}, {mouseY})"
if ← SDL.isRightMousePressed then
IO.println s!"Right click at ({mouseX}, {mouseY})"
if ← SDL.isMiddleMousePressed then
IO.println s!"Middle click at ({mouseX}, {mouseY})"
let state ← engineState.get
if state.running then
renderScene state
SDL.renderPresent state.renderer
gameLoop engineState
partial def run : IO Unit := do
unless (← SDL.init SDL.SDL_INIT_VIDEO) == 1 do
IO.println "Failed to initialize SDL"
return
let window ← try
SDL.createWindow "LeanDoomed" SCREEN_WIDTH SCREEN_HEIGHT SDL.SDL_WINDOW_SHOWN
catch sdlError =>
IO.println sdlError
SDL.quit
return
let renderer ← try
SDL.createRenderer window
catch sdlError =>
IO.println sdlError
SDL.quit
return
let texture ← try
SDL.loadImageTexture renderer "assets/wall.png"
catch sdlError =>
IO.println sdlError
SDL.quit
return
unless (← SDL.ttfInit) do
IO.println "Failed to initialize SDL_ttf"
SDL.quit
return
let font ← try
SDL.loadFont "assets/Inter-VariableFont.ttf" 24
catch sdlError =>
IO.println sdlError
SDL.quit
return
unless (← SDL.mixerInit) do
IO.println "Failed to initialize SDL_mixer"
SDL.quit
return
let mixer ← try
SDL.createMixer ()
catch sdlError =>
IO.println sdlError
SDL.quit
return
let track ← try
SDL.createTrack mixer
catch sdlError =>
IO.println sdlError
SDL.quit
return
let audio ← try
SDL.loadAudio mixer "assets/In_The_Dark_Flashes.mp3"
catch sdlError =>
IO.println sdlError
SDL.quit
return
match (← SDL.setTrackAudio track audio) with
| true => pure ()
| false =>
IO.println s!"Failed to set track audio"
SDL.quit
return
match (← SDL.playTrack track) with
| true => pure ()
| false =>
IO.println s!"Failed to play track"
SDL.quit
return
let initialState : EngineState := {
window := window, renderer := renderer
deltaTime := 0.0, lastTime := 0, running := true
playerX := (SCREEN_WIDTH / 2), playerY := (SCREEN_HEIGHT / 2)
texture := texture, mixer := mixer, track := track, audio := audio, font := font
}
let engineState ← IO.mkRef initialState
IO.println "Starting game loop..."
gameLoop engineState
SDL.quit
def EngineState.setRunning (state : EngineState) (running : Bool) : EngineState :=
{ state with running }
def main : IO Unit :=
run