Skip to content

Commit 5187186

Browse files
committed
Add input viewer
1 parent cac02be commit 5187186

File tree

5 files changed

+138
-4
lines changed

5 files changed

+138
-4
lines changed

app.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"errors"
55
"fmt"
6+
inputviewer "ivan/input-viewer"
67
"ivan/timer"
78
"ivan/tracker"
89
"log"
@@ -18,9 +19,10 @@ const configPath = "assets/config.json"
1819
var errCloseApp = errors.New("user requested app close")
1920

2021
type App struct {
21-
tracker *tracker.Tracker
22-
timer *timer.Timer
23-
config config
22+
tracker *tracker.Tracker
23+
timer *timer.Timer
24+
inputViewer *inputviewer.InputViewer
25+
config config
2426

2527
saveDebounce func(func())
2628
}
@@ -61,6 +63,7 @@ func NewApp() (*App, error) {
6163
return &App{
6264
tracker: tracker,
6365
timer: timer,
66+
inputViewer: nil, // initialized on first frame to ensure we have a gamepad
6467
config: config,
6568
saveDebounce: debounce.New(1 * time.Second),
6669
}, nil
@@ -71,6 +74,10 @@ func (app *App) Update(screen *ebiten.Image) error {
7174
_, wheel := ebiten.Wheel()
7275
var shouldSave bool
7376

77+
if app.inputViewer == nil {
78+
app.inputViewer = inputviewer.NewInputViewer(app.config.InputViewer)
79+
}
80+
7481
switch {
7582
case inpututil.IsKeyJustPressed(ebiten.KeyEscape):
7683
if !app.timer.IsRunning() && !app.tracker.EatInput() {
@@ -147,6 +154,7 @@ func (app *App) Update(screen *ebiten.Image) error {
147154
func (app *App) Draw(screen *ebiten.Image) {
148155
app.tracker.Draw(screen)
149156
app.timer.Draw(screen)
157+
app.inputViewer.Draw(screen)
150158
}
151159

152160
func (app *App) Layout(w, h int) (int, int) {

assets/config.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
{
2+
"InputViewer": {
3+
"A": {"Type": "Button", "ID": 1, "Pos": {"X": 130, "Y": 384}, "Color": {"G": 255}},
4+
"B": {"Type": "Button", "ID": 3, "Pos": {"X": 134, "Y": 384}, "Color": {"R": 255}},
5+
"Start": {"Type": "Button", "ID": 7, "Pos": {"X": 138, "Y": 384}, "Color": {"R": 255, "G": 255, "B": 255}},
6+
"CLeft": {"Type": "Button", "ID": 0, "Pos": {"X": 142, "Y": 388}, "Color": {"R": 255, "G": 255}},
7+
"CUp": {"Type": "Axis", "ID": 4, "Dir": 1, "Pos": {"X": 146, "Y": 384}, "Color": {"R": 255, "G": 255}},
8+
"CDown": {"Type": "Button", "ID": 4, "Pos": {"X": 146, "Y": 392}, "Color": {"R": 255, "G": 255}},
9+
"CRight": {"Type": "Button", "ID": 2, "Pos": {"X": 150, "Y": 388}, "Color": {"R": 255, "G": 255}},
10+
"Z": {"Type": "Axis", "ID": 2, "Pos": {"X": 154, "Y": 384}, "Color": {"R": 255, "G": 255, "B": 255}},
11+
"R": {"Type": "Axis", "ID": 5, "Pos": {"X": 158, "Y": 384}, "Color": {"R": 255, "G": 255, "B": 255}},
12+
13+
"J": {"Type": "Axis", "IDX": 0, "IDY": 1, "Pos": {"X": 122, "Y": 388}, "Color": {"R": 255, "G": 255, "B": 255}}
14+
},
15+
216
"Binds": {
317
"0": "StartItemInput",
418
".": "DowngradeNext",

config.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"encoding/json"
55
"image"
6+
inputviewer "ivan/input-viewer"
67
"ivan/tracker"
78
"os"
89
)
@@ -15,7 +16,8 @@ type config struct {
1516

1617
DungeonInputMedallionOrder, DungeonInputDungeonKP []string
1718

18-
Dimensions struct {
19+
InputViewer inputviewer.Config
20+
Dimensions struct {
1921
ItemTracker image.Rectangle
2022
Timer image.Rectangle
2123
HintTracker image.Rectangle

input-viewer/input_viewer.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package inputviewer
2+
3+
import (
4+
"image"
5+
"image/color"
6+
"log"
7+
8+
"github.com/hajimehoshi/ebiten"
9+
"github.com/hajimehoshi/ebiten/ebitenutil"
10+
)
11+
12+
type Config struct {
13+
A, B, Z, R, Start InputButton
14+
CUp, CRight, CDown, CLeft InputButton
15+
16+
J InputJoystick
17+
}
18+
19+
type InputButton struct {
20+
Type string // (Button, Axis)
21+
ID int
22+
Dir int // -1 / 1
23+
24+
Pos image.Point
25+
Color color.RGBA
26+
}
27+
28+
type InputJoystick struct {
29+
IDX, IDY int
30+
31+
Pos image.Point
32+
Color color.RGBA
33+
}
34+
35+
func (i InputJoystick) axes(id int) (float64, float64) {
36+
return ebiten.GamepadAxis(id, i.IDX), ebiten.GamepadAxis(id, i.IDY)
37+
}
38+
39+
func (i InputButton) pressed(id int) bool {
40+
dir := 1.0
41+
if dir < 0 {
42+
dir = -1
43+
}
44+
45+
switch i.Type {
46+
case "Button":
47+
return ebiten.IsGamepadButtonPressed(id, ebiten.GamepadButton(i.ID))
48+
case "Axis":
49+
return ebiten.GamepadAxis(id, i.ID) > (dir * 0.15)
50+
}
51+
52+
return false
53+
}
54+
55+
type InputViewer struct {
56+
config Config
57+
id int
58+
}
59+
60+
func NewInputViewer(config Config) *InputViewer {
61+
ids := ebiten.GamepadIDs()
62+
if len(ids) == 0 {
63+
log.Printf("warning: no gamepad found")
64+
return nil
65+
}
66+
id := ids[0]
67+
68+
log.Printf("info: reading input from %s", ebiten.GamepadName(id))
69+
70+
return &InputViewer{
71+
config: config,
72+
id: id,
73+
}
74+
}
75+
76+
func (iv *InputViewer) Draw(screen *ebiten.Image) {
77+
if iv == nil { // allow ignoring input viewer
78+
return
79+
}
80+
81+
for _, v := range []*InputButton{
82+
&iv.config.A, &iv.config.B,
83+
&iv.config.Z, &iv.config.R,
84+
&iv.config.Start,
85+
&iv.config.CUp, &iv.config.CRight,
86+
&iv.config.CDown, &iv.config.CLeft,
87+
} {
88+
if !v.pressed(iv.id) {
89+
continue
90+
}
91+
92+
ebitenutil.DrawRect(
93+
screen,
94+
float64(v.Pos.X), float64(v.Pos.Y),
95+
2, 2,
96+
color.RGBA{v.Color.R, v.Color.G, v.Color.B, 0xFF},
97+
)
98+
}
99+
100+
j := iv.config.J
101+
x, y := j.axes(iv.id)
102+
ebitenutil.DrawRect(
103+
screen,
104+
float64(j.Pos.X)+4.0*x,
105+
float64(j.Pos.Y)+4.0*y,
106+
2, 2,
107+
color.RGBA{j.Color.R, j.Color.G, j.Color.B, 0xFF},
108+
)
109+
}

tracker/input.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ func (tracker *Tracker) idleHandleAction(a action) {
125125
}
126126
}
127127

128+
// nolint:funlen
128129
func (tracker *Tracker) inputAction(a action) {
129130
// Ensure we can _always_ leave using KP0
130131
if a == actionStartItemInput && !tracker.kbInputStateIs(inputStateIdle) {

0 commit comments

Comments
 (0)