feat: add basic state machine implementation
This commit is contained in:
parent
ceb4cfad40
commit
75b4981566
3 changed files with 82 additions and 0 deletions
8
game/state/handler.go
Normal file
8
game/state/handler.go
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
type Handler interface {
|
||||||
|
Enter()
|
||||||
|
Exit()
|
||||||
|
Update(transitioner Transitioner, delta float32)
|
||||||
|
Render()
|
||||||
|
}
|
||||||
68
game/state/machine/machine.go
Normal file
68
game/state/machine/machine.go
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "tetris/game/state"
|
||||||
|
|
||||||
|
type Machine struct {
|
||||||
|
current state.Handler
|
||||||
|
pending string
|
||||||
|
registry map[string]state.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates an empty machine.
|
||||||
|
func New() *Machine {
|
||||||
|
return &Machine{registry: make(map[string]state.Handler)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register binds a name to a factory that returns a fresh state.Handler.
|
||||||
|
func (m *Machine) Register(name string, handler state.Handler) {
|
||||||
|
m.registry[name] = handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start switches to the named initial state immediately (calls Enter()).
|
||||||
|
func (m *Machine) Start(name string) {
|
||||||
|
m.switchNow(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Switch queues a transition to be applied after the current Update finishes.
|
||||||
|
func (m *Machine) Switch(name string) {
|
||||||
|
if name == "" || name == m.pending {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.pending = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update ticks the current state, then applies any queued transition.
|
||||||
|
func (m *Machine) Update(delta float32) {
|
||||||
|
if m.current == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.current.Update(m, delta)
|
||||||
|
|
||||||
|
if m.pending != "" {
|
||||||
|
next := m.pending
|
||||||
|
m.pending = ""
|
||||||
|
m.switchNow(next)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render proxies to current state.
|
||||||
|
func (m *Machine) Render() {
|
||||||
|
if m.current != nil {
|
||||||
|
m.current.Render()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Machine) switchNow(name string) {
|
||||||
|
handler, ok := m.registry[name]
|
||||||
|
if !ok {
|
||||||
|
// Unknown state: dont switch.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.current != nil {
|
||||||
|
m.current.Exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
m.current = handler
|
||||||
|
m.current.Enter()
|
||||||
|
}
|
||||||
6
game/state/transitioner.go
Normal file
6
game/state/transitioner.go
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
package state
|
||||||
|
|
||||||
|
// Transitioner is the only thing a state needs to know about the machine.
|
||||||
|
type Transitioner interface {
|
||||||
|
Switch(name string) // request transition by state name
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue