diff options
| author | Bruce Hill <bruce@bruce-hill.com> | 2025-09-01 17:37:24 -0400 |
|---|---|---|
| committer | Bruce Hill <bruce@bruce-hill.com> | 2025-09-01 17:37:24 -0400 |
| commit | 12345a85d9c7d7a56ddf323247a4bdf347021b73 (patch) | |
| tree | 93bafb42c1ec2c22cc2858936034901c39cbca82 /examples/game | |
| parent | c778c8822f1c8acf981e26f7b860a384c94cff6f (diff) | |
| parent | adc2d81b5683e611c5f3289be6157d4519a60632 (diff) | |
Merge branch 'main' into optional-list-indexing
Diffstat (limited to 'examples/game')
| -rw-r--r-- | examples/game/CHANGES.md | 5 | ||||
| -rw-r--r-- | examples/game/Makefile | 17 | ||||
| -rw-r--r-- | examples/game/README.md | 13 | ||||
| -rw-r--r-- | examples/game/box.tm | 7 | ||||
| -rw-r--r-- | examples/game/game.tm | 29 | ||||
| -rw-r--r-- | examples/game/map.txt | 18 | ||||
| -rw-r--r-- | examples/game/player.tm | 28 | ||||
| -rw-r--r-- | examples/game/raylib.tm | 63 | ||||
| -rw-r--r-- | examples/game/world.tm | 88 |
9 files changed, 0 insertions, 268 deletions
diff --git a/examples/game/CHANGES.md b/examples/game/CHANGES.md deleted file mode 100644 index 42ae752c..00000000 --- a/examples/game/CHANGES.md +++ /dev/null @@ -1,5 +0,0 @@ -# Version History - -## v1.0 - -Initial version diff --git a/examples/game/Makefile b/examples/game/Makefile deleted file mode 100644 index 7cf46ce6..00000000 --- a/examples/game/Makefile +++ /dev/null @@ -1,17 +0,0 @@ - - -game: game.tm box.tm color.tm player.tm world.tm - tomo -e game.tm - -# Disable built-in makefile rules: -%: %.c -%.o: %.c -%: %.o - -clean: - rm -vf game *.tm.* - -play: game - ./game - -.PHONY: play, clean diff --git a/examples/game/README.md b/examples/game/README.md deleted file mode 100644 index 475a8299..00000000 --- a/examples/game/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Example Game - -This is a simple example game that uses [raylib](https://www.raylib.com/) to -demonstrate a project that spans multiple files and showcases some game -programming concepts used in idiomatic Tomo code. It also showcases how to -interact with an external C library. To run the game: - -```bash -tomo game.tm -``` - -An example [Makefile](Makefile) is also provided if you want to use `make` to -build the game and `make clean` to clean up the built files. diff --git a/examples/game/box.tm b/examples/game/box.tm deleted file mode 100644 index 41ae10e5..00000000 --- a/examples/game/box.tm +++ /dev/null @@ -1,7 +0,0 @@ -# Defines a struct representing boxes on the terrain -use ./world.tm -use ./raylib.tm - -struct Box(pos:Vector2, size=Vector2(50, 50), color=Color(0x80,0x80,0x80)) - func draw(b:Box) - DrawRectangleV(b.pos, b.size, b.color) diff --git a/examples/game/game.tm b/examples/game/game.tm deleted file mode 100644 index f82e4f40..00000000 --- a/examples/game/game.tm +++ /dev/null @@ -1,29 +0,0 @@ -# This game demo uses Raylib to present a simple maze-type game -use ./raylib.tm -use ./world.tm - -func main(map=(./map.txt)) - InitWindow(1600, 900, CString("raylib [core] example - 2d camera")) - - map_contents := map.read() or exit("Could not find the game map: $map") - - world := @World( - player=@Player(Vector2(0,0), Vector2(0,0)), - goal=@Box(Vector2(0,0), Vector2(50,50), color=Color(0x10,0xa0,0x10)), - boxes=@[], - ) - world.load_map(map_contents) - - SetTargetFPS(60) - - while not WindowShouldClose() - dt := GetFrameTime() - world.update(dt) - - BeginDrawing() - ClearBackground(Color(0xCC, 0xCC, 0xCC, 0xFF)) - world.draw() - EndDrawing() - - CloseWindow() - diff --git a/examples/game/map.txt b/examples/game/map.txt deleted file mode 100644 index 46fccd09..00000000 --- a/examples/game/map.txt +++ /dev/null @@ -1,18 +0,0 @@ -################################ -#@ # # # -# #### #### # # #### ##### -# # # # # # -# ####### # ####### # # ### -# # # # # # # -# #### ########## # #### # -# # # # # # # -#### # # # # # # # # ## -# # # # # # # # -####### ########## # ######## -# # # # # -# ########## #### # # # # -# # # # # # # # # -# ####### # # ########## # -# # # # # # # ? # -# # # # # # # -################################ diff --git a/examples/game/player.tm b/examples/game/player.tm deleted file mode 100644 index 2e5e54f6..00000000 --- a/examples/game/player.tm +++ /dev/null @@ -1,28 +0,0 @@ -# Defines a struct representing the player, which is controlled by WASD keys -use ./world.tm -use ./raylib.tm - -struct Player(pos,prev_pos:Vector2) - WALK_SPEED := Num32(500.) - ACCEL := Num32(0.3) - FRICTION := Num32(0.99) - SIZE := Vector2(30, 30) - COLOR := Color(0x60, 0x60, 0xbF) - - func update(p:@Player) - target_x := C_code:Num32( - (Num32_t)((IsKeyDown(KEY_A) ? -1 : 0) + (IsKeyDown(KEY_D) ? 1 : 0)) - ) - target_y := C_code:Num32( - (Num32_t)((IsKeyDown(KEY_W) ? -1 : 0) + (IsKeyDown(KEY_S) ? 1 : 0)) - ) - target_vel := Vector2(target_x, target_y).norm() * Player.WALK_SPEED - - vel := (p.pos - p.prev_pos)/World.DT - vel *= Player.FRICTION - vel = vel.mix(target_vel, Player.ACCEL) - - p.prev_pos, p.pos = p.pos, p.pos + World.DT*vel - - func draw(p:Player) - DrawRectangleV(p.pos, Player.SIZE, Player.COLOR) diff --git a/examples/game/raylib.tm b/examples/game/raylib.tm deleted file mode 100644 index b2ba53d7..00000000 --- a/examples/game/raylib.tm +++ /dev/null @@ -1,63 +0,0 @@ -# Raylib wrapper for some functions and structs -use -lraylib -use <raylib.h> -use <raymath.h> - -struct Color(r,g,b:Byte,a=Byte(255); extern) -struct Rectangle(x,y,width,height:Num32; extern) - func draw(r:Rectangle, color:Color) - DrawRectangleRec(r, color) - -struct Vector2(x,y:Num32; extern) - ZERO := Vector2(0, 0) - func plus(a,b:Vector2->Vector2; inline) - return Vector2(a.x+b.x, a.y+b.y) - func minus(a,b:Vector2->Vector2; inline) - return Vector2(a.x-b.x, a.y-b.y) - func times(a,b:Vector2->Vector2; inline) - return Vector2(a.x*b.x, a.y*b.y) - func negative(v:Vector2->Vector2; inline) - return Vector2(-v.x, -v.y) - func dot(a,b:Vector2->Num32; inline) - return ((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)) - func cross(a,b:Vector2->Num32; inline) - return a.x*b.y - a.y*b.x - func scaled_by(v:Vector2, k:Num32->Vector2; inline) - return Vector2(v.x*k, v.y*k) - func divided_by(v:Vector2, divisor:Num32->Vector2; inline) - return Vector2(v.x/divisor, v.y/divisor) - func length(v:Vector2->Num32; inline) - return (v.x*v.x + v.y*v.y).sqrt() - func dist(a,b:Vector2->Num32; inline) - return a.minus(b).length() - func angle(v:Vector2->Num32; inline) - return Num32.atan2(v.y, v.x) - func norm(v:Vector2->Vector2; inline) - if v.x == 0 and v.y == 0 - return v - len := v.length() - return Vector2(v.x/len, v.y/len) - func rotated(v:Vector2, radians:Num32 -> Vector2) - cos := radians.cos() or return v - sin := radians.sin() or return v - return Vector2(cos*v.x - sin*v.y, sin*v.x + cos*v.y) - func mix(a,b:Vector2, amount:Num32 -> Vector2) - return Vector2( - amount.mix(a.x, b.x), - amount.mix(a.y, b.y), - ) - -extern InitWindow : func(width:Int32, height:Int32, title:CString) -extern SetTargetFPS : func(fps:Int32) -extern WindowShouldClose : func(->Bool) -extern GetFrameTime : func(->Num32) -extern BeginDrawing : func() -extern EndDrawing : func() -extern CloseWindow : func() -extern ClearBackground : func(color:Color) -extern DrawRectangle : func(x,y,width,height:Int32, color:Color) -extern DrawRectangleRec : func(rec:Rectangle, color:Color) -extern DrawRectangleV : func(pos:Vector2, size:Vector2, color:Color) -extern DrawText : func(text:CString, x,y:Int32, text_height:Int32, color:Color) -extern GetScreenWidth : func(->Int32) -extern GetScreenHeight : func(->Int32) diff --git a/examples/game/world.tm b/examples/game/world.tm deleted file mode 100644 index 0de8ea4b..00000000 --- a/examples/game/world.tm +++ /dev/null @@ -1,88 +0,0 @@ -# This file defines a World object for keeping track of everything, as well -# as the collision logic. -use ./player.tm -use ./raylib.tm -use ./box.tm - -# Return a displacement relative to `a` that will push it out of `b` -func solve_overlap(a_pos:Vector2, a_size:Vector2, b_pos:Vector2, b_size:Vector2 -> Vector2) - a_left := a_pos.x - a_right := a_pos.x + a_size.x - a_top := a_pos.y - a_bottom := a_pos.y + a_size.y - - b_left := b_pos.x - b_right := b_pos.x + b_size.x - b_top := b_pos.y - b_bottom := b_pos.y + b_size.y - - # Calculate the overlap in each dimension - overlap_x := (a_right _min_ b_right) - (a_left _max_ b_left) - overlap_y := (a_bottom _min_ b_bottom) - (a_top _max_ b_top) - - # If either axis is not overlapping, then there is no collision: - if overlap_x <= 0 or overlap_y <= 0 - return Vector2(0, 0) - - if overlap_x < overlap_y - if a_right > b_left and a_right < b_right - return Vector2(-(overlap_x), 0) - else if a_left < b_right and a_left > b_left - return Vector2(overlap_x, 0) - else - if a_top < b_bottom and a_top > b_top - return Vector2(0, overlap_y) - else if a_bottom > b_top and a_bottom < b_bottom - return Vector2(0, -overlap_y) - - return Vector2(0, 0) - -struct World(player:@Player, goal:@Box, boxes:@[@Box], dt_accum=Num32(0.0), won=no) - DT := (Num32(1.)/Num32(60.)) - STIFFNESS := Num32(0.3) - - func update(w:@World, dt:Num32) - w.dt_accum += dt - while w.dt_accum > 0 - w.update_once() - w.dt_accum -= World.DT - - func update_once(w:@World) - w.player.update() - - if solve_overlap(w.player.pos, Player.SIZE, w.goal.pos, w.goal.size) != Vector2(0,0) - w.won = yes - - # Resolve player overlapping with any boxes: - for i in 3 - for b in w.boxes - w.player.pos += World.STIFFNESS * solve_overlap(w.player.pos, Player.SIZE, b.pos, b.size) - - func draw(w:@World) - for b in w.boxes - b.draw() - w.goal.draw() - w.player.draw() - - if w.won - DrawText(CString("WINNER"), GetScreenWidth()/Int32(2)-Int32(48*3), GetScreenHeight()/Int32(2)-Int32(24), 48, Color(0,0,0)) - - func load_map(w:@World, map:Text) - if map.has("[]") - map = map.translate({"[]"="#", "@ "="@", " "=" "}) - w.boxes = @[] - box_size := Vector2(50., 50.) - for y,line in map.lines() - for x,cell in line.split() - if cell == "#" - pos := Vector2((Num32(x)-1) * box_size.x, (Num32(y)-1) * box_size.y) - box := @Box(pos, size=box_size, color=Color(0x80,0x80,0x80)) - w.boxes.insert(box) - else if cell == "@" - pos := Vector2((Num32(x)-1) * box_size.x, (Num32(y)-1) * box_size.y) - pos += box_size/Num32(2) - Player.SIZE/Num32(2) - w.player = @Player(pos,pos) - else if cell == "?" - pos := Vector2((Num32(x)-1) * box_size.x, (Num32(y)-1) * box_size.y) - w.goal.pos = pos - |
