Skip to content

Commit b32f60c

Browse files
committed
add ui and start and game over screens
1 parent d42e9a5 commit b32f60c

5 files changed

+174
-39
lines changed

dist/fonts/Minecraftia-Regular.ttf

68.7 KB
Binary file not shown.

dist/fonts/WorkSans-Medium.ttf

140 KB
Binary file not shown.

gleam.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ target = "javascript"
1515

1616
[dependencies]
1717
gleam_stdlib = ">= 0.36.0 and < 2.0.0"
18-
p5js_gleam = ">= 2.1.1 and < 3.0.0"
18+
p5js_gleam = ">= 2.1.2 and < 3.0.0"
1919
prng = ">= 3.0.2 and < 4.0.0"
2020
gleam_community_maths = ">= 1.1.0 and < 2.0.0"
2121

2222
[dev-dependencies]
2323
esgleam = ">= 0.6.0 and < 1.0.0"
24-
startest = ">= 0.2.0 and < 1.0.0"
24+
startest = ">= 0.2.1 and < 1.0.0"

manifest.toml

+11-9
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
packages = [
55
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
6+
{ name = "bigben", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "bigben", source = "hex", outer_checksum = "8E5A98FA6E981EEEF016C40F1CDFADA095927CAF6CAAA0C7E295EED02FC95947" },
67
{ name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" },
78
{ name = "esgleam", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "simplifile"], otp_app = "esgleam", source = "hex", outer_checksum = "571D149ACFB7C7A81CF8C7A70ECFDA5A084ADBF706962353C0DA85787CB4DD24" },
89
{ name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" },
@@ -13,23 +14,24 @@ packages = [
1314
{ name = "gleam_community_maths", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_community_maths", source = "hex", outer_checksum = "E30C61A75051DAF7CFD77C4FBAA04140FDA0B5D831955E7A74521E5576E2780D" },
1415
{ name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" },
1516
{ name = "gleam_javascript", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_javascript", source = "hex", outer_checksum = "14D5B7E1A70681E0776BF0A0357F575B822167960C844D3D3FA114D3A75F05A8" },
16-
{ name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" },
17-
{ name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" },
18-
{ name = "glint", version = "0.18.1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "5FB54D7732B4105E4AF4D89A7EE6D5E8CF33DA13A3575D0C6ECE470B97958454" },
19-
{ name = "p5js_gleam", version = "2.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "p5js_gleam", source = "hex", outer_checksum = "4EEC8FCD162486FCAA2AFEC9E8B7A8843AC9935551CF2B2A604A0F070AB6B00F" },
20-
{ name = "prng", version = "3.0.2", build_tools = ["gleam"], requirements = ["gleam_bitwise", "gleam_stdlib"], otp_app = "prng", source = "hex", outer_checksum = "C61B103F9AF5031ADAA35187CCE7130845EF5088D88FD084E5995D4FBEC9D745" },
17+
{ name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" },
18+
{ name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" },
19+
{ name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" },
20+
{ name = "glint", version = "1.0.0-rc1", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "91EC8EFA3E8FBCB842C219AA02E8072204CEE02597B4C36C2ED78AD86DD1B2EC" },
21+
{ name = "p5js_gleam", version = "2.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "p5js_gleam", source = "hex", outer_checksum = "6280E50C5CF893BA84B6A2D82A3EA83BB764EA7F3509CA22BB12326D01283F85" },
22+
{ name = "prng", version = "3.0.3", build_tools = ["gleam"], requirements = ["gleam_bitwise", "gleam_stdlib"], otp_app = "prng", source = "hex", outer_checksum = "53006736FE23A0F61828C95B505193E10905D8DB76E128F1642D3E571E08F589" },
2123
{ name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" },
2224
{ name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" },
2325
{ name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" },
24-
{ name = "startest", version = "0.2.0", build_tools = ["gleam"], requirements = ["argv", "birl", "exception", "gleam_community_ansi", "gleam_erlang", "gleam_javascript", "gleam_stdlib", "glint", "simplifile", "tom"], otp_app = "startest", source = "hex", outer_checksum = "89F8575C91696D1713075F0B850A54160A32580A7CF415E045A0EEAD498AA30D" },
25-
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
26+
{ name = "startest", version = "0.2.1", build_tools = ["gleam"], requirements = ["argv", "bigben", "birl", "exception", "gleam_community_ansi", "gleam_erlang", "gleam_javascript", "gleam_stdlib", "glint", "simplifile", "tom"], otp_app = "startest", source = "hex", outer_checksum = "D87A0C48712EE53878BBC5058FD4E74CD2B766779E6E7F72FC69D472C820C820" },
27+
{ name = "thoas", version = "1.2.0", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "540C8CB7D9257F2AD0A14145DC23560F91ACDCA995F0CCBA779EB33AF5D859D1" },
2628
{ name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" },
2729
]
2830

2931
[requirements]
3032
esgleam = { version = ">= 0.6.0 and < 1.0.0" }
3133
gleam_community_maths = { version = ">= 1.1.0 and < 2.0.0" }
3234
gleam_stdlib = { version = ">= 0.36.0 and < 2.0.0" }
33-
p5js_gleam = { version = ">= 2.1.1 and < 3.0.0"}
35+
p5js_gleam = { version = ">= 2.1.2 and < 3.0.0"}
3436
prng = { version = ">= 3.0.2 and < 4.0.0" }
35-
startest = { version = ">= 0.2.0 and < 1.0.0" }
37+
startest = { version = ">= 0.2.1 and < 1.0.0" }

src/bullet_heck_gleam.gleam

+161-28
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,243 @@
11
import bullet
22
import dungeon
33
import gleam/bool
4+
import gleam/int
45
import gleam/list
5-
import p5js_gleam.{type P5}
6+
import p5js_gleam.{type Assets, type P5}
67
import p5js_gleam/bindings as p5
78
import player
89
import utils
910
import vector
1011

1112
/// Represents the overall game state
1213
type WorldState {
13-
/// State of the world when the game is active
14+
/// The start screen of the game.
15+
StartScreen
16+
/// State of the world when the game is active.
1417
GameRunning(
1518
dungeon: dungeon.Dungeon,
1619
player: player.Player,
1720
bullets: List(bullet.Bullet),
21+
score: Int,
1822
)
19-
GameOver(fell_in_pitch: Bool)
20-
// enemies: List(Enemy),
23+
/// The game over screen when the player has lost.
24+
GameOver(fell_in_pit: Bool, score: Int)
25+
}
26+
27+
fn preload(p: P5) -> Assets {
28+
let minecraftia = p5.load_font(p, "./fonts/Minecraftia-Regular.ttf")
29+
let worksans = p5.load_font(p, "./fonts/WorkSans-Medium.ttf")
30+
31+
p5js_gleam.initialize_assets()
32+
|> p5js_gleam.insert_font("minecraftia", minecraftia)
33+
|> p5js_gleam.insert_font("worksans", worksans)
2134
}
2235

2336
fn setup(p: P5) -> WorldState {
2437
let canvas_size = dungeon.total_size()
2538
p5.create_canvas(p, canvas_size, canvas_size)
26-
let dungeon = dungeon.generate_dungeon()
27-
GameRunning(
28-
dungeon,
29-
player.new_player(vector.Vector(canvas_size /. 2.0, canvas_size /. 2.0, 0.0)),
30-
[],
31-
)
39+
StartScreen
3240
}
3341

34-
fn draw(p: P5, state: WorldState) {
42+
fn draw(p: P5, state: WorldState, assets: Assets) {
43+
let center_text = fn(txt: String) {
44+
let canvas_size = dungeon.total_size()
45+
canvas_size /. 2.0 -. p5.text_width(p, txt) /. 2.0
46+
}
47+
let h1 = 40
48+
let h2 = 30
49+
let h3 = 22
50+
let h4 = 18
51+
let par = 14
52+
let assert Ok(minecraftia) = p5js_gleam.get_font(assets, "minecraftia")
53+
let assert Ok(worksans) = p5js_gleam.get_font(assets, "worksans")
54+
let canvas_size = dungeon.total_size()
55+
3556
p5.background(p, "#000000")
3657
case state {
37-
GameRunning(dungeon, player, bullets) -> {
58+
StartScreen -> {
59+
let title = "BULLET HECK"
60+
let start = "Press 'SPACE' to start"
61+
let ctrl = "Controls"
62+
let ctrl_move = "Use arrow keys or WASD to move"
63+
let ctrl_jump = "Press SPACE to jump"
64+
let ctrl_shoot = "Use mouse to aim, click to shoot"
65+
66+
p
67+
|> p5.fill("#0f0f0f")
68+
|> p5.rect(0.0, 0.0, canvas_size, canvas_size)
69+
|> p5.text_size(h1)
70+
|> p5.fill("#ffffff")
71+
|> p5.text_font(minecraftia)
72+
|> p5.text(title, center_text(title), canvas_size /. 2.0 +. 5.0)
73+
|> p5.text_font(worksans)
74+
|> p5.text_size(h4)
75+
|> p5.text(start, center_text(start), canvas_size /. 2.0 +. 20.0)
76+
// controls
77+
|> p5.fill("#969696")
78+
|> p5.text(ctrl, center_text(ctrl), canvas_size /. 2.0 +. 200.0)
79+
|> p5.text_size(par)
80+
|> p5.text(ctrl_move, center_text(ctrl_move), canvas_size /. 2.0 +. 225.0)
81+
|> p5.text(ctrl_jump, center_text(ctrl_jump), canvas_size /. 2.0 +. 245.0)
82+
|> p5.text(
83+
ctrl_shoot,
84+
center_text(ctrl_shoot),
85+
canvas_size /. 2.0 +. 265.0,
86+
)
87+
}
88+
GameRunning(dungeon, player, bullets, score) -> {
3889
dungeon.draw(p, dungeon)
3990
player.draw(p, player)
4091
list.each(bullets, bullet.draw(p, _))
92+
93+
// Render UI
94+
let hp_x = 22.0
95+
let score_x = canvas_size -. 100.0
96+
4197
p
98+
|> p5.no_stroke()
99+
|> p5.fill("#660000")
100+
|> p5.rect(0.0, 0.0, canvas_size, 36.0)
101+
// draw health bar
102+
|> p5.fill("#28e200")
103+
|> p5.rect(hp_x +. 15.0, 12.0, int.to_float(player.current_health), 10.0)
104+
|> p5.fill("#ffffff")
105+
|> p5.text_size(par)
106+
|> p5.text("HP:", 10.0, hp_x)
107+
// draw score
108+
|> p5.text("Score:", score_x, 22.0)
109+
|> p5.text(int.to_string(score), score_x +. 45.0, 22.0)
42110
}
43-
GameOver(_) -> {
111+
GameOver(fell_in_pit, score) -> {
112+
let canvas_size = dungeon.total_size()
113+
let game_over = "GAME OVER"
114+
let final_score = "Final Score: "
115+
let restart = "Press 'R' to play again"
116+
let score_text = final_score <> int.to_string(score)
117+
let cause_of_death = case fell_in_pit {
118+
True -> "You fell to your death."
119+
False -> "Turns out, red things hurt."
120+
}
121+
44122
p
123+
|> p5.fill("#0f0f0f")
124+
|> p5.rect(0.0, 0.0, canvas_size, canvas_size)
125+
|> p5.fill("#e20000")
126+
|> p5.text_size(h2)
127+
|> p5.text_font(minecraftia)
128+
|> p5.text(game_over, center_text(game_over), canvas_size /. 2.0 -. 25.0)
129+
|> p5.text_size(h3)
130+
|> p5.text_font(worksans)
131+
|> p5.text(
132+
cause_of_death,
133+
center_text(cause_of_death),
134+
canvas_size /. 2.0 -. 15.0,
135+
)
136+
|> p5.fill("#ffffff")
137+
|> p5.text(
138+
score_text,
139+
center_text(score_text),
140+
canvas_size /. 2.0 +. 45.0,
141+
)
142+
|> p5.text_size(h4)
143+
|> p5.text(restart, center_text(restart), canvas_size /. 2.0 +. 70.0)
45144
}
46145
}
47146
}
48147

49148
fn on_key_pressed(key: String, _: Int, state: WorldState) -> WorldState {
50149
case key, state {
51-
" ", GameRunning(dungeon, player, bullets) ->
150+
"r", _ -> StartScreen
151+
" ", StartScreen -> {
152+
let canvas_size = dungeon.total_size()
153+
let dungeon = dungeon.generate_dungeon()
154+
GameRunning(
155+
dungeon,
156+
player.new_player(vector.Vector(
157+
canvas_size /. 2.0,
158+
canvas_size /. 2.0,
159+
0.0,
160+
)),
161+
[],
162+
0,
163+
)
164+
}
165+
" ", GameRunning(dungeon, player, bullets, score) ->
52166
GameRunning(
53167
dungeon: dungeon,
54168
bullets: bullets,
55169
player: player.jump(player),
170+
score: score,
56171
)
57-
"w", GameRunning(dungeon, player, bullets) ->
172+
"w", GameRunning(dungeon, player, bullets, score) ->
58173
GameRunning(
59174
dungeon: dungeon,
60175
bullets: bullets,
61176
player: player.accelerate_y(player, False),
177+
score: score,
62178
)
63-
"s", GameRunning(dungeon, player, bullets) ->
179+
"s", GameRunning(dungeon, player, bullets, score) ->
64180
GameRunning(
65181
dungeon: dungeon,
66182
bullets: bullets,
67183
player: player.accelerate_y(player, True),
184+
score: score,
68185
)
69-
"a", GameRunning(dungeon, player, bullets) ->
186+
"a", GameRunning(dungeon, player, bullets, score) ->
70187
GameRunning(
71188
dungeon: dungeon,
72189
bullets: bullets,
73190
player: player.accelerate_x(player, False),
191+
score: score,
74192
)
75-
"d", GameRunning(dungeon, player, bullets) ->
193+
"d", GameRunning(dungeon, player, bullets, score) ->
76194
GameRunning(
77195
dungeon: dungeon,
78196
bullets: bullets,
79197
player: player.accelerate_x(player, True),
198+
score: score,
80199
)
81200
_, _ -> state
82201
}
83202
}
84203

85204
fn on_key_released(key: String, _: Int, state: WorldState) -> WorldState {
86205
case key, state {
87-
"w", GameRunning(dungeon, player, bullets) ->
206+
"w", GameRunning(dungeon, player, bullets, score) ->
88207
GameRunning(
89208
dungeon: dungeon,
90209
bullets: bullets,
91210
player: player.stop_y(player),
211+
score: score,
92212
)
93-
"s", GameRunning(dungeon, player, bullets) ->
213+
"s", GameRunning(dungeon, player, bullets, score) ->
94214
GameRunning(
95215
dungeon: dungeon,
96216
bullets: bullets,
97217
player: player.stop_y(player),
218+
score: score,
98219
)
99-
"a", GameRunning(dungeon, player, bullets) ->
220+
"a", GameRunning(dungeon, player, bullets, score) ->
100221
GameRunning(
101222
dungeon: dungeon,
102223
bullets: bullets,
103224
player: player.stop_x(player),
225+
score: score,
104226
)
105-
"d", GameRunning(dungeon, player, bullets) ->
227+
"d", GameRunning(dungeon, player, bullets, score) ->
106228
GameRunning(
107229
dungeon: dungeon,
108230
bullets: bullets,
109231
player: player.stop_x(player),
232+
score: score,
110233
)
111234
_, _ -> state
112235
}
113236
}
114237

115238
fn on_mouse_clicked(x: Float, y: Float, state: WorldState) -> WorldState {
116239
case state {
117-
GameRunning(dungeon, player, bullets) -> {
240+
GameRunning(dungeon, player, bullets, score) -> {
118241
use <- bool.guard(!player.can_player_fire(player), state)
119242

120243
let firing_direction =
@@ -137,6 +260,7 @@ fn on_mouse_clicked(x: Float, y: Float, state: WorldState) -> WorldState {
137260
..player,
138261
last_fire_time: utils.now_in_milliseconds(),
139262
),
263+
score: score,
140264
)
141265
}
142266
_ -> state
@@ -145,7 +269,7 @@ fn on_mouse_clicked(x: Float, y: Float, state: WorldState) -> WorldState {
145269

146270
fn on_tick(state: WorldState) -> WorldState {
147271
case state {
148-
GameRunning(dungeon, player, bullets) -> {
272+
GameRunning(dungeon, player, bullets, score) -> {
149273
// Attempt to move player
150274
let old_position = player.position
151275
let moved = player.move(player)
@@ -166,9 +290,9 @@ fn on_tick(state: WorldState) -> WorldState {
166290
}
167291

168292
use <- bool.guard(
169-
player.position.z <. 0.0
293+
player.position.z <=. 0.0
170294
&& dungeon.is_over_pit(dungeon, player.position),
171-
GameOver(True),
295+
GameOver(True, score),
172296
)
173297

174298
let player = player.update_velocity(player)
@@ -203,14 +327,23 @@ fn on_tick(state: WorldState) -> WorldState {
203327
#([bullet.advance_bullet(b), ..bullets], player)
204328
})
205329

206-
GameRunning(dungeon: dungeon, player: player, bullets: bullets)
330+
GameRunning(
331+
dungeon: dungeon,
332+
player: player,
333+
bullets: bullets,
334+
score: score,
335+
)
207336
}
208337
_ -> state
209338
}
210339
}
211340

212341
pub fn main() {
213-
p5js_gleam.create_sketch(init: setup, draw: draw)
342+
p5js_gleam.create_sketch_with_preloading(
343+
init: setup,
344+
draw: draw,
345+
preload: preload,
346+
)
214347
|> p5js_gleam.set_on_key_pressed(on_key_pressed)
215348
|> p5js_gleam.set_on_key_released(on_key_released)
216349
|> p5js_gleam.set_on_mouse_clicked(on_mouse_clicked)

0 commit comments

Comments
 (0)