-
Notifications
You must be signed in to change notification settings - Fork 8
/
main.go
158 lines (132 loc) · 3.35 KB
/
main.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//go:build example
package main
import (
_ "embed"
"encoding/json"
"fmt"
"log"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
input "github.com/quasilyte/ebitengine-input"
)
// Here is a basic algorithm to load a keymap from a file:
//
// 1. Store an action=>[]keyname mapping somewhere in a file;
//
// 2. When initializing an input.Keymap, you need to associate
// an action string key with an actual input.Action constant;
//
// 3. Map keyname to input.Key, this can be done by using input.ParseKey function.
//
// Only the 2nd step requires some extra efforts.
// Since input.Action is an external type, you can't use a stringer tool to
// generate the string mappings. You can try using some other tool to do that.
// Or you can write the mapping manually (see actionString).
//
// When you have an action=>actionname mapping, it's easy to build a
// reverse index for the second step. A special sentinel value like actionLast
// can be useful (see the code below).
const (
ActionUnknown input.Action = iota
ActionLeft
ActionRight
ActionPause
ActionRestart
ActionSecret
actionLast
)
func actionString(a input.Action) string {
// This is the only function we have to implement.
// Write it manually or use the tools to generate it (not stringer though).
switch a {
case ActionLeft:
return "Left"
case ActionRight:
return "Right"
case ActionPause:
return "Pause"
case ActionRestart:
return "Restart"
case ActionSecret:
return "Secret"
default:
return "?"
}
}
//go:embed keymap.json
var keymapConfigData []byte
func main() {
ebiten.SetWindowSize(640, 480)
if err := ebiten.RunGame(newExampleGame()); err != nil {
log.Fatal(err)
}
}
type exampleGame struct {
started bool
lastActionPressed string
inputHandler *input.Handler
inputSystem input.System
}
func newExampleGame() *exampleGame {
g := &exampleGame{}
g.inputSystem.Init(input.SystemConfig{
DevicesEnabled: input.AnyDevice,
})
return g
}
func (g *exampleGame) Layout(_, _ int) (int, int) {
return 640, 480
}
func (g *exampleGame) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrint(screen, "last pressed action: "+g.lastActionPressed)
}
func (g *exampleGame) Update() error {
g.inputSystem.Update()
if !g.started {
g.Init()
g.started = true
}
actions := [...]input.Action{
ActionLeft,
ActionRight,
ActionPause,
ActionRestart,
ActionSecret,
}
for _, a := range actions {
if g.inputHandler.ActionIsJustPressed(a) {
g.lastActionPressed = actionString(a)
break
}
}
return nil
}
func (g *exampleGame) Init() {
var keymapConfig map[string][]string
if err := json.Unmarshal(keymapConfigData, &keymapConfig); err != nil {
panic(err)
}
// Build a reverse index to get an action ID by its name.
actionNameToID := map[string]input.Action{}
for a := ActionUnknown; a < actionLast; a++ {
actionNameToID[actionString(a)] = a
}
// Parse our config file into a keymap object.
keymap := input.Keymap{}
for actionName, keyNames := range keymapConfig {
a, ok := actionNameToID[actionName]
if !ok {
panic(fmt.Sprintf("unexpected action name: %s", actionName))
}
keys := make([]input.Key, len(keyNames))
for i, keyString := range keyNames {
k, err := input.ParseKey(keyString)
if err != nil {
panic(err)
}
keys[i] = k
}
keymap[a] = keys
}
g.inputHandler = g.inputSystem.NewHandler(0, keymap)
}