aboutsummaryrefslogtreecommitdiff
path: root/examples/game
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-09-01 16:44:58 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-09-01 16:44:58 -0400
commited50c5fefb8892ad2ba5262491669f268ddbd436 (patch)
treee93a6a8b7e963c37a001691751d6845d10e0cbf8 /examples/game
parent02a99d24a310c04622a875dcf4b0c6fd2de71332 (diff)
Overhaul code to stop keeping examples and libraries in the same repo,
but instead spin each out into its own repo.
Diffstat (limited to 'examples/game')
-rw-r--r--examples/game/CHANGES.md5
-rw-r--r--examples/game/Makefile17
-rw-r--r--examples/game/README.md13
-rw-r--r--examples/game/box.tm7
-rw-r--r--examples/game/game.tm29
-rw-r--r--examples/game/map.txt18
-rw-r--r--examples/game/player.tm28
-rw-r--r--examples/game/raylib.tm63
-rw-r--r--examples/game/world.tm88
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
-