-
Notifications
You must be signed in to change notification settings - Fork 83
/
Copy pathlevel.go
126 lines (113 loc) · 3 KB
/
level.go
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
package termloop
// Level interface represents a Drawable with a separate background
// that is drawn first. It can also contain Drawables of its own.
type Level interface {
DrawBackground(*Screen)
AddEntity(Drawable)
RemoveEntity(Drawable)
Draw(*Screen)
Tick(Event)
}
// BaseLevel type represents a Level with a background defined as a Cell,
// which is tiled. The background is drawn first, then all Entities.
type BaseLevel struct {
Entities []Drawable
bg Cell
offsetx int
offsety int
}
// NewBaseLevel creates a new BaseLevel with background bg.
// Returns a pointer to the new BaseLevel.
func NewBaseLevel(bg Cell) *BaseLevel {
level := BaseLevel{Entities: make([]Drawable, 0), bg: bg}
return &level
}
// Tick handles any collisions between Physicals in the level's entities,
// and processes any input.
func (l *BaseLevel) Tick(ev Event) {
// Handle input
for _, e := range l.Entities {
e.Tick(ev)
}
// Handle collisions
colls := make([]Physical, 0)
dynamics := make([]DynamicPhysical, 0)
for _, e := range l.Entities {
if p, ok := interface{}(e).(Physical); ok {
colls = append(colls, p)
}
if p, ok := interface{}(e).(DynamicPhysical); ok {
dynamics = append(dynamics, p)
}
}
jobs := make(chan DynamicPhysical, len(dynamics))
results := make(chan int, len(dynamics))
for w := 0; w <= len(dynamics)/3; w++ {
go checkCollisionsWorker(colls, jobs, results)
}
for _, p := range dynamics {
jobs <- p
}
close(jobs)
for r := 0; r < len(dynamics); r++ {
<-results
}
}
// DrawBackground draws the background Cell bg to each Cell of the Screen s.
func (l *BaseLevel) DrawBackground(s *Screen) {
for i, row := range s.canvas {
for j := range row {
s.canvas[i][j] = l.bg
}
}
}
// Draw draws the level's entities to the Screen s.
func (l *BaseLevel) Draw(s *Screen) {
offx, offy := s.offset()
s.setOffset(l.offsetx, l.offsety)
for _, e := range l.Entities {
e.Draw(s)
}
s.setOffset(offx, offy)
}
// AddEntity adds Drawable d to the level's entities.
func (l *BaseLevel) AddEntity(d Drawable) {
l.Entities = append(l.Entities, d)
}
// RemoveEntity removes Drawable d from the level's entities.
func (l *BaseLevel) RemoveEntity(d Drawable) {
for i, elem := range l.Entities {
if elem == d {
l.Entities = append(l.Entities[:i], l.Entities[i+1:]...)
return
}
}
}
// Offset returns the level's drawing offset.
func (l *BaseLevel) Offset() (int, int) {
return l.offsetx, l.offsety
}
// SetOffset sets the level's drawing offset to be (x, y).
// The drawing offset can be used to simulate moving the level, or
// moving the 'camera'.
func (l *BaseLevel) SetOffset(x, y int) {
l.offsetx, l.offsety = x, y
}
func checkCollisionsWorker(ps []Physical, jobs <-chan DynamicPhysical, results chan<- int) {
for p := range jobs {
for _, c := range ps {
if c == p {
continue
}
px, py := p.Position()
cx, cy := c.Position()
pw, ph := p.Size()
cw, ch := c.Size()
if px < cx+cw && px+pw > cx &&
py < cy+ch && py+ph > cy {
p.Collide(c)
}
}
results <- 1
}
}