feat: using goroutines for every object.

This commit is contained in:
Andrey Parhomenko 2024-01-08 06:09:36 +03:00
parent 6e76188bd8
commit aa4bcc3f8d
12 changed files with 123 additions and 92 deletions

View file

@ -8,8 +8,7 @@ import (
) )
type Debug struct { type Debug struct {
gg.Visibility gg.Object
gg.Layer
} }
func (d *Debug) Draw(c *Context) { func (d *Debug) Draw(c *Context) {

View file

@ -46,10 +46,10 @@ func main() {
player = NewPlayer() player = NewPlayer()
tri = NewTri() tri = NewTri()
e.Add(&Debug{}) e.Spawn(&Debug{})
e.Add(player) e.Spawn(player)
e.Add(rect) e.Spawn(rect)
e.Add(tri) e.Spawn(tri)
fmt.Println(rect.GetLayer(), player.GetLayer()) fmt.Println(rect.GetLayer(), player.GetLayer())
err = e.Run() err = e.Run()

View file

@ -11,7 +11,6 @@ type Player struct {
gg.Sprite gg.Sprite
MoveSpeed gg.Float MoveSpeed gg.Float
ScaleSpeed gg.Float ScaleSpeed gg.Float
gg.Layer
} }
func NewPlayer() *Player { func NewPlayer() *Player {

View file

@ -4,7 +4,6 @@ import "vultras.su/core/gg"
type Rect struct { type Rect struct {
gg.DrawableRectangle gg.DrawableRectangle
gg.Layer
} }
func NewRect() *Rect { func NewRect() *Rect {
@ -17,6 +16,7 @@ func NewRect() *Rect {
gg.MaxColorV, gg.MaxColorV,
} }
ret.Layer = RectL ret.Layer = RectL
ret.Visible = true
return ret return ret
} }

View file

@ -5,7 +5,7 @@ import "fmt"
type Tri struct { type Tri struct {
gg.DrawablePolygon gg.DrawablePolygon
gg.Layer Spawned bool
} }
func NewTri() *Tri { func NewTri() *Tri {
@ -34,6 +34,10 @@ func (t *Tri) Update(c *Context) {
t.Color = gg.Rgba(1, 0, 1, 1) t.Color = gg.Rgba(1, 0, 1, 1)
} }
/*if t.Spawned {
return
}*/
d := +1. d := +1.
if c.IsPressed(gg.KeyShift) { if c.IsPressed(gg.KeyShift) {
d = -1. d = -1.
@ -55,15 +59,25 @@ func (t *Tri) Update(c *Context) {
func (t *Tri) Event(c *Context) { func (t *Tri) Event(c *Context) {
switch e := c.Event.(type) { switch e := c.Event.(type) {
case *gg.KeyDown: case *gg.KeyDown:
if e.Key != gg.Key1 { fmt.Println(e)
break switch e.Key {
} case gg.Key1 :
if t.Connected() { if t.Connected() {
fmt.Println("disconnecting:", tri.Transform) fmt.Println("disconnecting:", tri.Transform)
t.Disconnect() t.Disconnect()
} else { } else {
t.Connect(player) t.Connect(player)
fmt.Println("connecting:", tri.Transform) fmt.Println("connecting:", tri.Transform)
}
case gg.Key2 :
if t.Spawned {
return
}
fmt.Println("shit")
tt := *t
tt.Spawned = true
tt.Disconnect()
c.Spawn(&tt)
} }
} }
} }

View file

@ -1,6 +1,17 @@
package gg package gg
type contextType int
const (
startContext contextType = iota
updateContext
eventContext
drawContext
deleteContext
)
type Context struct { type Context struct {
typ contextType
events []any
*Engine *Engine
*Image *Image
Event any Event any

108
engine.go
View file

@ -47,7 +47,7 @@ type Engine struct {
// The main holder for objects. // The main holder for objects.
// Uses the map structure to quickly // Uses the map structure to quickly
// delete and create new objects. // delete and create new objects.
Objects maps.Map[Object, struct{}] Objects maps.Map[Objecter, struct{}]
// The main camera to display in window. // The main camera to display in window.
// If is set to nil then the engine will panic. // If is set to nil then the engine will panic.
@ -64,6 +64,7 @@ type Engine struct {
wheel Vector wheel Vector
cursorPos Vector cursorPos Vector
outerEvents, handleEvents EventChan outerEvents, handleEvents EventChan
wg sync.WaitGroup
} }
type engine Engine type engine Engine
@ -102,7 +103,7 @@ func NewEngine(
ret.Camera = ret.NewCamera() ret.Camera = ret.NewCamera()
ret.outerEvents = make(EventChan) ret.outerEvents = make(EventChan)
ret.handleEvents = make(EventChan) ret.handleEvents = make(EventChan)
ret.Objects = maps.NewOrdered[Object, struct{}]() ret.Objects = maps.NewOrdered[Objecter, struct{}]()
ret.buttons = MouseButtonMap{} ret.buttons = MouseButtonMap{}
return ret return ret
} }
@ -125,42 +126,42 @@ func (e *Engine) EventInput() EventChan {
// Add new object considering what // Add new object considering what
// interfaces it implements. // interfaces it implements.
func (e *Engine) Add(b any) error { func (e *Engine) Spawn(b Objecter) error {
object, _ := b.(Object) if e.Objects.Has(b) {
if e.Objects.Has(object) {
return ObjectExistErr return ObjectExistErr
} }
/*o, ok := e.makeObject(b)
if !ok {
return ObjectNotImplementedErr
}*/
starter, ok := b.(Starter) b.Start(&Context{Engine: e})
if ok { obj := b.GetObject()
starter.Start(&Context{ obj.input = make(chan *Context)
Engine: e, go func() {
}) for c := range obj.input {
} switch c.typ {
case updateContext:
e.Objects.Set(object, struct{}{}) b.Update(c)
case eventContext:
for _, event := range c.events {
b.Event(&Context{
Engine: e,
Event: event,
})
}
}
e.wg.Done()
}
}()
e.Objects.Set(b, struct{}{})
return nil return nil
} }
// Delete object from Engine. // Delete object from Engine.
func (e *Engine) Del(b any) error { func (e *Engine) Del(b Objecter) error {
object, _ := b.(Object) if !e.Objects.Has(b) {
if !e.Objects.Has(object) {
return ObjectNotExistErr return ObjectNotExistErr
} }
deleter, ok := b.(Deleter) b.Delete(&Context{Engine: e})
if ok {
deleter.Delete(&Context{
Engine: e,
})
}
e.Objects.Del(b) e.Objects.Del(b)
return nil return nil
@ -210,24 +211,16 @@ func (e *Engine) AbsCursorPosition() Vector {
} }
func (e *engine) Update() error { func (e *engine) Update() error {
var wg sync.WaitGroup
eng := (*Engine)(e) eng := (*Engine)(e)
e.dt = time.Since(e.lastTime).Seconds() e.dt = time.Since(e.lastTime).Seconds()
// Buffering the context for faster.
c := &Context{Engine: eng, typ: updateContext}
for object := range e.Objects.KeyChan() { for object := range e.Objects.KeyChan() {
updater, ok := object.(Updater) e.wg.Add(1)
if !ok { object.Input() <- c
continue
}
wg.Add(1)
go func() {
updater.Update(&Context{
Engine: eng,
})
wg.Done()
}()
} }
wg.Wait() e.wg.Wait()
e.prevKeys = e.keys e.prevKeys = e.keys
e.keys = inpututil. e.keys = inpututil.
@ -289,22 +282,12 @@ func (e *engine) Update() error {
// Providing the events to the objects. // Providing the events to the objects.
// Maybe should think of the better way, // Maybe should think of the better way,
// but for it is simple enough. // but for it is simple enough.
c = &Context{Engine: eng, typ: eventContext, events: events}
for object := range e.Objects.KeyChan() { for object := range e.Objects.KeyChan() {
eventer, ok := object.(Eventer) e.wg.Add(1)
if ok { object.Input() <- c
wg.Add(1)
go func() {
defer wg.Done()
for _, event := range events {
eventer.Event(&Context{
Engine: eng,
Event: event,
})
}
}()
}
} }
wg.Wait() e.wg.Wait()
e.lastTime = time.Now() e.lastTime = time.Now()
return nil return nil
@ -314,30 +297,27 @@ func (e *engine) Draw(i *ebiten.Image) {
eng := (*Engine)(e) eng := (*Engine)(e)
m := map[Layer][]Drawer{} m := map[Layer][]Drawer{}
for object := range eng.Objects.KeyChan() { for object := range eng.Objects.KeyChan() {
drawer, ok := object.(Drawer) // Skipping the ones we do not need to draw.
if !ok { if !object.IsVisible() {
continue continue
} }
l := object.GetLayer()
l := drawer.GetLayer()
layer, ok := m[l] layer, ok := m[l]
// Create new if has no the layer // Create new if has no the layer
if !ok { if !ok {
m[l] = []Drawer{drawer} m[l] = []Drawer{object}
continue continue
} }
m[l] = append(layer, drawer) m[l] = append(layer, object)
} }
// Drawing layers. // Drawing layers.
layers := maps.NewSparse[Layer, []Drawer](nil, m) layers := maps.NewSparse[Layer, []Drawer](nil, m)
c := &Context{Engine: eng, typ: drawContext, Image: i}
for layer := range layers.Chan() { for layer := range layers.Chan() {
for _, drawer := range layer { for _, drawer := range layer {
drawer.Draw(&Context{ drawer.Draw(c)
Engine: eng,
Image: i,
})
} }
} }
// Empty the buff to generate it again. // Empty the buff to generate it again.

View file

@ -1,11 +1,5 @@
package gg package gg
// Implementing the interface lets the object
// to handle emited events.
type Eventer interface {
Event(*Context)
}
// Implementing the interface type // Implementing the interface type
// will call the function OnStart // will call the function OnStart
// when first appear on scene BEFORE // when first appear on scene BEFORE
@ -22,6 +16,12 @@ type Updater interface {
Update(*Context) Update(*Context)
} }
// Implementing the interface lets the object
// to handle emited events.
type Eventer interface {
Event(*Context)
}
// Implementing the interface type // Implementing the interface type
// will call the function on deleting // will call the function on deleting
// the object. // the object.
@ -51,6 +51,29 @@ type Drawer interface {
IsVisible() bool IsVisible() bool
} }
// The type represents everything that can work inside engine. type Objecter interface {
type Object any GetObject() *Object
Input() chan *Context
Starter
Updater
Eventer
Drawer
Deleter
}
// The type for embedding into engine-in types.
type Object struct {
Layer
Visibility
input chan *Context
}
func (o *Object) GetObject() *Object { return o }
func (o *Object) Input() chan *Context { return o.input }
func (o *Object) Start(c *Context) {}
func (o *Object) Update(c *Context) {}
func (o *Object) Event(c *Context) {}
func (o *Object) Draw(c *Context) {}
func (o *Object) Delete(c *Context) {}

View file

@ -5,6 +5,7 @@ import (
// Grouped triangles type. // Grouped triangles type.
type Polygon struct { type Polygon struct {
Object
Transform Transform
Triangles Triangles
} }

View file

@ -9,6 +9,7 @@ import (
// The type describes rectangle geometry. // The type describes rectangle geometry.
type Rectangle struct { type Rectangle struct {
Object
Transform Transform
} }

View file

@ -6,6 +6,7 @@ import (
) )
type Sprite struct { type Sprite struct {
Object
Transform Transform
ShaderOptions ShaderOptions
Floating bool Floating bool
@ -52,7 +53,9 @@ func (s *Sprite) Rectangle() Rectangle {
t.Around.X *= Float(w) t.Around.X *= Float(w)
t.Around.Y *= Float(h) t.Around.Y *= Float(h)
return Rectangle{t} return Rectangle{
Transform: t,
}
} }
// Get triangles of the rectangle that contains the sprite // Get triangles of the rectangle that contains the sprite

View file

@ -92,7 +92,7 @@ func (v Vector) Norm() Vector {
} }
func (pts Points) Contained(c PointContainer) Points { func (pts Points) Contained(c PointContainer) Points {
ret := Points{} ret := make([]Point, 0, len(pts))
for _, pt := range pts { for _, pt := range pts {
if c.ContainsPoint(pt) { if c.ContainsPoint(pt) {