mirror of
https://github.com/bloeys/nmage.git
synced 2025-12-29 13:28:20 +00:00
Generational indices+get/free entity+free list
This commit is contained in:
@ -1,5 +1,19 @@
|
||||
package entity
|
||||
|
||||
type EntityFlag byte
|
||||
|
||||
const (
|
||||
EntityFlag_Unknown EntityFlag = 0
|
||||
EntityFlag_Dead EntityFlag = 1 << (iota - 1)
|
||||
EntityFlag_Alive
|
||||
)
|
||||
|
||||
const (
|
||||
GenerationShiftBits = 64 - 8
|
||||
FlagsShiftBits = 64 - 16
|
||||
IndexBitMask = 0x00_00_FFFF_FFFF_FFFF
|
||||
)
|
||||
|
||||
type Entity struct {
|
||||
|
||||
// Byte 1: Generation; Byte 2: Flags; Bytes 3-8: Index
|
||||
@ -7,6 +21,26 @@ type Entity struct {
|
||||
Comps []Comp
|
||||
}
|
||||
|
||||
func GetGeneration(id uint64) byte {
|
||||
return byte(id >> GenerationShiftBits)
|
||||
}
|
||||
|
||||
func GetFlags(id uint64) byte {
|
||||
return byte(id >> FlagsShiftBits)
|
||||
}
|
||||
|
||||
func GetIndex(id uint64) uint64 {
|
||||
return id & IndexBitMask
|
||||
}
|
||||
|
||||
func (e *Entity) HasFlag(ef EntityFlag) bool {
|
||||
return GetFlags(e.ID)&byte(ef) > 0
|
||||
}
|
||||
|
||||
func NewEntityId(generation, flags byte, index uint64) uint64 {
|
||||
return index | (uint64(generation) << GenerationShiftBits) | (uint64(flags) << FlagsShiftBits)
|
||||
}
|
||||
|
||||
type Comp interface {
|
||||
Name() string
|
||||
}
|
||||
|
||||
@ -1,30 +1,89 @@
|
||||
package entity
|
||||
|
||||
import "github.com/bloeys/nmage/assert"
|
||||
import (
|
||||
"github.com/bloeys/nmage/assert"
|
||||
)
|
||||
|
||||
type freeListitem struct {
|
||||
EntityIndex uint64
|
||||
nextFree *freeListitem
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
EntityCount uint64
|
||||
Entities []Entity
|
||||
FreeList *freeListitem
|
||||
}
|
||||
|
||||
func (r *Registry) NewEntity() *Entity {
|
||||
|
||||
assert.T(r.EntityCount < uint64(len(r.Entities)), "Can not add more entities to registry because it is full")
|
||||
|
||||
entityToUseIndex := uint64(0)
|
||||
var entityToUse *Entity = nil
|
||||
|
||||
if r.FreeList != nil {
|
||||
|
||||
entityToUseIndex = r.FreeList.EntityIndex
|
||||
entityToUse = &r.Entities[entityToUseIndex]
|
||||
r.FreeList = r.FreeList.nextFree
|
||||
} else {
|
||||
|
||||
for i := 0; i < len(r.Entities); i++ {
|
||||
|
||||
// @TODO: Implement generational indices
|
||||
e := &r.Entities[i]
|
||||
if e.ID == 0 {
|
||||
r.EntityCount++
|
||||
e.ID = uint64(i) + 1
|
||||
if GetFlags(e.ID) != byte(EntityFlag_Unknown) && !e.HasFlag(EntityFlag_Dead) {
|
||||
continue
|
||||
}
|
||||
|
||||
entityToUse = e
|
||||
entityToUseIndex = uint64(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if entityToUse == nil {
|
||||
panic("failed to create new entity because we did not find a free spot in the registry. Why did the assert not go off?")
|
||||
}
|
||||
|
||||
r.EntityCount++
|
||||
entityToUse.ID = NewEntityId(GetGeneration(entityToUse.ID)+1, byte(EntityFlag_Alive), entityToUseIndex)
|
||||
assert.T(entityToUse.ID != 0, "Entity ID must not be zero")
|
||||
return entityToUse
|
||||
}
|
||||
|
||||
func (r *Registry) GetEntity(id uint64) *Entity {
|
||||
|
||||
index := GetIndex(id)
|
||||
gen := GetGeneration(id)
|
||||
|
||||
e := &r.Entities[index]
|
||||
eGen := GetGeneration(e.ID)
|
||||
|
||||
if gen != eGen {
|
||||
return nil
|
||||
}
|
||||
|
||||
assert.T(e.ID != 0, "Entity ID must not be zero")
|
||||
return e
|
||||
}
|
||||
|
||||
func (r *Registry) FreeEntity(id uint64) {
|
||||
|
||||
e := r.GetEntity(id)
|
||||
if e == nil {
|
||||
return
|
||||
}
|
||||
|
||||
panic("failed to create new entity because we did not find a free spot in the registry. Why did the assert not go off?")
|
||||
r.EntityCount--
|
||||
eIndex := GetIndex(e.ID)
|
||||
|
||||
e.Comps = []Comp{}
|
||||
e.ID = NewEntityId(GetGeneration(e.ID), byte(EntityFlag_Dead), eIndex)
|
||||
|
||||
r.FreeList = &freeListitem{
|
||||
EntityIndex: eIndex,
|
||||
nextFree: r.FreeList,
|
||||
}
|
||||
}
|
||||
|
||||
func NewRegistry(size uint32) *Registry {
|
||||
|
||||
64
main.go
64
main.go
@ -8,7 +8,9 @@ import (
|
||||
"github.com/bloeys/nmage/assets"
|
||||
"github.com/bloeys/nmage/camera"
|
||||
"github.com/bloeys/nmage/engine"
|
||||
"github.com/bloeys/nmage/entity"
|
||||
"github.com/bloeys/nmage/input"
|
||||
"github.com/bloeys/nmage/level"
|
||||
"github.com/bloeys/nmage/logging"
|
||||
"github.com/bloeys/nmage/materials"
|
||||
"github.com/bloeys/nmage/meshes"
|
||||
@ -52,45 +54,45 @@ type OurGame struct {
|
||||
ImGUIInfo nmageimgui.ImguiInfo
|
||||
}
|
||||
|
||||
// type TransformComp struct {
|
||||
// Pos *gglm.Vec3
|
||||
// Rot *gglm.Quat
|
||||
// Scale *gglm.Vec3
|
||||
// }
|
||||
type TransformComp struct {
|
||||
Pos *gglm.Vec3
|
||||
Rot *gglm.Quat
|
||||
Scale *gglm.Vec3
|
||||
}
|
||||
|
||||
// func (t TransformComp) Name() string {
|
||||
// return "Transform Component"
|
||||
// }
|
||||
func (t TransformComp) Name() string {
|
||||
return "Transform Component"
|
||||
}
|
||||
|
||||
// func Test() {
|
||||
func Test() {
|
||||
|
||||
// lvl := level.NewLevel("test level", 1000)
|
||||
// e := lvl.Registry.NewEntity()
|
||||
lvl := level.NewLevel("test level", 1000)
|
||||
e1 := lvl.Registry.NewEntity()
|
||||
|
||||
// trComp := entity.GetComp[*TransformComp](e)
|
||||
// fmt.Println("Got comp 1:", trComp)
|
||||
trComp := entity.GetComp[*TransformComp](e1)
|
||||
fmt.Println("Got comp 1:", trComp)
|
||||
|
||||
// e.Comps = append(e.Comps, &TransformComp{
|
||||
// Pos: gglm.NewVec3(0, 0, 0),
|
||||
// Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||
// Scale: gglm.NewVec3(0, 0, 0),
|
||||
// }, &TransformComp{
|
||||
// Pos: gglm.NewVec3(0, 0, 0),
|
||||
// Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||
// Scale: gglm.NewVec3(1, 1, 1),
|
||||
// })
|
||||
e1.Comps = append(e1.Comps, &TransformComp{
|
||||
Pos: gglm.NewVec3(0, 0, 0),
|
||||
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||
Scale: gglm.NewVec3(0, 0, 0),
|
||||
}, &TransformComp{
|
||||
Pos: gglm.NewVec3(0, 0, 0),
|
||||
Rot: gglm.NewQuatEulerXYZ(0, 0, 0),
|
||||
Scale: gglm.NewVec3(1, 1, 1),
|
||||
})
|
||||
|
||||
// trComp = entity.GetComp[*TransformComp](e)
|
||||
// fmt.Println("Got comp 2:", trComp)
|
||||
trComp = entity.GetComp[*TransformComp](e1)
|
||||
fmt.Println("Got comp 2:", trComp)
|
||||
|
||||
// trComps := entity.GetAllCompOfType[*TransformComp](e)
|
||||
// fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
|
||||
trComps := entity.GetAllCompOfType[*TransformComp](e1)
|
||||
fmt.Printf("Got comp 3: %+v, %+v\n", trComps[0], trComps[1])
|
||||
|
||||
// fmt.Printf("Entity: %+v\n", e)
|
||||
// fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
// fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
// fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
// }
|
||||
fmt.Printf("Entity: %+v\n", e1)
|
||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
fmt.Printf("Entity: %+v\n", lvl.Registry.NewEntity())
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user