GithubHelp home page GithubHelp logo

ecs's People

Contributors

bfreis avatar coupez avatar etiennebruines avatar mewmew avatar noofbiz avatar otraore avatar paked avatar sbrow avatar storyfeet avatar yarbelk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ecs's Issues

Extensify tests

Would be nice to have a test for every possible aspect, to ensure it's stable.

World System "auto-register"

Hi,
thanks for all your work, having a lot of fun here using ecs & engo :)

One of the most boring, mistakable, and kind of dirty stuff is the registering process of a system.

Usually, we go to a code like that:

	rsys := &common.RenderSystem{}
	var r *common.Renderable
	var notr *common.NotRenderable
	w.AddSystemInterface(rsys, r, notr)

I would like to add a method to World in order to simplify this process (before, just an idea, can PR a complete work):

// didn't check the code, just the idea
type SomeSystem() {}
func(*SomeSystem) Add(basic *ecs.BasicEntity, space *common.SpaceComponent, component *BulletComponent) {}
func(*SomeSystem) Remove(basic ecs.BasicEntity) {}
func(s *SomeSystem) AutoRegister(w *ecs.World) {
	var able *SomeSystemAble
	var notAble *NotSomeSystemAble
	w.AddSystemInterface(s, able, notAble)
}

type Registerable interface {
	AutoRegister(w *ecs.World)
}

func (w *ecs.World) AutoRegisterSystem(r Registerable) *ecs.World {
	r.AutoRegister(w)
}

func (w *ecs.World) AutoRegisterSystem(r Registerable) *ecs.World {
	w.append(w.toBeRegistered, r)
}

world.AutoRegisterSystem(&SomeSystem{})

The idea is to delegate the registration process to the system... this can be done in multiple ways like above. Another interesting way can be done by using directly the method "AutoRegister" on the system but I think it's better to define an interface and delegate the registration to World.

This is what I currently do (with a decorator but the idea is here).

Feedback appreciated

ecs.BasicFace does not exist

I'm going through the "Automatically add entities to systems" section in the readme, and I'm stuck at this part in the example:

type Myable interface {
    ecs.BasicFace
    AFace
}

I do not have the ecs.BasicFace interface, and therefore cannot move on to the next step which calls obj.GetBasicEntity(). Has this been changed and the readme not updated?

Feature Request: Allow more than one interface in `World.AddSystemInterface` in and ex.

Sometimes a system needs to keep track of more than one type of entity at a time. For example, a move system that tracks "Moveable" entities with a Space component, and "MoveAction" entities that contain information on where to move next.

I think it would be advantageous if World.AddSystemInterface could interpret arrays/slices of interfaces as well as individual ones.

like so:

Example

package main

import (
	"github.com/EngoEngine/ecs"
	"github.com/EngoEngine/engo/common"
)

type moveAction struct {
	*ecs.BasicEntity
	target *ecs.BasicEntity
	*common.SpaceComponent
}

type moveEntity struct {
	*ecs.BasicEntity
	*common.SpaceComponent
}

type MoveSystem struct {
	actions  moveAction
	entities moveEntity
}

type MoveActionable interface {
	common.BasicFace
	common.SpaceFace
	Target() *ecs.basicEntity
}

type Moveable interface {
	common.BasicFace
	common.SpaceFace
}

func main() {
	w := new(ecs.World)
	m := new(MoveSystem)

	var moveable *Moveable
	var moveActionable *MoveActionable
	w.AddSystemInterface(m, []interface{}{moveable, moveActionable}, nil)
}

As far as I'm aware, this would not be a breaking change.

Let me know what you think!

Question: What is the rational behind dt being a `float32` instead of `time.Duration`/`float64`?

Just taking a walk through the code-base to familiarize myself and I wanted to better understand why the System interface's Update method takes a float32 instead of a time.Duration.

type System interface {
	Update(dt float32)
	Remove(e BasicEntity)
}

Off-handedly, I don't suppose that being more idiomatic to Go necessarily buys you anything extra but you would probably expect game-developers coming from more classic C/C++ environments to expect a double which would be a equivalent to float64 (See Game Programming Patterns: Passing Time of which you're probably already familiar, but this is reference for others who might stumble upon this question later along their own game-dev education).

If it was a "just cuz" decision, that's totally valid. I'm really just curious.

`...string` instead of `[]string` for NewEntity

Harley Laue noted at the slack-chat, that our ecs.NewEntity function takes a []string as an argument.

We could easily change this to ...string, without changing much to the ecs.NewEntity method, it wouldn't change anything to the Entity type, and it would make the syntax look way nicer.

e := ecs.NewEntity([]string{"RenderSystem", "MouseSystem"})

would become

e := ecs.NewEntity("RenderSystem", "MouseSystem")

Add a CONTRIBUTING.md

Its a good idea to have a CONTRIBUTING.md file, (and possibly an authors file as well).

Exclusion interface only matches if all components are present

I noticed the exclusion interface only excluded entities if all those components are present on an entity.

The behaviour I assumed was if one or all of the components on the exclude interface are on an entity it will exclude the entity.

Is the current behaviour the expected behaviour?

type NotMovementFace interface {
	GetDropComponent() *components.DropComponent
	GetTargetComponent() *components.TargetComponent
}

type NotMoveable interface {
	ecs.BasicFace
	NotMovementFace
}

// Will be excluded
type Enemy struct {
	ecs.BasicEntity
	SpaceComponent
	VelocityComponent
	TargetComponent
	DropComponent
}

// Wil not be excluded
type Bullet struct {
	ecs.BasicEntity
	SpaceComponent
	VelocityComponent
	DropComponent
}

In the example above I would expect any entities with either drop. target or both get excluded?

Update readme to utilize multiple interfaces

So you won't have to create entirely new interfaces for each system! You could just have one interface for each component, and add that to a slice of interfaces at the add. Might be easier, I'll have to try it to see! :P

Require tests to succeed before merging

Once we have the tests described in #4, we could add some kind of build-system (Travis? Something else?) which ensures that we're not breaking the code as we're progressing.

This isn't possible for engo because that depends on a lot of CGO and libraries, but this repository has no such dependencies, and is perfectly suited for it.

Mistake in README

The README has a small error in one of the code examples, were type is used instead of func.

type (m *MySystem) Add(basic ecs.BasicEntity, a *ComponentA) { /* Add stuff goes here */ }
type (m *MySystem) Remove(basic ecs.BasicEntity) { /* Remove stuff here */ }
type (m *MySystem) Update(dt float32) { /* Update stuff here */ }

Should be changed to:

func (m *MySystem) Add(basic ecs.BasicEntity, a *ComponentA) { /* Add stuff goes here */ }
func (m *MySystem) Remove(basic ecs.BasicEntity) { /* Remove stuff here */ }
func (m *MySystem) Update(dt float32) { /* Update stuff here */ }

Consider unexporting the Systems type

To minimize the public API to the core concepts of ECS, I propose we unexport the Systems type. It may be considered an internal detail of the ecs package, and should users of ecs want to use a similar priority queue outside of World, the implementation of the sort.Sort interface is trivial.

The Systems type is only used by the private systems field of the World structure, and the Systems method on World returns []System rather than Systems. Therefore we may easily unexport it, without breaking too many users. And, obviously the time to make changes to core packages like ecs is now since #13 was just merged, and all users have to update their code anyways.

From world.go

type World struct {
    systems Systems
}

// Systems returns a list of Systems
func (w *World) Systems() []System {
    return w.systems
}

Duplicate Entities

Migration of EngoEngine/engo#104

TL;DR: we want to do this:

e := NewEntity([]string{"RenderSystem"}) // Create template entity
// do things to entity

es := e.Duplicate(20) // fill a group with 20 different e's

w.Add(es)

Add Identifier interface, targeted at BasicEntity

If I want to be able to easily look up an entity by its ID, I would need to easily store purely based on ID; one solution to this is:

        type Identifier interface {
                ID() uint64
        }

        // Registry is an example data structure where this would be useful
        // it could implement the basic Add/Remove functionality that is so common

        type Registry struct {
                entities map[uint64]Identifier
                entitiesRWMutex sync.RWMutex
        }

The benefit of this is I can register something in one system, and the dynamically
check to see if whatever that entity was implements a specific interface at run time.
this means I don't need to store as many 'half implemented' subsets of the entities, and
i will have less duplicated code. The only thing I need to store in the system itself
would be the ID, and the information specific to the system.

Idiomatic Go - biggest breaking change yet

So, I was told by some people at the slack-chat, that we aren't using idiomatic Go. There may be collisions between the Type() string methods, and we're wasting performance by doing constant lookups.

They said: why don't you use reflect? Well, reflect is horrible so I don't want to use it.

But the idea is simple: get rid of the global []Entity, which stores every Entity. Instead, add the user-made entities to the appropriate systems,


Usage would be something like:

type MyEntity struct {
    BasicEntity
    SpaceComponent
    RenderComponent
}

func main() {
    // There'd be some kind of global list of systems, which contain every system, so we can loop over them
    var systems []BasicSystem

    // Each system we create, we add to that global list of systems
    RS := &RenderSystem{}
    systems = append(systems, RS)

    // Then we can define initialize our own custom-made entity struct
    e := &MyEntity{}

    // Add the appropriate component-references to the RenderSystem - this way you know for sure which components the render-systems requires
    RS.Add(&e.BasicEntity, &e.SpaceComponent, &e.RenderComponent)

    // And now we loop
    for _, sys := range systems {
        sys.Update(0.25)
    }
}

Upsides;

  • It's blazing-fast. The current Component function takes 91ns per lookup, the ComponentFast about 18ns, and this approach takes 0ns. For something that might happen thousands / millions of times a second, this is nice.
  • It's idiomatic Go, in the sense that it uses Go's type-safety. If it compiles, it'll most-likely run.

Downsides:

  • You need a reference to each system you want to use. Where to keep those references? What if we changed Scenes? They would have to start using other references.
  • It would break everything

This change is huge, but might also be worth it. I'd love a discussion on this, and maybe a fix for the downside? @paked, @everyone?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.