Implemented dynamic layering. (should think of optimizations because it requires to sort objects every frame.
This commit is contained in:
parent
f081e9e6b4
commit
560bb93644
8 changed files with 138 additions and 108 deletions
1
go.mod
1
go.mod
|
@ -8,6 +8,7 @@ require (
|
||||||
github.com/hajimehoshi/ebiten/v2 v2.6.0-alpha.3.0.20230521122940-90562ee84b9b // indirect
|
github.com/hajimehoshi/ebiten/v2 v2.6.0-alpha.3.0.20230521122940-90562ee84b9b // indirect
|
||||||
github.com/hajimehoshi/file2byteslice v1.0.0 // indirect
|
github.com/hajimehoshi/file2byteslice v1.0.0 // indirect
|
||||||
github.com/jezek/xgb v1.1.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
|
github.com/surdeus/godat v0.0.0-20230428145139-f51a8ab74bc8 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
|
golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb // indirect
|
||||||
golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
golang.org/x/exp/shiny v0.0.0-20230522175609-2e198f4a06a1 // indirect
|
||||||
|
|
2
go.sum
2
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/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||||
github.com/jfreymuth/oggvorbis v1.0.4/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
github.com/jfreymuth/oggvorbis v1.0.4/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||||
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
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/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 h1:Fmoxhb42mS6BEmLF2spRiYlzes+S1VrEw0PnbR1ktUM=
|
||||||
github.com/surdeus/godat v0.0.0-20230217130825-eddf2c345cb7/go.mod h1:tQGz8oe6Qig5yjYobaW1O8paXGGhzdukg8nT2bpvfes=
|
github.com/surdeus/godat v0.0.0-20230217130825-eddf2c345cb7/go.mod h1:tQGz8oe6Qig5yjYobaW1O8paXGGhzdukg8nT2bpvfes=
|
||||||
|
|
|
@ -11,20 +11,34 @@ import (
|
||||||
"math/rand"
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
HighestL gx.Layer = -iota
|
||||||
|
DebugL
|
||||||
|
TriangleL
|
||||||
|
PlayerL
|
||||||
|
RectL
|
||||||
|
LowestL
|
||||||
|
)
|
||||||
|
|
||||||
type Player struct {
|
type Player struct {
|
||||||
*gx.Sprite
|
*gx.Sprite
|
||||||
MoveSpeed gx.Float
|
MoveSpeed gx.Float
|
||||||
ScaleSpeed gx.Float
|
ScaleSpeed gx.Float
|
||||||
|
gx.Layer
|
||||||
}
|
}
|
||||||
|
|
||||||
type Debug struct{}
|
type Debug struct{
|
||||||
|
gx.Layer
|
||||||
|
}
|
||||||
|
|
||||||
type Rect struct {
|
type Rect struct {
|
||||||
*gx.DrawableRectangle
|
*gx.DrawableRectangle
|
||||||
|
gx.Layer
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tri struct {
|
type Tri struct {
|
||||||
*gx.DrawablePolygon
|
*gx.DrawablePolygon
|
||||||
|
gx.Layer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTri() *Tri {
|
func NewTri() *Tri {
|
||||||
|
@ -46,12 +60,13 @@ func NewTri() *Tri {
|
||||||
}
|
}
|
||||||
ret.Color = gx.Color{gx.MaxColorV, gx.MaxColorV, 0, gx.MaxColorV}
|
ret.Color = gx.Color{gx.MaxColorV, gx.MaxColorV, 0, gx.MaxColorV}
|
||||||
ret.Visible = true
|
ret.Visible = true
|
||||||
|
ret.Layer = TriangleL
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRect() *Rect {
|
func NewRect() *Rect {
|
||||||
return &Rect{&gx.DrawableRectangle{
|
ret := &Rect{&gx.DrawableRectangle{
|
||||||
Rectangle: gx.Rectangle{
|
Rectangle: gx.Rectangle{
|
||||||
Transform: gx.Transform{
|
Transform: gx.Transform{
|
||||||
S: gx.Vector{
|
S: gx.Vector{
|
||||||
|
@ -76,7 +91,11 @@ func NewRect() *Rect {
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
},*/
|
},*/
|
||||||
}}
|
},
|
||||||
|
RectL,
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Rect) Update(e *gx.Engine) error {
|
func (r *Rect) Update(e *gx.Engine) error {
|
||||||
|
@ -110,6 +129,7 @@ func NewPlayer() *Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.Images[0] = playerImg
|
ret.Images[0] = playerImg
|
||||||
|
ret.Layer = PlayerL
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
@ -206,6 +226,12 @@ func (p *Player) Update(e *gx.Engine) error {
|
||||||
}
|
}
|
||||||
case ebiten.Key0 :
|
case ebiten.Key0 :
|
||||||
e.Del(p)
|
e.Del(p)
|
||||||
|
case ebiten.KeyB :
|
||||||
|
if p.Layer != PlayerL {
|
||||||
|
p.Layer = PlayerL
|
||||||
|
} else {
|
||||||
|
p.Layer = HighestL
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -251,10 +277,11 @@ func main() {
|
||||||
rect = NewRect()
|
rect = NewRect()
|
||||||
tri = NewTri()
|
tri = NewTri()
|
||||||
|
|
||||||
e.Add(1, &Debug{})
|
e.Add(&Debug{})
|
||||||
e.Add(0, player)
|
e.Add(player)
|
||||||
e.Add(-1, rect)
|
e.Add(rect)
|
||||||
e.Add(100, tri)
|
e.Add(tri)
|
||||||
|
fmt.Println(rect.GetLayer(), player.GetLayer())
|
||||||
|
|
||||||
e.Run()
|
e.Run()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,26 +20,10 @@ type Collision struct {
|
||||||
// to determine if the object collides with anything.
|
// to determine if the object collides with anything.
|
||||||
// Mostly will use the Collide function with some
|
// Mostly will use the Collide function with some
|
||||||
// inner structure field as first argument.
|
// inner structure field as first argument.
|
||||||
|
// The Collide method will be called on collisions.
|
||||||
type Collider interface {
|
type Collider interface {
|
||||||
Collides(Collider) *Collision
|
Collides(Collider) *Collision
|
||||||
}
|
|
||||||
|
|
||||||
// happening collision getting the Collision as
|
|
||||||
// argument.
|
|
||||||
type CollideEventer interface {
|
|
||||||
Collide(*Collision)
|
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
126
src/gx/engine.go
126
src/gx/engine.go
|
@ -3,14 +3,19 @@ package gx
|
||||||
import (
|
import (
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
"github.com/hajimehoshi/ebiten/v2/inpututil"
|
||||||
"github.com/surdeus/godat/src/sparsex"
|
"github.com/mojosa-software/godat/sparsex"
|
||||||
"github.com/surdeus/godat/src/poolx"
|
"github.com/mojosa-software/godat/mapx"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The type represents order of drawing.
|
// 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.
|
// Window configuration type.
|
||||||
type WindowConfig struct {
|
type WindowConfig struct {
|
||||||
|
@ -27,8 +32,7 @@ type WindowConfig struct {
|
||||||
// The main structure that represents current state of [game] engine.
|
// The main structure that represents current state of [game] engine.
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
wcfg *WindowConfig
|
wcfg *WindowConfig
|
||||||
layers *sparsex.Sparse[Layer, *poolx.Pool[Drawer]]
|
objects *mapx.OrderedMap[Object, struct{}]
|
||||||
updaters *poolx.Pool[Updater]
|
|
||||||
lastTime time.Time
|
lastTime time.Time
|
||||||
dt Float
|
dt Float
|
||||||
camera *Camera
|
camera *Camera
|
||||||
|
@ -58,81 +62,59 @@ func NewEngine(
|
||||||
) *Engine {
|
) *Engine {
|
||||||
w := Float(cfg.Width)
|
w := Float(cfg.Width)
|
||||||
h := Float(cfg.Height)
|
h := Float(cfg.Height)
|
||||||
fmt.Println("res:", w, h)
|
|
||||||
return &Engine{
|
return &Engine{
|
||||||
wcfg: cfg,
|
wcfg: cfg,
|
||||||
layers: sparsex.New[
|
|
||||||
Layer,
|
|
||||||
*poolx.Pool[Drawer],
|
|
||||||
](true),
|
|
||||||
camera: &Camera{
|
camera: &Camera{
|
||||||
Transform: Transform{
|
Transform: Transform{
|
||||||
|
// Normal, no distortion.
|
||||||
S: Vector{1, 1},
|
S: Vector{1, 1},
|
||||||
|
// Center.
|
||||||
RA: V(w/2, h/2),
|
RA: V(w/2, h/2),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
updaters: poolx.New[Updater](),
|
objects: mapx.NewOrdered[Object, struct{}](),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new object considering what
|
// Add new object considering what
|
||||||
// interfaces it implements.
|
// 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)
|
starter, ok := b.(Starter)
|
||||||
if ok {
|
if ok {
|
||||||
starter.Start(e)
|
starter.Start(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
updater, ok := b.(Updater)
|
|
||||||
if ok {
|
|
||||||
e.addUpdater(updater)
|
|
||||||
}
|
|
||||||
|
|
||||||
drawer, ok := b.(Drawer)
|
e.objects.Set(object, struct{}{})
|
||||||
if ok {
|
|
||||||
e.addDrawer(l, drawer)
|
return nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete object from Engine.
|
// 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)
|
deleter, ok := b.(Deleter)
|
||||||
if ok {
|
if ok {
|
||||||
deleter.Delete(e, v...)
|
deleter.Delete(e)
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.objects.Del(b)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Engine) addUpdater(b Updater) {
|
|
||||||
e.updaters.Append(b)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *engine) Update() error {
|
func (e *engine) Update() error {
|
||||||
var err error
|
var err error
|
||||||
|
@ -142,8 +124,12 @@ func (e *engine) Update() error {
|
||||||
AppendPressedKeys(e.keys[:0])
|
AppendPressedKeys(e.keys[:0])
|
||||||
|
|
||||||
e.dt = time.Since(e.lastTime).Seconds()
|
e.dt = time.Since(e.lastTime).Seconds()
|
||||||
for p := range eng.updaters.Range() {
|
for object := range e.objects.KeyChan() {
|
||||||
err = p.V.Update(eng)
|
updater, ok := object.(Updater)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = updater.Update(eng)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -155,13 +141,28 @@ func (e *engine) Update() error {
|
||||||
|
|
||||||
func (e *engine) Draw(i *ebiten.Image) {
|
func (e *engine) Draw(i *ebiten.Image) {
|
||||||
eng := (*Engine)(e)
|
eng := (*Engine)(e)
|
||||||
for p := range e.layers.Vals() {
|
layers := sparsex.New[Layer, []Drawer]()
|
||||||
for pj := range p.V.Range() {
|
for object := range eng.objects.KeyChan() {
|
||||||
visibler, ok := pj.V.(Visibler)
|
drawer, ok := object.(Drawer)
|
||||||
if ok && !visibler.IsVisible() {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
pj.V.Draw(eng, i)
|
|
||||||
|
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)
|
ebiten.SetVsyncEnabled(e.wcfg.VSync)
|
||||||
|
|
||||||
e.lastTime = time.Now()
|
e.lastTime = time.Now()
|
||||||
|
fmt.Println(e.objects)
|
||||||
return ebiten.RunGame((*engine)(e))
|
return ebiten.RunGame((*engine)(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/gx/errors.go
Normal file
12
src/gx/errors.go
Normal file
|
@ -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")
|
||||||
|
)
|
||||||
|
|
|
@ -16,32 +16,11 @@ type Color struct {
|
||||||
R, G, B, A ColorV
|
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 (
|
const (
|
||||||
MaxColorV = math.MaxUint32
|
MaxColorV = math.MaxUint32
|
||||||
)
|
)
|
||||||
|
|
||||||
func (v Visibility) IsVisible() bool {
|
|
||||||
return v.Visible
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadImage(input io.Reader) (*Image, error) {
|
func LoadImage(input io.Reader) (*Image, error) {
|
||||||
img, _, err := image.Decode(input)
|
img, _, err := image.Decode(input)
|
||||||
|
|
|
@ -6,7 +6,7 @@ package gx
|
||||||
// the OnUpdate.
|
// the OnUpdate.
|
||||||
// The v value will be get from Add function.
|
// The v value will be get from Add function.
|
||||||
type Starter interface {
|
type Starter interface {
|
||||||
Start(*Engine, ...any)
|
Start(*Engine)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing the interface type
|
// Implementing the interface type
|
||||||
|
@ -23,3 +23,26 @@ type Deleter interface {
|
||||||
Delete(*Engine, ...any)
|
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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue