player and dimension loader with ecs system

This commit is contained in:
Tnze
2022-05-27 00:38:46 +08:00
parent d2f7db9d0d
commit 474d6a229b
34 changed files with 956 additions and 795 deletions

View File

@ -1,39 +0,0 @@
package ecs
type BitSet struct {
// TODO: this is not a bitset, I'm just testing
values map[Index]struct{}
}
func (b BitSet) Set(i Index) (old bool) {
_, old = b.values[i]
b.values[i] = struct{}{}
return
}
func (b BitSet) Unset(i Index) (old bool) {
_, old = b.values[i]
delete(b.values, i)
return
}
func (b BitSet) Contains(i Index) bool {
_, contains := b.values[i]
return contains
}
func (b BitSet) And(other BitSet) (result BitSet) {
result = BitSet{values: make(map[Index]struct{})}
for i := range b.values {
if other.Contains(i) {
result.values[i] = struct{}{}
}
}
return result
}
func (b BitSet) Range(f func(eid Index)) {
for i := range b.values {
f(i)
}
}

View File

@ -1,27 +0,0 @@
package ecs
import "testing"
func Test_common(t *testing.T) {
// W
w := NewWorld()
// C
type pos [2]int
type vel [2]int
Register(w, pos{})
Register(w, vel{})
// E
w.CreateEntity(pos{0, 0})
w.CreateEntity(vel{1, 2})
w.CreateEntity(pos{1, 2}, vel{2, 0})
// S
s1 := FuncSystem(func(p pos) {
t.Log("system 1", p)
})
s2 := FuncSystem(func(p pos, v vel) {
t.Log("system 2", p, v)
})
// Run
s1.Update(w)
s2.Update(w)
}

View File

@ -1,34 +0,0 @@
package ecs
type Index uint32
type Storage interface {
Get(eid Index) any
Insert(eid Index, v any)
Remove(eid Index) any
BitSet() BitSet
}
type HashMapStorage[T any] struct {
keys BitSet
values map[Index]T
}
func NewHashMapStorage[T any]() *HashMapStorage[T] {
return &HashMapStorage[T]{
keys: BitSet{values: make(map[Index]struct{})},
values: make(map[Index]T),
}
}
func (h *HashMapStorage[T]) Get(eid Index) any { return h.values[eid] }
func (h *HashMapStorage[T]) Insert(eid Index, v any) {
h.keys.Set(eid)
h.values[eid] = v.(T)
}
func (h *HashMapStorage[T]) Remove(eid Index) any {
h.keys.Unset(eid)
v := h.values[eid]
delete(h.values, eid)
return v
}
func (h *HashMapStorage[T]) BitSet() BitSet { return h.keys }

View File

@ -1,49 +0,0 @@
package ecs
import "reflect"
type System interface {
Update(w *World)
}
type funcsystem struct {
update reflect.Value
args func(w *World) []Storage
}
func FuncSystem(F any) System {
f := reflect.ValueOf(F)
in := f.Type().NumIn()
argTypes := make([]reflect.Type, in)
for i := 0; i < in; i++ {
argTypes[i] = f.Type().In(i)
}
return &funcsystem{
update: f,
args: func(w *World) (args []Storage) {
args = make([]Storage, in)
for i := 0; i < in; i++ {
args[i] = w.GetResourceRaw(argTypes[i]).(Storage)
}
return
},
}
}
func (f *funcsystem) Update(w *World) {
storages := f.args(w)
if len(storages) == 0 {
return
}
eids := storages[0].BitSet()
for _, v := range storages[1:] {
eids = eids.And(v.BitSet())
}
args := make([]reflect.Value, len(storages))
eids.Range(func(eid Index) {
for i := range args {
args[i] = reflect.ValueOf(storages[i].Get(eid))
}
f.update.Call(args)
})
}

View File

@ -1,58 +0,0 @@
package ecs
import (
"reflect"
"sync/atomic"
)
type World struct {
resources map[reflect.Type]any
maxEID Index
}
func NewWorld() *World {
return &World{resources: make(map[reflect.Type]any)}
}
func (w *World) Insert(resource any) {
t := reflect.ValueOf(resource).Type()
w.resources[t] = resource
}
func (w *World) Remove(resource any) any {
t := reflect.ValueOf(resource).Type()
resource = w.resources[t]
delete(w.resources, t)
return resource
}
func (w *World) GetResource(resource any) any {
if resource == nil {
return nil
}
t := reflect.ValueOf(resource).Type()
v, _ := w.resources[t]
return v
}
func (w *World) GetResourceRaw(t reflect.Type) any {
v, _ := w.resources[t]
return v
}
func Register[T any](w *World, component T) {
t := reflect.TypeOf(component)
s := NewHashMapStorage[T]()
w.resources[t] = s
}
func (w *World) CreateEntity(components ...any) (i Index) {
i = Index(atomic.AddUint32((*uint32)(&w.maxEID), 1))
for _, c := range components {
v := reflect.ValueOf(c)
t := v.Type()
storage := w.resources[t].(Storage)
storage.Insert(w.maxEID, c)
}
return
}