summaryrefslogtreecommitdiff
path: root/internal/pacman/pacman.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/pacman/pacman.go')
-rw-r--r--internal/pacman/pacman.go152
1 files changed, 152 insertions, 0 deletions
diff --git a/internal/pacman/pacman.go b/internal/pacman/pacman.go
new file mode 100644
index 0000000..cb663af
--- /dev/null
+++ b/internal/pacman/pacman.go
@@ -0,0 +1,152 @@
+package pacman
+
+import (
+ "time"
+
+ "github.com/ChausseBenjamin/pacgo/internal/render"
+)
+
+type Direction uint8
+
+const (
+ UP Direction = iota
+ DOWN
+ LEFT
+ RIGHT
+)
+
+type Pacman struct {
+ renderer *render.Renderer
+
+ bright bool
+ x float64
+ y float64
+ dir Direction
+ refreshRate int // times/second the position is updated
+
+ vSpeed float64 // tiles per second
+ hSpeed float64 // tiles per second
+ moveTicker *time.Ticker
+ moveDone chan bool
+
+ blinkRate float64 // stateChanges per second
+ blinkTicker *time.Ticker
+ blinkDone chan bool
+}
+
+func (p *Pacman) blink() {
+ p.bright = !p.bright
+}
+
+func (p *Pacman) drawInstruction() render.DrawInstruction {
+ return render.DrawInstruction{
+ X: int(p.x),
+ Y: int(p.y),
+ Content: p.Icon(),
+ }
+}
+
+// clear will remove the pacman from the screen. This is useful in two cases:
+// - Remove pacman's trail/previous position
+// - Remove pacman from the screen on death/level change/etc.
+// This function will not update pacman's position. This means it must be
+// called before updating the position.
+func (p *Pacman) clearInstruction() render.ClearInstruction {
+ return render.ClearInstruction{
+ X: int(p.x),
+ Y: int(p.y),
+ Size: 1,
+ }
+}
+
+// move will update pacman's position constantly
+// based on the direction it is facing.
+func (p *Pacman) move() {
+ p.renderer.Push(p.clearInstruction())
+ switch p.dir {
+ case UP:
+ p.y -= (float64(p.vSpeed) * float64(p.refreshRate)) / 1000
+ case DOWN:
+ p.y += (float64(p.vSpeed) * float64(p.refreshRate)) / 1000
+ case LEFT:
+ p.x -= (float64(p.hSpeed) * float64(p.refreshRate)) / 1000
+ case RIGHT:
+ p.x += (float64(p.hSpeed) * float64(p.refreshRate)) / 1000
+ }
+ p.renderer.Push(p.drawInstruction())
+}
+
+func (p *Pacman) Pos() (float64, float64) {
+ return p.x, p.y
+}
+
+func (p *Pacman) Redirect(dir Direction) {
+ p.dir = dir
+}
+
+func (p *Pacman) Icon() string {
+ icns := map[Direction]map[bool]string{
+ UP: {true: "", false: "󰬧"},
+ DOWN: {true: "", false: "󰬭"},
+ LEFT: {true: "", false: "󰬫"},
+ RIGHT: {true: "", false: "󰬩"},
+ }
+
+ return icns[p.dir][p.bright]
+}
+
+func (p *Pacman) Start() {
+ p.blinkDone = make(chan bool)
+ p.moveDone = make(chan bool)
+ // fmt.Println(time.Duration(1/p.blinkRate) * time.Second)
+ blinkTicker := time.NewTicker(time.Duration(float64(time.Second) / p.blinkRate))
+ moveTicker := time.NewTicker(time.Duration(float64(time.Second) / float64(p.refreshRate)))
+
+ go func() {
+ for {
+ select {
+ case <-blinkTicker.C:
+ p.blink()
+ case <-moveTicker.C:
+ p.move()
+ case <-p.blinkDone:
+ return
+ case <-p.moveDone:
+ return
+ }
+ }
+ }()
+}
+
+func (p *Pacman) Stop() {
+ p.blinkTicker.Stop()
+ p.moveTicker.Stop()
+ p.blinkDone <- true
+ p.moveDone <- true
+}
+
+func NewPacman(x float64, y float64, rdr *render.Renderer) *Pacman {
+ p := &Pacman{x: x, y: y}
+ p.dir = RIGHT
+ p.refreshRate = 200
+ p.vSpeed = 0.1
+ p.hSpeed = 0.2
+ p.blinkRate = 3
+ p.renderer = rdr
+ go p.blink()
+ go p.move()
+ return p
+}
+
+// // Icons
+// pub const PACMAN_UP_ON :char = '';
+// pub const PACMAN_DOWN_ON :char = '';
+// pub const PACMAN_LEFT_ON :char = '';
+// pub const PACMAN_RIGHT_ON :char = '';
+// pub const GHOST_ON :char = '󰊠';
+
+// pub const PACMAN_UP_OFF :char = '󰬧';
+// pub const PACMAN_DOWN_OFF :char = '󰬭';
+// pub const PACMAN_LEFT_OFF :char = '󰬩';
+// pub const PACMAN_RIGHT_OFF :char = '󰬫';
+// pub const GHOST_OFF :char = '󱙝';