diff --git a/camera.go b/camera.go index ed17a44..855b018 100644 --- a/camera.go +++ b/camera.go @@ -22,12 +22,11 @@ func (e *Engine) NewCamera() *Camera { // position, scale and rotation to apply // it to the objects to get the real // transform to display on the screen. -// (Should implement buffering it so we do not -// need to calculate it each time for each object. ) func (c *Camera)RealMatrix() Matrix { - /*if c.buf != nil { + // Bufferization + if c.buf != nil { return *(c.buf) - }*/ + } g := &Matrix{} g.Translate(-c.Position.X, -c.Position.Y) g.Rotate(c.Rotation) diff --git a/cmd/test/debug.go b/cmd/test/debug.go index ab4e27e..5425657 100644 --- a/cmd/test/debug.go +++ b/cmd/test/debug.go @@ -15,21 +15,38 @@ type Debug struct { func (d *Debug) Draw(c *Context) { e := c.Engine keyStrs := []string{} - for _, k := range e.Keys() { - keyStrs = append(keyStrs, k.String()) - } - if rectMove.ContainsPoint(e.AbsCursorPosition()) { + keys := []string{} + for _, k := range e.Keys() { + keys = append(keys, k.String()) + } + keyStrs = append(keyStrs, fmt.Sprintf( + "keys: %s", strings.Join(keys, ", "), + )) + + keyStrs = append(keyStrs, fmt.Sprintf( + "buttons: %v", c.MouseButtons(), + )) + keyStrs = append(keyStrs, fmt.Sprintf( + "wheel: %v", c.Wheel(), + )) + + /*if rectMove.ContainsPoint(e.AbsCursorPosition()) { keyStrs = append(keyStrs, "contains cursor") } if rectMove.Vertices().Contained(rect).Len() > 0 || rect.Vertices().Contained(rectMove).Len() > 0 { keyStrs = append(keyStrs, "rectangles intersect") - } + }*/ - keyStrs = append(keyStrs, fmt.Sprintf("%v", e.CursorPosition())) - keyStrs = append(keyStrs, fmt.Sprintf("%v", e.AbsCursorPosition())) + keyStrs = append(keyStrs, fmt.Sprintf( + "camera position: %v %v", + c.Camera.Position.X, + c.Camera.Position.Y, + )) + keyStrs = append(keyStrs, fmt.Sprintf("realCursorPos: %v", e.CursorPosition())) + keyStrs = append(keyStrs, fmt.Sprintf("absCursorPos: %v", e.AbsCursorPosition())) keyStrs = append(keyStrs, fmt.Sprintf("absWinSize: %v", c.AbsWinSize())) e.DebugPrint(c.Image, diff --git a/cmd/test/player.go b/cmd/test/player.go index 182d430..26a8eab 100644 --- a/cmd/test/player.go +++ b/cmd/test/player.go @@ -82,9 +82,9 @@ func (p *Player) Update(c *Context) { } case gg.KeyF: if c.IsPressed(gg.KeyShift) { - cam.Scale = cam.Scale.Add(gg.V1(p.ScaleSpeed * dt)) + cam.Scale = cam.Scale.Add(gg.V2(p.ScaleSpeed * dt)) } else { - cam.Scale = cam.Scale.Add(gg.V1(-p.ScaleSpeed * dt)) + cam.Scale = cam.Scale.Add(gg.V2(-p.ScaleSpeed * dt)) } case gg.KeyG: if c.IsPressed(gg.KeyShift) { @@ -124,6 +124,17 @@ func (p *Player) Event(c *gg.Context) { p.Layer = HighestL } } + case *gg.MouseMove : + if !c.IsButtoned(gg.MouseButtonRight) { + break + } + pos := c.Camera.Position + c.Camera.Position = pos.Sub(ec.Abs) + case *gg.WheelChange : + c.Camera.Scale = c.Camera.Scale.Add(gg.V2( + ec.Offset.Y * c.DT() * p.ScaleSpeed, + )) } + } diff --git a/cmd/test/trianlge.go b/cmd/test/trianlge.go index acdd065..7a1e459 100644 --- a/cmd/test/trianlge.go +++ b/cmd/test/trianlge.go @@ -11,7 +11,7 @@ type Tri struct { func NewTri() *Tri { ret := &Tri{} ret.DrawablePolygon = &gg.DrawablePolygon{} - ret.Transform.Scale = gg.V(1, 1) + ret.Transform.Scale = gg.V2(1) ret.Triangles = gg.Triangles{ gg.Triangle{ diff --git a/engine.go b/engine.go index c4d7349..48d4a41 100644 --- a/engine.go +++ b/engine.go @@ -6,6 +6,7 @@ import ( "github.com/di4f/gods/maps" //"fmt" "time" + "slices" ) // The type represents order of drawing. @@ -53,8 +54,9 @@ type Engine struct { // Temporary stuff keys, prevKeys []Key - cursorPos, prevCursorPos Vector - mouseButtons, prevMouseButtons []MouseButton + buttons MouseButtonMap + wheel Vector + cursorPos Vector outerEvents, handleEvents EventChan } @@ -65,6 +67,18 @@ func (e *Engine) Keys() []Key { return e.keys } +// Returns currently pressed buttons. +func (e *Engine) MouseButtons() []MouseButton { + ret := make([]MouseButton, len(e.buttons)) + i := 0 + for v := range e.buttons { + ret[i] = v + i++ + } + slices.Sort(ret) + return ret +} + // Returns new empty Engine. func NewEngine( cfg *WindowConfig, @@ -79,6 +93,7 @@ func NewEngine( ret.outerEvents = make(EventChan) ret.handleEvents = make(EventChan) ret.Objects = maps.NewOrdered[Object, struct{}]() + ret.buttons = MouseButtonMap{} return ret } @@ -141,18 +156,94 @@ func (e *Engine) Del(b any) error { return nil } +var ( + allButtons = []MouseButton{ + MouseButton0, + MouseButton1, + MouseButton2, + MouseButton3, + MouseButton4, + } +) + +func (e *Engine) IsPressed(k Key) bool { + keys := e.Keys() + for _, v := range keys { + if v == k { + return true + } + } + + return false +} + +func (e *Engine) IsButtoned(b MouseButton) bool { + _, ok := e.buttons[b] + return ok +} + +func (e *Engine) Wheel() Vector { + return e.wheel +} + +func (e *Engine) cursorPosition() Vector { + x, y := ebiten.CursorPosition() + return V(Float(x), Float(y)) +} + +func (e *Engine) CursorPosition() Vector { + return e.cursorPos +} + +func (e *Engine) AbsCursorPosition() Vector { + m := &Matrix{} + m.Concat(e.Camera.AbsMatrix()) + return e.CursorPosition().Apply(m) +} func (e *engine) Update() error { eng := (*Engine)(e) + e.dt = time.Since(e.lastTime).Seconds() + for object := range e.Objects.KeyChan() { + updater, ok := object.(Updater) + if !ok { + continue + } + updater.Update(&Context{ + Engine: eng, + }) + } e.prevKeys = e.keys e.keys = inpututil. AppendPressedKeys(e.keys[:0]) events := []any{} + btns := e.buttons + for _, btn := range allButtons { + if inpututil.IsMouseButtonJustPressed(btn) { + btns[btn] = struct{}{} + events = append(events, &MouseButtonDown{ + MouseButton: btn, + }) + } else if inpututil.IsMouseButtonJustReleased(btn) { + delete(btns, btn) + events = append(events, &MouseButtonUp{ + MouseButton: btn, + }) + } + } - diff := keyDiff(e.prevKeys, e.keys) - for _, key := range diff { + x, y := ebiten.Wheel() + eng.wheel = V(x, y) + if !(eng.wheel.Eq(ZV)) { + events = append(events, &WheelChange{ + Offset: eng.wheel, + }) + } + + keyDiff := diffEm(e.prevKeys, e.keys) + for _, key := range keyDiff { var event any if eng.IsPressed(key) { event = &KeyDown{ @@ -166,7 +257,19 @@ func (e *engine) Update() error { events = append(events, event) } - e.dt = time.Since(e.lastTime).Seconds() + realPos := eng.cursorPosition() + if !realPos.Eq(eng.cursorPos) { + absM := eng.Camera.AbsMatrix() + + absPrevPos :=eng.cursorPos.Apply(&absM) + absPos := realPos.Apply(&absM) + + events = append(events, &MouseMove{ + Real: realPos.Sub(eng.cursorPos), + Abs: absPos.Sub(absPrevPos), + }) + eng.cursorPos = realPos + } for object := range e.Objects.KeyChan() { eventer, ok := object.(Eventer) if ok { @@ -177,16 +280,9 @@ func (e *engine) Update() error { }) } } - updater, ok := object.(Updater) - if !ok { - continue - } - updater.Update(&Context{ - Engine: eng, - }) } - e.lastTime = time.Now() + e.lastTime = time.Now() return nil } diff --git a/event.go b/event.go index cd11f41..7399d07 100644 --- a/event.go +++ b/event.go @@ -4,9 +4,9 @@ import ( //"github.com/hajimehoshi/ebiten/v2" ) -func keyDiff(s1, s2 []Key) []Key { +func diffEm[V comparable](s1, s2 []V) []V { combinedSlice := append(s1, s2...) - dm := make(map[Key]int) + dm := make(map[V]int) for _, v := range combinedSlice { if _, ok := dm[v]; ok { // remove element later as it exist in both slice. @@ -16,7 +16,7 @@ func keyDiff(s1, s2 []Key) []Key { // new entry, add in map! dm[v] = 1 } - var retSlice []Key + var retSlice []V for k, v := range dm { if v == 1 { retSlice = append(retSlice, k) @@ -44,7 +44,12 @@ type MouseButtonUp struct { } type MouseMove struct { - Delta Vector + // Real and absolute deltas. + Real, Abs Vector +} + +type WheelChange struct { + Offset Vector } type EventChan chan any diff --git a/keys.go b/keys.go index d4bff97..724b9f3 100644 --- a/keys.go +++ b/keys.go @@ -156,13 +156,3 @@ const ( KeyRightBracket Key = Key(ebiten.KeyBracketRight) KeyArrowUp Key = Key(ebiten.KeyArrowUp) ) -func (e *Engine) IsPressed(k Key) bool { - keys := e.Keys() - for _, v := range keys { - if v == k { - return true - } - } - - return false -} diff --git a/mouse.go b/mouse.go index cf7c562..55984c2 100644 --- a/mouse.go +++ b/mouse.go @@ -4,16 +4,18 @@ import ( "github.com/hajimehoshi/ebiten/v2" ) +type MouseButtonMap map[MouseButton] struct{} type MouseButton = ebiten.MouseButton +const ( + MouseButtonLeft MouseButton = ebiten.MouseButton0 + MouseButtonMiddle MouseButton = ebiten.MouseButton1 + MouseButtonRight MouseButton = ebiten.MouseButton2 -func (e *Engine) CursorPosition() Vector { - x, y := ebiten.CursorPosition() - return V(Float(x), Float(y)) -} - -func (e *Engine) AbsCursorPosition() Vector { - m := &Matrix{} - m.Concat(e.Camera.AbsMatrix()) - return e.CursorPosition().Apply(m) -} + MouseButton0 MouseButton = ebiten.MouseButton0 + MouseButton1 MouseButton = ebiten.MouseButton1 + MouseButton2 MouseButton = ebiten.MouseButton2 + MouseButton3 MouseButton = ebiten.MouseButton3 + MouseButton4 MouseButton = ebiten.MouseButton4 + MouseButtonMax MouseButton = ebiten.MouseButton4 +) diff --git a/transform.go b/transform.go index c9e1fa4..abb26f3 100644 --- a/transform.go +++ b/transform.go @@ -22,11 +22,12 @@ type Transform struct { Parent *Transform } -// Returns empty Transform -// with standard scaling. (1/1) +// Returns the default Transform structure. func T() Transform { ret := Transform{ + // Rotate around Scale: Vector{1, 1}, + // Rotate around the center. Around: V(.5, .5), } return ret diff --git a/vector.go b/vector.go index f310c58..abf0949 100644 --- a/vector.go +++ b/vector.go @@ -5,6 +5,10 @@ import ( "math" ) +var ( + ZV = V2(0) +) + type Vector struct { X, Y Float } @@ -18,7 +22,7 @@ func V(x, y Float) Vector { return Vector{x, y} } -func V1(v Float) Vector { +func V2(v Float) Vector { return V(v, v) }