aboutsummaryrefslogtreecommitdiff
path: root/examples/game/world.tm
blob: e8255ab87ff97d746767f5e4f3666ee0e000bf31 (plain)
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
# 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