diff --git a/go.mod b/go.mod index d8f9472..98e6dfd 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/hajimehoshi/ebiten/v2 v2.6.0-alpha.3.0.20230521122940-90562ee84b9b // indirect github.com/hajimehoshi/file2byteslice v1.0.0 // indirect github.com/jezek/xgb v1.1.0 // indirect + github.com/mojosa-software/godat v0.0.0-20230831073655-8009ad0e84fd // indirect github.com/surdeus/godat v0.0.0-20230428145139-f51a8ab74bc8 // indirect golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1 // indirect diff --git a/go.sum b/go.sum index 0d34d57..e15cd18 100644 --- a/go.sum +++ b/go.sum @@ -24,6 +24,8 @@ github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk= github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/jfreymuth/oggvorbis v1.0.4/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII= github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ= +github.com/mojosa-software/godat v0.0.0-20230831073655-8009ad0e84fd h1:zc6BBPR5U31BMLrjFDfLoZuvRIygaDAWnDbQxEYPxrc= +github.com/mojosa-software/godat v0.0.0-20230831073655-8009ad0e84fd/go.mod h1:E6ohOj8PpUJBQOSRdrLygjoO+Te6yfeox3ZtaItsHUg= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/surdeus/godat v0.0.0-20230217130825-eddf2c345cb7 h1:Fmoxhb42mS6BEmLF2spRiYlzes+S1VrEw0PnbR1ktUM= github.com/surdeus/godat v0.0.0-20230217130825-eddf2c345cb7/go.mod h1:tQGz8oe6Qig5yjYobaW1O8paXGGhzdukg8nT2bpvfes= diff --git a/src/cmd/test/main.go b/src/cmd/test/main.go index 4f77ac3..d26e039 100644 --- a/src/cmd/test/main.go +++ b/src/cmd/test/main.go @@ -11,20 +11,34 @@ import ( "math/rand" ) +const ( + HighestL gx.Layer = -iota + DebugL + TriangleL + PlayerL + RectL + LowestL +) + type Player struct { *gx.Sprite MoveSpeed gx.Float ScaleSpeed gx.Float + gx.Layer } -type Debug struct{} +type Debug struct{ + gx.Layer +} type Rect struct { *gx.DrawableRectangle + gx.Layer } type Tri struct { *gx.DrawablePolygon + gx.Layer } func NewTri() *Tri { @@ -46,12 +60,13 @@ func NewTri() *Tri { } ret.Color = gx.Color{gx.MaxColorV, gx.MaxColorV, 0, gx.MaxColorV} ret.Visible = true + ret.Layer = TriangleL return ret } func NewRect() *Rect { - return &Rect{&gx.DrawableRectangle{ + ret := &Rect{&gx.DrawableRectangle{ Rectangle: gx.Rectangle{ Transform: gx.Transform{ S: gx.Vector{ @@ -76,7 +91,11 @@ func NewRect() *Rect { nil, }, },*/ - }} + }, + RectL, + } + + return ret } func (r *Rect) Update(e *gx.Engine) error { @@ -110,6 +129,7 @@ func NewPlayer() *Player { } ret.Images[0] = playerImg + ret.Layer = PlayerL return ret } @@ -206,6 +226,12 @@ func (p *Player) Update(e *gx.Engine) error { } case ebiten.Key0 : e.Del(p) + case ebiten.KeyB : + if p.Layer != PlayerL { + p.Layer = PlayerL + } else { + p.Layer = HighestL + } }} return nil @@ -251,10 +277,11 @@ func main() { rect = NewRect() tri = NewTri() - e.Add(1, &Debug{}) - e.Add(0, player) - e.Add(-1, rect) - e.Add(100, tri) + e.Add(&Debug{}) + e.Add(player) + e.Add(rect) + e.Add(tri) + fmt.Println(rect.GetLayer(), player.GetLayer()) e.Run() } diff --git a/src/gx/collider.go b/src/gx/collider.go index c4c05fb..f3a7317 100644 --- a/src/gx/collider.go +++ b/src/gx/collider.go @@ -20,26 +20,10 @@ type Collision struct { // to determine if the object collides with anything. // Mostly will use the Collide function with some // inner structure field as first argument. +// The Collide method will be called on collisions. type Collider interface { Collides(Collider) *Collision -} - -// happening collision getting the Collision as -// argument. -type CollideEventer interface { Collide(*Collision) } -// Single function for all collision to remove -// functionality duplicating from the archtecture. -// Returns the collision if there is and nil if there -// is no collision. -/*func Collide(c1, c2 any) bool { -} - -func triangleCollidesPoint(t Triangle, p Point) *Collision { -} - -func triangleCollidesTriangle(t1, t2 Triangle) *Collision -*/ diff --git a/src/gx/engine.go b/src/gx/engine.go index 9e8fa89..0e104b4 100644 --- a/src/gx/engine.go +++ b/src/gx/engine.go @@ -3,14 +3,19 @@ package gx import ( "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/inpututil" - "github.com/surdeus/godat/src/sparsex" - "github.com/surdeus/godat/src/poolx" + "github.com/mojosa-software/godat/sparsex" + "github.com/mojosa-software/godat/mapx" "fmt" "time" ) // The type represents order of drawing. -type Layer int +// Higher values are drawn later. +type Layer float64 + +func (l Layer) GetLayer() Layer { + return l +} // Window configuration type. type WindowConfig struct { @@ -27,8 +32,7 @@ type WindowConfig struct { // The main structure that represents current state of [game] engine. type Engine struct { wcfg *WindowConfig - layers *sparsex.Sparse[Layer, *poolx.Pool[Drawer]] - updaters *poolx.Pool[Updater] + objects *mapx.OrderedMap[Object, struct{}] lastTime time.Time dt Float camera *Camera @@ -58,81 +62,59 @@ func NewEngine( ) *Engine { w := Float(cfg.Width) h := Float(cfg.Height) - fmt.Println("res:", w, h) return &Engine{ wcfg: cfg, - layers: sparsex.New[ - Layer, - *poolx.Pool[Drawer], - ](true), camera: &Camera{ Transform: Transform{ + // Normal, no distortion. S: Vector{1, 1}, + // Center. RA: V(w/2, h/2), }, }, - updaters: poolx.New[Updater](), + objects: mapx.NewOrdered[Object, struct{}](), } } // Add new object considering what // interfaces it implements. -func (e *Engine) Add(l Layer, b any) { +func (e *Engine) Add(b any) error { + object, _ := b.(Object) + if e.objects.Has(object) { + return ObjectExistErr + } + /*o, ok := e.makeObject(b) + if !ok { + return ObjectNotImplementedErr + }*/ + starter, ok := b.(Starter) if ok { starter.Start(e) } - - updater, ok := b.(Updater) - if ok { - e.addUpdater(updater) - } - drawer, ok := b.(Drawer) - if ok { - e.addDrawer(l, drawer) - } + e.objects.Set(object, struct{}{}) + + return nil } // Delete object from Engine. -func (e *Engine) Del(b any, v ...any) { +func (e *Engine) Del(b any) error { + object, _ := b.(Object) + if !e.objects.Has(object) { + return ObjectNotExistErr + } + deleter, ok := b.(Deleter) if ok { - deleter.Delete(e, v...) - } - - drawer, ok := b.(Drawer) - if ok { - for layer := range e.layers.Vals() { - layer.V.Del(drawer) - } - } - - updater, ok := b.(Updater) - if ok { - e.updaters.Del(updater) - } - -} - -func (e *Engine) addDrawer(l Layer, d Drawer) { - g, ok := e.layers.Get(l) - if !ok { - layer := poolx.New[Drawer]() - e.layers.Set( - l, - layer, - ) - layer.Append(d) - } else { - g.Append(d) + deleter.Delete(e) } + e.objects.Del(b) + + return nil } -func (e *Engine) addUpdater(b Updater) { - e.updaters.Append(b) -} func (e *engine) Update() error { var err error @@ -142,8 +124,12 @@ func (e *engine) Update() error { AppendPressedKeys(e.keys[:0]) e.dt = time.Since(e.lastTime).Seconds() - for p := range eng.updaters.Range() { - err = p.V.Update(eng) + for object := range e.objects.KeyChan() { + updater, ok := object.(Updater) + if !ok { + continue + } + err = updater.Update(eng) if err != nil { return err } @@ -155,13 +141,28 @@ func (e *engine) Update() error { func (e *engine) Draw(i *ebiten.Image) { eng := (*Engine)(e) - for p := range e.layers.Vals() { - for pj := range p.V.Range() { - visibler, ok := pj.V.(Visibler) - if ok && !visibler.IsVisible() { - continue - } - pj.V.Draw(eng, i) + layers := sparsex.New[Layer, []Drawer]() + for object := range eng.objects.KeyChan() { + drawer, ok := object.(Drawer) + if !ok { + continue + } + + l := drawer.GetLayer() + layer, ok := layers.Get(l) + if !ok { + layers.Set(l, []Drawer{drawer}) + continue + } + + layers.Set(l, append(layer, drawer)) + } + + // Drawing sorted layers. + layers.Sort() + for layer := range layers.Chan() { + for _, drawer := range layer { + drawer.Draw(eng, i) } } } @@ -187,6 +188,7 @@ func (e *Engine) Run() error { ebiten.SetVsyncEnabled(e.wcfg.VSync) e.lastTime = time.Now() + fmt.Println(e.objects) return ebiten.RunGame((*engine)(e)) } diff --git a/src/gx/errors.go b/src/gx/errors.go new file mode 100644 index 0000000..f8ba5e4 --- /dev/null +++ b/src/gx/errors.go @@ -0,0 +1,12 @@ +package gx + +import ( + "errors" +) + +var ( + ObjectExistErr = errors.New("the object already exists") + ObjectNotExistErr = errors.New("the object does not exist") + ObjectNotImplementedErr = errors.New("none of object methods are implemented") +) + diff --git a/src/gx/img.go b/src/gx/img.go index c7321bf..f114f47 100644 --- a/src/gx/img.go +++ b/src/gx/img.go @@ -16,32 +16,11 @@ type Color struct { R, G, B, A ColorV } -type Colority struct { - Color Color -} - -type Visibility struct { - Visible bool -} - -// The interface describes anything that can be -// drawn. It will be drew corresponding to -// the layers order. -type Drawer interface { - Draw(*Engine, *Image) -} - -type Visibler interface { - IsVisible() bool -} const ( MaxColorV = math.MaxUint32 ) -func (v Visibility) IsVisible() bool { - return v.Visible -} func LoadImage(input io.Reader) (*Image, error) { img, _, err := image.Decode(input) diff --git a/src/gx/object.go b/src/gx/object.go index 679c4db..3b2cdf1 100644 --- a/src/gx/object.go +++ b/src/gx/object.go @@ -6,7 +6,7 @@ package gx // the OnUpdate. // The v value will be get from Add function. type Starter interface { - Start(*Engine, ...any) + Start(*Engine) } // Implementing the interface type @@ -23,3 +23,26 @@ type Deleter interface { Delete(*Engine, ...any) } +type Visibility struct { + Visible bool +} +func (v Visibility) IsVisible() bool { + return v.Visible +} + +type Colority struct { + Color Color +} + +// The interface describes anything that can be +// drawn. It will be drew corresponding to +// the layers order. +type Drawer interface { + Draw(*Engine, *Image) + GetLayer() Layer + IsVisible() bool +} + +// The type represents everything that can work inside engine. +type Object any +