mirror of
https://github.com/mvvasilev/last_light.git
synced 2025-04-19 12:49:52 +03:00
maybe rewrite with ecs, idk
This commit is contained in:
parent
3c83d97a34
commit
53483ac870
15 changed files with 416 additions and 181 deletions
73
engine/ecs/component_type.go
Normal file
73
engine/ecs/component_type.go
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
package ecs
|
||||||
|
|
||||||
|
/* ================== ComponentType =================== */
|
||||||
|
|
||||||
|
type ComponentType uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
ComponentType_0 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_1 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000000001
|
||||||
|
ComponentType_2 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000000010
|
||||||
|
ComponentType_3 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000000100
|
||||||
|
ComponentType_4 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000001000
|
||||||
|
ComponentType_5 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000010000
|
||||||
|
ComponentType_6 ComponentType = 0b0000000000000000000000000000000000000000000000000000000000100000
|
||||||
|
ComponentType_7 ComponentType = 0b0000000000000000000000000000000000000000000000000000000001000000
|
||||||
|
ComponentType_8 ComponentType = 0b0000000000000000000000000000000000000000000000000000000010000000
|
||||||
|
ComponentType_9 ComponentType = 0b0000000000000000000000000000000000000000000000000000000100000000
|
||||||
|
ComponentType_10 ComponentType = 0b0000000000000000000000000000000000000000000000000000001000000000
|
||||||
|
ComponentType_11 ComponentType = 0b0000000000000000000000000000000000000000000000000000010000000000
|
||||||
|
ComponentType_12 ComponentType = 0b0000000000000000000000000000000000000000000000000000100000000000
|
||||||
|
ComponentType_13 ComponentType = 0b0000000000000000000000000000000000000000000000000001000000000000
|
||||||
|
ComponentType_14 ComponentType = 0b0000000000000000000000000000000000000000000000000010000000000000
|
||||||
|
ComponentType_15 ComponentType = 0b0000000000000000000000000000000000000000000000000100000000000000
|
||||||
|
ComponentType_16 ComponentType = 0b0000000000000000000000000000000000000000000000001000000000000000
|
||||||
|
ComponentType_17 ComponentType = 0b0000000000000000000000000000000000000000000000010000000000000000
|
||||||
|
ComponentType_18 ComponentType = 0b0000000000000000000000000000000000000000000000100000000000000000
|
||||||
|
ComponentType_19 ComponentType = 0b0000000000000000000000000000000000000000000001000000000000000000
|
||||||
|
ComponentType_20 ComponentType = 0b0000000000000000000000000000000000000000000010000000000000000000
|
||||||
|
ComponentType_21 ComponentType = 0b0000000000000000000000000000000000000000000100000000000000000000
|
||||||
|
ComponentType_22 ComponentType = 0b0000000000000000000000000000000000000000001000000000000000000000
|
||||||
|
ComponentType_23 ComponentType = 0b0000000000000000000000000000000000000000010000000000000000000000
|
||||||
|
ComponentType_24 ComponentType = 0b0000000000000000000000000000000000000000100000000000000000000000
|
||||||
|
ComponentType_25 ComponentType = 0b0000000000000000000000000000000000000001000000000000000000000000
|
||||||
|
ComponentType_26 ComponentType = 0b0000000000000000000000000000000000000010000000000000000000000000
|
||||||
|
ComponentType_27 ComponentType = 0b0000000000000000000000000000000000000100000000000000000000000000
|
||||||
|
ComponentType_28 ComponentType = 0b0000000000000000000000000000000000001000000000000000000000000000
|
||||||
|
ComponentType_29 ComponentType = 0b0000000000000000000000000000000000010000000000000000000000000000
|
||||||
|
ComponentType_30 ComponentType = 0b0000000000000000000000000000000000100000000000000000000000000000
|
||||||
|
ComponentType_31 ComponentType = 0b0000000000000000000000000000000001000000000000000000000000000000
|
||||||
|
ComponentType_32 ComponentType = 0b0000000000000000000000000000000010000000000000000000000000000000
|
||||||
|
ComponentType_33 ComponentType = 0b0000000000000000000000000000000100000000000000000000000000000000
|
||||||
|
ComponentType_34 ComponentType = 0b0000000000000000000000000000001000000000000000000000000000000000
|
||||||
|
ComponentType_35 ComponentType = 0b0000000000000000000000000000010000000000000000000000000000000000
|
||||||
|
ComponentType_36 ComponentType = 0b0000000000000000000000000000100000000000000000000000000000000000
|
||||||
|
ComponentType_37 ComponentType = 0b0000000000000000000000000001000000000000000000000000000000000000
|
||||||
|
ComponentType_38 ComponentType = 0b0000000000000000000000000010000000000000000000000000000000000000
|
||||||
|
ComponentType_39 ComponentType = 0b0000000000000000000000000100000000000000000000000000000000000000
|
||||||
|
ComponentType_40 ComponentType = 0b0000000000000000000000001000000000000000000000000000000000000000
|
||||||
|
ComponentType_41 ComponentType = 0b0000000000000000000000010000000000000000000000000000000000000000
|
||||||
|
ComponentType_42 ComponentType = 0b0000000000000000000000100000000000000000000000000000000000000000
|
||||||
|
ComponentType_43 ComponentType = 0b0000000000000000000001000000000000000000000000000000000000000000
|
||||||
|
ComponentType_44 ComponentType = 0b0000000000000000000010000000000000000000000000000000000000000000
|
||||||
|
ComponentType_45 ComponentType = 0b0000000000000000000100000000000000000000000000000000000000000000
|
||||||
|
ComponentType_46 ComponentType = 0b0000000000000000001000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_47 ComponentType = 0b0000000000000000010000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_48 ComponentType = 0b0000000000000000100000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_49 ComponentType = 0b0000000000000001000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_50 ComponentType = 0b0000000000000010000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_51 ComponentType = 0b0000000000000100000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_52 ComponentType = 0b0000000000001000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_53 ComponentType = 0b0000000000010000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_54 ComponentType = 0b0000000000100000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_55 ComponentType = 0b0000000001000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_56 ComponentType = 0b0000000010000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_57 ComponentType = 0b0000000100000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_58 ComponentType = 0b0000001000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_59 ComponentType = 0b0000010000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_60 ComponentType = 0b0000100000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_61 ComponentType = 0b0001000000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_62 ComponentType = 0b0010000000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_63 ComponentType = 0b0100000000000000000000000000000000000000000000000000000000000000
|
||||||
|
ComponentType_64 ComponentType = 0b1000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
)
|
|
@ -1,10 +1,9 @@
|
||||||
package ecs
|
package ecs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/* ===================== ECSError ===================== */
|
/* ===================== ECSError ===================== */
|
||||||
|
@ -25,30 +24,8 @@ func (e *ECSError) Error() string {
|
||||||
|
|
||||||
/* ==================================================== */
|
/* ==================================================== */
|
||||||
|
|
||||||
/* ================== ComponentType =================== */
|
|
||||||
|
|
||||||
type ComponentType uint64
|
|
||||||
|
|
||||||
func TypeFrom(powerOf2 uint64) (ComponentType, *ECSError) {
|
|
||||||
if powerOf2 > 63 {
|
|
||||||
return 0, ecsError("Failure: Provided number is too high ( component types must be represented by a power of 2, up to 63 )")
|
|
||||||
}
|
|
||||||
|
|
||||||
t := uint64(0)
|
|
||||||
|
|
||||||
for i := range powerOf2 {
|
|
||||||
t *= i
|
|
||||||
}
|
|
||||||
|
|
||||||
return ComponentType(t), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================================================== */
|
|
||||||
|
|
||||||
/* ====================== Types ======================= */
|
/* ====================== Types ======================= */
|
||||||
|
|
||||||
type SystemOrder uint8
|
|
||||||
|
|
||||||
type EntityId uint64
|
type EntityId uint64
|
||||||
|
|
||||||
type ComponentMask uint64
|
type ComponentMask uint64
|
||||||
|
@ -90,7 +67,6 @@ func (c ComponentMask) ContainsMultiple(ids ComponentMask) bool {
|
||||||
type System interface {
|
type System interface {
|
||||||
Name() string
|
Name() string
|
||||||
Order() int
|
Order() int
|
||||||
Input(world *World, e tcell.EventKey)
|
|
||||||
Tick(world *World, deltaTime int64)
|
Tick(world *World, deltaTime int64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,17 +92,11 @@ func CreateRandomEntityId() EntityId {
|
||||||
return EntityId(time.Now().UnixNano())
|
return EntityId(time.Now().UnixNano())
|
||||||
}
|
}
|
||||||
|
|
||||||
func createEntity(components ...Component) *BasicEntity {
|
func createEntity() *BasicEntity {
|
||||||
ent := &BasicEntity{
|
return &BasicEntity{
|
||||||
id: CreateRandomEntityId(),
|
id: CreateRandomEntityId(),
|
||||||
components: make(map[ComponentType]Component, 0),
|
components: make(map[ComponentType]Component, 0),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range components {
|
|
||||||
ent.components[c.Type()] = c
|
|
||||||
}
|
|
||||||
|
|
||||||
return ent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ent *BasicEntity) Id() EntityId {
|
func (ent *BasicEntity) Id() EntityId {
|
||||||
|
@ -192,6 +162,7 @@ type World struct {
|
||||||
|
|
||||||
entities map[EntityId]*BasicEntity
|
entities map[EntityId]*BasicEntity
|
||||||
components map[ComponentType][]Component
|
components map[ComponentType][]Component
|
||||||
|
singletons map[ComponentType]Component
|
||||||
systems []System
|
systems []System
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,6 +171,8 @@ func CreateWorld() *World {
|
||||||
entities: make(map[EntityId]*BasicEntity, 0),
|
entities: make(map[EntityId]*BasicEntity, 0),
|
||||||
systems: make([]System, 0),
|
systems: make([]System, 0),
|
||||||
components: make(map[ComponentType][]Component, 0),
|
components: make(map[ComponentType][]Component, 0),
|
||||||
|
registeredComponentNames: make(map[ComponentType]string, 0),
|
||||||
|
singletons: make(map[ComponentType]Component, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +198,22 @@ func (w *World) QueryComponents(componentIds ...ComponentType) (components map[C
|
||||||
return comps, nil
|
return comps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *World) FetchSingletonComponent(componentId ComponentType) (component Component, err *ECSError) {
|
||||||
|
comp := w.singletons[componentId]
|
||||||
|
|
||||||
|
if comp == nil {
|
||||||
|
componentName := w.registeredComponentNames[componentId]
|
||||||
|
|
||||||
|
return nil, ecsError(fmt.Sprintf("Failure: No singleton component of type %v could be found", componentName))
|
||||||
|
}
|
||||||
|
|
||||||
|
return comp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *World) AddSingletonComponent(component Component) {
|
||||||
|
w.singletons[component.Type()] = component
|
||||||
|
}
|
||||||
|
|
||||||
func (w *World) RegisterComponentType(t ComponentType, name string) (err *ECSError) {
|
func (w *World) RegisterComponentType(t ComponentType, name string) (err *ECSError) {
|
||||||
if w.registeredComponentTypes.Contains(t) {
|
if w.registeredComponentTypes.Contains(t) {
|
||||||
return ecsError("Failure: ComponentType conflict, another component already exists with that type number")
|
return ecsError("Failure: ComponentType conflict, another component already exists with that type number")
|
||||||
|
@ -268,19 +257,21 @@ func (w *World) AddComponentToEntity(ent *BasicEntity, comp Component) (modified
|
||||||
return ent, nil
|
return ent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *World) AddSystem(s System) (err *ECSError) {
|
func (w *World) AddSystem(s System) {
|
||||||
w.systems = append(w.systems, s)
|
w.systems = append(w.systems, s)
|
||||||
|
|
||||||
slices.SortFunc(w.systems, func(a System, b System) int { return a.Order() - b.Order() })
|
slices.SortFunc(w.systems, func(a System, b System) int { return a.Order() - b.Order() })
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *World) CreateEntity(comps ...Component) *BasicEntity {
|
func (w *World) CreateEntity(comps ...Component) *BasicEntity {
|
||||||
ent := createEntity(comps...)
|
ent := createEntity()
|
||||||
|
|
||||||
w.entities[ent.Id()] = ent
|
w.entities[ent.Id()] = ent
|
||||||
|
|
||||||
|
for _, c := range comps {
|
||||||
|
w.AddComponentToEntity(ent, c)
|
||||||
|
}
|
||||||
|
|
||||||
return ent
|
return ent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,10 +295,4 @@ func (w *World) Tick(dt int64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *World) Input(e tcell.EventKey) {
|
|
||||||
for _, s := range w.systems {
|
|
||||||
s.Input(w, e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ==================================================== */
|
/* ==================================================== */
|
||||||
|
|
|
@ -3,8 +3,6 @@ package ecs
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_ecsError(t *testing.T) {
|
func Test_ecsError(t *testing.T) {
|
||||||
|
@ -171,9 +169,8 @@ func TestCreateRandomEntityId(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_createEntity(t *testing.T) {
|
func Test_createEntity(t *testing.T) {
|
||||||
type args struct {
|
type args struct{}
|
||||||
components []Component
|
|
||||||
}
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
args args
|
args args
|
||||||
|
@ -183,7 +180,7 @@ func Test_createEntity(t *testing.T) {
|
||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
if got := createEntity(tt.args.components...); !reflect.DeepEqual(got, tt.want) {
|
if got := createEntity(); !reflect.DeepEqual(got, tt.want) {
|
||||||
t.Errorf("createEntity() = %v, want %v", got, tt.want)
|
t.Errorf("createEntity() = %v, want %v", got, tt.want)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -535,41 +532,6 @@ func TestWorld_AddComponentToEntity(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWorld_AddSystem(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
registeredComponentTypes ComponentMask
|
|
||||||
registeredComponentNames map[ComponentType]string
|
|
||||||
entities map[EntityId]*BasicEntity
|
|
||||||
components map[ComponentType][]Component
|
|
||||||
systems []System
|
|
||||||
}
|
|
||||||
type args struct {
|
|
||||||
s System
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
args args
|
|
||||||
wantErr *ECSError
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
w := &World{
|
|
||||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
|
||||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
|
||||||
entities: tt.fields.entities,
|
|
||||||
components: tt.fields.components,
|
|
||||||
systems: tt.fields.systems,
|
|
||||||
}
|
|
||||||
if gotErr := w.AddSystem(tt.args.s); !reflect.DeepEqual(gotErr, tt.wantErr) {
|
|
||||||
t.Errorf("World.AddSystem() = %v, want %v", gotErr, tt.wantErr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWorld_CreateEntity(t *testing.T) {
|
func TestWorld_CreateEntity(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
registeredComponentTypes ComponentMask
|
registeredComponentTypes ComponentMask
|
||||||
|
@ -709,38 +671,6 @@ func TestWorld_Tick(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWorld_Input(t *testing.T) {
|
|
||||||
type fields struct {
|
|
||||||
registeredComponentTypes ComponentMask
|
|
||||||
registeredComponentNames map[ComponentType]string
|
|
||||||
entities map[EntityId]*BasicEntity
|
|
||||||
components map[ComponentType][]Component
|
|
||||||
systems []System
|
|
||||||
}
|
|
||||||
type args struct {
|
|
||||||
e tcell.EventKey
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
fields fields
|
|
||||||
args args
|
|
||||||
}{
|
|
||||||
// TODO: Add test cases.
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
w := &World{
|
|
||||||
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
|
||||||
registeredComponentNames: tt.fields.registeredComponentNames,
|
|
||||||
entities: tt.fields.entities,
|
|
||||||
components: tt.fields.components,
|
|
||||||
systems: tt.fields.systems,
|
|
||||||
}
|
|
||||||
w.Input(tt.args.e)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWorld_FindEntitiesWithComponents(t *testing.T) {
|
func TestWorld_FindEntitiesWithComponents(t *testing.T) {
|
||||||
type fields struct {
|
type fields struct {
|
||||||
registeredComponentTypes ComponentMask
|
registeredComponentTypes ComponentMask
|
||||||
|
@ -775,3 +705,35 @@ func TestWorld_FindEntitiesWithComponents(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWorld_AddSystem(t *testing.T) {
|
||||||
|
type fields struct {
|
||||||
|
registeredComponentTypes ComponentMask
|
||||||
|
registeredComponentNames map[ComponentType]string
|
||||||
|
entities map[EntityId]*BasicEntity
|
||||||
|
components map[ComponentType][]Component
|
||||||
|
systems []System
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
s System
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
}{
|
||||||
|
// TODO: Add test cases.
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
w := &World{
|
||||||
|
registeredComponentTypes: tt.fields.registeredComponentTypes,
|
||||||
|
registeredComponentNames: tt.fields.registeredComponentNames,
|
||||||
|
entities: tt.fields.entities,
|
||||||
|
components: tt.fields.components,
|
||||||
|
systems: tt.fields.systems,
|
||||||
|
}
|
||||||
|
w.AddSystem(tt.args.s)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
22
engine/event.go
Normal file
22
engine/event.go
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package engine
|
||||||
|
|
||||||
|
import "github.com/gdamore/tcell/v2"
|
||||||
|
|
||||||
|
type Event interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type InputEvent struct {
|
||||||
|
tcellEvent *tcell.EventKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *InputEvent) TcellEvent() *tcell.EventKey {
|
||||||
|
return e.tcellEvent
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResizeEvent struct {
|
||||||
|
tcellEvent *tcell.EventResize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ResizeEvent) TcellEvent() *tcell.EventResize {
|
||||||
|
return e.tcellEvent
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
|
@ -40,16 +39,15 @@ func Multidraw(drawables ...Drawable) []Drawable {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenderContext struct {
|
type EngineContext struct {
|
||||||
screen tcell.Screen
|
screen tcell.Screen
|
||||||
view *views.ViewPort
|
view *views.ViewPort
|
||||||
|
|
||||||
events chan tcell.Event
|
events chan tcell.Event
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
drawables chan Drawable
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateRenderContext() (*RenderContext, error) {
|
func InitEngine() (*EngineContext, error) {
|
||||||
screen, sErr := tcell.NewScreen()
|
screen, sErr := tcell.NewScreen()
|
||||||
|
|
||||||
if sErr != nil {
|
if sErr != nil {
|
||||||
|
@ -87,22 +85,21 @@ func CreateRenderContext() (*RenderContext, error) {
|
||||||
|
|
||||||
go screen.ChannelEvents(events, quit)
|
go screen.ChannelEvents(events, quit)
|
||||||
|
|
||||||
context := new(RenderContext)
|
context := new(EngineContext)
|
||||||
|
|
||||||
context.screen = screen
|
context.screen = screen
|
||||||
context.events = events
|
context.events = events
|
||||||
context.quit = quit
|
context.quit = quit
|
||||||
context.view = view
|
context.view = view
|
||||||
context.drawables = make(chan Drawable)
|
|
||||||
|
|
||||||
return context, nil
|
return context, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RenderContext) Stop() {
|
func (c *EngineContext) Stop() {
|
||||||
c.screen.Fini()
|
c.screen.Fini()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RenderContext) CollectInputEvents() []*tcell.EventKey {
|
func (c *EngineContext) CollectInputEvents() []*tcell.EventKey {
|
||||||
events := make([]tcell.Event, len(c.events))
|
events := make([]tcell.Event, len(c.events))
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -118,20 +115,14 @@ func (c *RenderContext) CollectInputEvents() []*tcell.EventKey {
|
||||||
case *tcell.EventKey:
|
case *tcell.EventKey:
|
||||||
inputEvents = append(inputEvents, ev)
|
inputEvents = append(inputEvents, ev)
|
||||||
case *tcell.EventResize:
|
case *tcell.EventResize:
|
||||||
c.onResize(ev)
|
c.Resize(ev.Size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return inputEvents
|
return inputEvents
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RenderContext) DrawableQueue() chan Drawable {
|
func (c *EngineContext) Resize(width, height int) {
|
||||||
return c.drawables
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *RenderContext) onResize(ev *tcell.EventResize) {
|
|
||||||
width, height := ev.Size()
|
|
||||||
|
|
||||||
c.screen.Clear()
|
c.screen.Clear()
|
||||||
|
|
||||||
c.view.Resize(
|
c.view.Resize(
|
||||||
|
@ -144,20 +135,16 @@ func (c *RenderContext) onResize(ev *tcell.EventResize) {
|
||||||
c.screen.Sync()
|
c.screen.Sync()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *RenderContext) Draw(deltaTime int64, drawables []Drawable) {
|
func (c *EngineContext) Clear() {
|
||||||
fps := 1_000_000 / deltaTime
|
|
||||||
|
|
||||||
c.view.Clear()
|
c.view.Clear()
|
||||||
|
}
|
||||||
|
|
||||||
msPerFrame := float32(fps) / 1000.0
|
func (c *EngineContext) Show() {
|
||||||
|
c.screen.Show()
|
||||||
fpsText := CreateText(0, 0, 16, 1, fmt.Sprintf("%vms", msPerFrame), tcell.StyleDefault)
|
}
|
||||||
|
|
||||||
|
func (c *EngineContext) Draw(drawables []Drawable) {
|
||||||
for _, d := range drawables {
|
for _, d := range drawables {
|
||||||
d.Draw(c.view)
|
d.Draw(c.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
fpsText.Draw(c.view)
|
|
||||||
|
|
||||||
c.screen.Show()
|
|
||||||
}
|
}
|
||||||
|
|
17
game/component/drawables.go
Normal file
17
game/component/drawables.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package component
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mvvasilev/last_light/engine"
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ComponentType_RenderableComponent = ecs.ComponentType_0
|
||||||
|
|
||||||
|
type DrawablesComponent struct {
|
||||||
|
Priority int
|
||||||
|
Drawables []engine.Drawable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rc *DrawablesComponent) Type() ecs.ComponentType {
|
||||||
|
return ComponentType_RenderableComponent
|
||||||
|
}
|
16
game/component/game_state.go
Normal file
16
game/component/game_state.go
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
package component
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
"mvvasilev/last_light/game/state"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ComponentType_GameStateComponent = ecs.ComponentType_2
|
||||||
|
|
||||||
|
type GameStateComponent struct {
|
||||||
|
GameState *state.GameState
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gsc *GameStateComponent) Type() ecs.ComponentType {
|
||||||
|
return ComponentType_GameStateComponent
|
||||||
|
}
|
17
game/component/input.go
Normal file
17
game/component/input.go
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
package component
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ComponentType_InputComponent = ecs.ComponentType_1
|
||||||
|
|
||||||
|
type InputComponent struct {
|
||||||
|
KeyEvents []*tcell.EventKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ic *InputComponent) Type() ecs.ComponentType {
|
||||||
|
return ComponentType_InputComponent
|
||||||
|
}
|
|
@ -1,60 +1,30 @@
|
||||||
package game
|
package game
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
|
||||||
"mvvasilev/last_light/engine"
|
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const TICK_RATE int64 = 50 // tick every 50ms ( 20 ticks per second )
|
const TICK_RATE int64 = 50 // tick every 50ms ( 20 ticks per second )
|
||||||
|
|
||||||
type GameContext struct {
|
type GameContext struct {
|
||||||
renderContext *engine.RenderContext
|
world *GameWorld
|
||||||
|
|
||||||
game *Game
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateGameContext() *GameContext {
|
func CreateGameContext() *GameContext {
|
||||||
gc := new(GameContext)
|
gc := new(GameContext)
|
||||||
|
|
||||||
rc, err := engine.CreateRenderContext()
|
gc.world = CreateGameWorld()
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("%~v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
gc.renderContext = rc
|
|
||||||
gc.game = CreateGame()
|
|
||||||
|
|
||||||
return gc
|
return gc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *GameContext) Run() {
|
func (gc *GameContext) Run() {
|
||||||
lastLoop := time.Now()
|
lastLoop := time.Now()
|
||||||
lastTick := time.Now()
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
deltaTime := 1 + time.Since(lastLoop).Microseconds()
|
deltaTime := 1 + time.Since(lastLoop).Milliseconds()
|
||||||
lastLoop = time.Now()
|
lastLoop = time.Now()
|
||||||
|
|
||||||
for _, e := range gc.renderContext.CollectInputEvents() {
|
gc.world.Tick(deltaTime)
|
||||||
gc.game.Input(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if time.Since(lastTick).Milliseconds() >= TICK_RATE {
|
|
||||||
stop := !gc.game.Tick(deltaTime)
|
|
||||||
|
|
||||||
if stop {
|
|
||||||
gc.renderContext.Stop()
|
|
||||||
os.Exit(0)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
lastTick = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
drawables := gc.game.CollectDrawables()
|
|
||||||
gc.renderContext.Draw(deltaTime, drawables)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
52
game/game_world.go
Normal file
52
game/game_world.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"mvvasilev/last_light/engine"
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
"mvvasilev/last_light/game/component"
|
||||||
|
"mvvasilev/last_light/game/system"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GameWorld struct {
|
||||||
|
ecs *ecs.World
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateGameWorld() *GameWorld {
|
||||||
|
world := &GameWorld{
|
||||||
|
ecs: ecs.CreateWorld(),
|
||||||
|
}
|
||||||
|
|
||||||
|
engineContext, err := engine.InitEngine()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// TODO: error logs
|
||||||
|
log.Fatalf("%~v", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
world.ecs.RegisterComponentType(component.ComponentType_RenderableComponent, "RenderableComponent")
|
||||||
|
world.ecs.RegisterComponentType(component.ComponentType_InputComponent, "InputComponent")
|
||||||
|
world.ecs.RegisterComponentType(component.ComponentType_GameStateComponent, "GameStateComponent")
|
||||||
|
|
||||||
|
world.ecs.AddSystem(system.CreateRenderingSystem(engineContext))
|
||||||
|
world.ecs.AddSystem(system.CreateInputSystem(engineContext))
|
||||||
|
world.ecs.AddSystem(system.CreateGameStateSystem())
|
||||||
|
|
||||||
|
world.ecs.AddSingletonComponent(&component.InputComponent{})
|
||||||
|
|
||||||
|
world.ecs.CreateEntity(&component.DrawablesComponent{
|
||||||
|
Priority: 0,
|
||||||
|
Drawables: []engine.Drawable{},
|
||||||
|
})
|
||||||
|
|
||||||
|
return world
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gw *GameWorld) World() *ecs.World {
|
||||||
|
return gw.ecs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gw *GameWorld) Tick(dt int64) {
|
||||||
|
gw.ecs.Tick(dt)
|
||||||
|
}
|
27
game/system/game_state_system.go
Normal file
27
game/system/game_state_system.go
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
"mvvasilev/last_light/game/component"
|
||||||
|
)
|
||||||
|
|
||||||
|
type GameStateSystem struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateGameStateSystem() *GameStateSystem {
|
||||||
|
return &GameStateSystem{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gss *GameStateSystem) Name() string {
|
||||||
|
return "GameStateSystem"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gss *GameStateSystem) Order() int {
|
||||||
|
return math.MinInt + 100
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gss *GameStateSystem) Tick(world *ecs.World, deltaTime int64) {
|
||||||
|
comp, err := world.FetchSingletonComponent(component.ComponentType_GameStateComponent)
|
||||||
|
|
||||||
|
}
|
32
game/system/input_system.go
Normal file
32
game/system/input_system.go
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"mvvasilev/last_light/engine"
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
"mvvasilev/last_light/game/component"
|
||||||
|
)
|
||||||
|
|
||||||
|
type InputSystem struct {
|
||||||
|
engineContext *engine.EngineContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateInputSystem(ec *engine.EngineContext) *InputSystem {
|
||||||
|
return &InputSystem{
|
||||||
|
engineContext: ec,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *InputSystem) Name() string {
|
||||||
|
return "InputSystem"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *InputSystem) Order() int {
|
||||||
|
return math.MinInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (is *InputSystem) Tick(world *ecs.World, deltaTime int64) {
|
||||||
|
world.AddSingletonComponent(&component.InputComponent{
|
||||||
|
KeyEvents: is.engineContext.CollectInputEvents(),
|
||||||
|
})
|
||||||
|
}
|
65
game/system/rendering_system.go
Normal file
65
game/system/rendering_system.go
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
package system
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"mvvasilev/last_light/engine"
|
||||||
|
"mvvasilev/last_light/engine/ecs"
|
||||||
|
"mvvasilev/last_light/game/component"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RenderingSystem struct {
|
||||||
|
engineContext *engine.EngineContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateRenderingSystem(renderContext *engine.EngineContext) *RenderingSystem {
|
||||||
|
return &RenderingSystem{
|
||||||
|
engineContext: renderContext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RenderingSystem) Name() string {
|
||||||
|
return "RenderingSystem"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RenderingSystem) Order() int {
|
||||||
|
return math.MaxInt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rs *RenderingSystem) Tick(world *ecs.World, deltaTime int64) {
|
||||||
|
comps, err := world.QueryComponents(component.ComponentType_RenderableComponent)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// Skip this frame since an error occured // TODO: error logging
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
components := comps[component.ComponentType_RenderableComponent]
|
||||||
|
|
||||||
|
slices.SortFunc(components, func(a ecs.Component, b ecs.Component) int {
|
||||||
|
aDrawable := a.(*component.DrawablesComponent)
|
||||||
|
bDrawable := b.(*component.DrawablesComponent)
|
||||||
|
|
||||||
|
return aDrawable.Priority - bDrawable.Priority
|
||||||
|
})
|
||||||
|
|
||||||
|
fps := 1_000 / deltaTime
|
||||||
|
|
||||||
|
msPerFrame := float32(fps) / 1000.0
|
||||||
|
|
||||||
|
fpsText := engine.CreateText(0, 0, 16, 1, fmt.Sprintf("%vms", msPerFrame), tcell.StyleDefault)
|
||||||
|
|
||||||
|
rs.engineContext.Clear()
|
||||||
|
|
||||||
|
for _, c := range components {
|
||||||
|
drawables := c.(*component.DrawablesComponent).Drawables
|
||||||
|
rs.engineContext.Draw(drawables)
|
||||||
|
}
|
||||||
|
|
||||||
|
rs.engineContext.Draw([]engine.Drawable{fpsText})
|
||||||
|
|
||||||
|
rs.engineContext.Show()
|
||||||
|
}
|
5
go.sum
5
go.sum
|
@ -1,11 +1,15 @@
|
||||||
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
|
github.com/gdamore/tcell v1.4.0 h1:vUnHwJRvcPQa3tzi+0QI4U9JINXYJlOz9yiaiPQ2wMU=
|
||||||
|
github.com/gdamore/tcell v1.4.0/go.mod h1:vxEiSDZdW3L+Uhjii9c3375IlDmR05bzxY404ZVSMo0=
|
||||||
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
|
github.com/gdamore/tcell/v2 v2.7.4 h1:sg6/UnTM9jGpZU+oFYAsDahfchWAFW8Xx2yFinNSAYU=
|
||||||
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
github.com/gdamore/tcell/v2 v2.7.4/go.mod h1:dSXtXTSK0VsW1biw65DZLZ2NKr7j0qP/0J7ONmsraWg=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
@ -24,6 +28,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
5
main.go
5
main.go
|
@ -6,3 +6,8 @@ func main() {
|
||||||
gc := game.CreateGameContext()
|
gc := game.CreateGameContext()
|
||||||
gc.Run()
|
gc.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func runGame() {
|
||||||
|
gc := game.CreateGameContext()
|
||||||
|
gc.Run()
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue