forked from x-hgg-x/goecsengine
/
controls.go
161 lines (137 loc) · 4.05 KB
/
controls.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
159
160
161
package resources
import (
"fmt"
"reflect"
"github.com/ghtalpo/goecsengine/utils"
"github.com/hajimehoshi/ebiten/v2"
"github.com/pelletier/go-toml"
)
// Key is a US keyboard key
type Key struct {
Key ebiten.Key
}
// UnmarshalText fills structure fields from text data
func (k *Key) UnmarshalText(text []byte) error {
if key, ok := utils.KeyMap[string(text)]; ok {
k.Key = key
return nil
}
return fmt.Errorf("unknown key: '%s'", string(text))
}
// MouseButton is a mouse button
type MouseButton struct {
MouseButton ebiten.MouseButton
}
// UnmarshalText fills structure fields from text data
func (b *MouseButton) UnmarshalText(text []byte) error {
if mouseButton, ok := utils.MouseButtonMap[string(text)]; ok {
b.MouseButton = mouseButton
return nil
}
return fmt.Errorf("unknown mouse button: '%s'", string(text))
}
// ControllerButton is a gamepad button
type ControllerButton struct {
ID ebiten.GamepadID
GamepadButton ebiten.GamepadButton
}
// UnmarshalTOML fills structure fields from TOML data
func (b *ControllerButton) UnmarshalTOML(i interface{}) error {
data := i.(map[string]interface{})
if gamepadButton, ok := utils.GamepadButtonMap[data["button"].(string)]; ok {
b.ID = ebiten.GamepadID(data["id"].(int64))
b.GamepadButton = gamepadButton
return nil
}
return fmt.Errorf("unknown gamepad button: '%s'", data["button"].(string))
}
type button struct {
Key *Key
MouseButton *MouseButton `toml:"mouse_button"`
ControllerButton *ControllerButton `toml:"controller"`
}
// Button can be a US keyboard key, a mouse button or a gamepad button
type Button struct {
Value interface{}
}
// UnmarshalTOML fills structure fields from TOML data
func (b *Button) UnmarshalTOML(i interface{}) error {
var err error
b.Value, err = getInterfaceValue(i, &button{})
return err
}
// Emulated is an emulated axis
type Emulated struct {
Pos Button
Neg Button
}
// ControllerAxis is a gamepad axis
type ControllerAxis struct {
ID ebiten.GamepadID
Axis int
Invert bool
DeadZone float64 `toml:"dead_zone"`
}
// MouseAxis is a mouse axis
type MouseAxis struct {
Axis int
}
type axis struct {
Emulated *Emulated
ControllerAxis *ControllerAxis `toml:"controller_axis"`
MouseAxis *MouseAxis `toml:"mouse_axis"`
}
// Axis can be an emulated axis, a gamepad axis or a mouse axis
type Axis struct {
Value interface{}
}
// UnmarshalTOML fills structure fields from TOML data
func (a *Axis) UnmarshalTOML(i interface{}) error {
var err error
a.Value, err = getInterfaceValue(i, &axis{})
return err
}
// Action contains buttons combinations with settings
type Action struct {
// Combinations contains buttons combinations
Combinations [][]Button
// Once determines if the action should be triggered every frame when the button is pressed (default) or only once
Once bool
}
// Controls contains input controls
type Controls struct {
// Axes contains axis controls, used for inputs represented by a float value from -1 to 1
Axes map[string]Axis
// Actions contains buttons combinations, used for general inputs
Actions map[string]Action
}
// InputHandler contains input axis values and actions corresponding to specified controls
type InputHandler struct {
// Axes contains input axis values
Axes map[string]float64
// Actions contains input actions
Actions map[string]bool
}
func getInterfaceValue(treeMap interface{}, data interface{}) (interface{}, error) {
// Unmarshal from tree
if tree, err := toml.TreeFromMap(treeMap.(map[string]interface{})); err != nil {
return nil, err
} else if err := tree.Unmarshal(data); err != nil {
return nil, err
}
v := reflect.ValueOf(data).Elem()
// Get non-nil field
var typeName string
var value interface{}
for iField := 0; iField < v.NumField(); iField++ {
field := v.Field(iField)
if field.Kind() == reflect.Ptr && !field.IsNil() {
if typeName != "" {
return nil, fmt.Errorf("duplicate fields found: %s, %s", field.Elem().Type().Name(), typeName)
}
typeName = field.Elem().Type().Name()
value = field.Interface()
}
}
return value, nil
}