diff --git a/cmd/view-obj/main.go b/cmd/view-obj/main.go index 6b363e1..e7a1915 100644 --- a/cmd/view-obj/main.go +++ b/cmd/view-obj/main.go @@ -9,7 +9,6 @@ import ( "path/filepath" "github.com/hajimehoshi/ebiten" - "github.com/hajimehoshi/ebiten/inpututil" "ur.gs/ordoor/internal/conv" "ur.gs/ordoor/internal/data" @@ -22,14 +21,15 @@ var ( ) type env struct { - obj *conv.Object - state *state + obj *conv.Object + step int + + state state + lastState state } type state struct { - step int spriteIdx int - maxSprite int zoom float64 origin image.Point @@ -53,18 +53,30 @@ func main() { log.Fatalf("Failed to convert %s: %v", *objFile, err) } - state := &state{ - zoom: 6.0, - origin: image.Point{0, 0}, - maxSprite: len(obj.Sprites) - 1, + state := state{ + zoom: 6.0, + origin: image.Point{0, 0}, + } + + env := &env{ + obj: obj, + state: state, + lastState: state, } - env := &env{obj: obj, state: state} win, err := ui.NewWindow("View Object: " + *objFile) if err != nil { log.Fatal(err) } + win.OnKeyUp(ebiten.KeyMinus, env.changeSprite(-1)) + win.OnKeyUp(ebiten.KeyEqual, env.changeSprite(+1)) + win.OnKeyUp(ebiten.KeyLeft, env.changeOrigin(+4, +0)) + win.OnKeyUp(ebiten.KeyRight, env.changeOrigin(-4, +0)) + win.OnKeyUp(ebiten.KeyUp, env.changeOrigin(+0, +4)) + win.OnKeyUp(ebiten.KeyDown, env.changeOrigin(+0, -4)) + win.OnMouseWheel(env.changeZoom) + // The main thread now belongs to ebiten if err := win.Run(env.Update, env.Draw); err != nil { log.Fatal(err) @@ -72,32 +84,23 @@ func main() { } func (e *env) Update() error { - oldState := e.state - state := oldState.runStep() - - if oldState.step == 0 || *oldState != *state { + if e.step == 0 || e.lastState != e.state { log.Printf( "new state: numSprites=%d sprite=%d zoom=%.2f, origin=%+v", len(e.obj.Sprites), - state.spriteIdx, - state.zoom, - state.origin, + e.state.spriteIdx, + e.state.zoom, + e.state.origin, ) } - state.step += 1 - e.state = state + // This should be the final action + e.step += 1 + e.lastState = e.state return nil } -func (s *state) runStep() *state { - newState := *s - newState.handleKeys() - - return &newState -} - func (e *env) Draw(screen *ebiten.Image) error { sprite := e.obj.Sprites[e.state.spriteIdx] @@ -108,36 +111,28 @@ func (e *env) Draw(screen *ebiten.Image) error { return screen.DrawImage(sprite.Image, &ebiten.DrawImageOptions{GeoM: cam}) } -func (s *state) handleKeys() { - if inpututil.IsKeyJustReleased(ebiten.KeyMinus) { - if s.spriteIdx > 0 { - s.spriteIdx -= 1 +func (e *env) changeSprite(by int) func() { + return func() { + e.state.spriteIdx += by + + if e.state.spriteIdx < 0 { + e.state.spriteIdx = 0 + } + + if e.state.spriteIdx > len(e.obj.Sprites)-1 { + e.state.spriteIdx = len(e.obj.Sprites) - 1 } } - - if inpututil.IsKeyJustReleased(ebiten.KeyEqual) { - if s.spriteIdx < s.maxSprite { - s.spriteIdx += 1 - } - } - - if ebiten.IsKeyPressed(ebiten.KeyLeft) { - s.origin.X += 4 - } - - if ebiten.IsKeyPressed(ebiten.KeyRight) { - s.origin.X -= 4 - } - - if ebiten.IsKeyPressed(ebiten.KeyUp) { - s.origin.Y += 4 - } - - if ebiten.IsKeyPressed(ebiten.KeyDown) { - s.origin.Y -= 4 - } - - // Zoom in and out with the mouse wheel - _, wheelY := ebiten.Wheel() - s.zoom *= math.Pow(1.2, wheelY) +} + +func (e *env) changeOrigin(byX, byY int) func() { + return func() { + e.state.origin.X += byX + e.state.origin.Y += byY + } +} + +func (e *env) changeZoom(_, y float64) { + // Zoom in and out with the mouse wheel + e.state.zoom *= math.Pow(1.2, y) } diff --git a/internal/ui/window.go b/internal/ui/window.go index 976c671..c6e3ea2 100644 --- a/internal/ui/window.go +++ b/internal/ui/window.go @@ -4,6 +4,7 @@ import ( "flag" "github.com/hajimehoshi/ebiten" + "github.com/hajimehoshi/ebiten/inpututil" ) var ( @@ -12,8 +13,9 @@ var ( ) type Window struct { - Title string - KeyEventHandlers map[ebiten.Key][]func() + Title string + KeyUpHandlers map[ebiten.Key]func() + MouseWheelHandler func(float64, float64) // User-provided update actions updateFn func() error @@ -25,13 +27,18 @@ type Window struct { // ebiten assumes a single window, so only call this once... func NewWindow(title string) (*Window, error) { return &Window{ - Title: title, - KeyEventHandlers: make(map[ebiten.Key][]func()), + Title: title, + KeyUpHandlers: make(map[ebiten.Key]func()), }, nil } +// TODO: multiple handlers for the same key? func (w *Window) OnKeyUp(key ebiten.Key, f func()) { + w.KeyUpHandlers[key] = f +} +func (w *Window) OnMouseWheel(f func(x, y float64)) { + w.MouseWheelHandler = f } func (w *Window) run(screen *ebiten.Image) error { @@ -40,6 +47,20 @@ func (w *Window) run(screen *ebiten.Image) error { } // Process keys + // TODO: efficient set operations + + for key, cb := range w.KeyUpHandlers { + if inpututil.IsKeyJustReleased(key) { + cb() + } + } + + if w.MouseWheelHandler != nil { + x, y := ebiten.Wheel() + if x != 0 || y != 0 { + w.MouseWheelHandler(x, y) + } + } if !ebiten.IsDrawingSkipped() { if err := w.drawFn(screen); err != nil {