Provide function to get next available CID.
Closed this issue · 8 comments
the implementation would be fairly simple, keep track of the last cid generated, and call HasEntity
to make sure it hasn't been manually bound to.
What would this function be used for that event.NextID
does not provide?
Well, clarity for one, as I'm not entirely sure what event.NextID
does, or why it takes an argument, or why it's the only thing called in Entity.Init
.
I was going to add a real example, but the more I think about it, the less I understand it.
if I remember correctly/ reread correctly event.NextID takes in an entity purely so that it can be added to the callers list which will be used to track all entities.
For an example of callers being used please see ScanForEntity. https://github.com/oakmound/oak/blob/master/event/entity.go#L47
Admittedly the signature of NextID can be confusing but at the end of the day it has two responsibilites:
- find the id to assign to the entity calling it (https://github.com/oakmound/oak/blob/master/event/entity.go#L30)
- track the entity https://github.com/oakmound/oak/blob/master/event/entity.go#L29
How would one go about using it then, when all of the implementations of event.Entity
(e.g. entities.Moving
) take a CID as an argument? It would seem you would need the CID before you have the entity.
All entities creation helpers call cid.Parse:
Line 18 in 34e40df
Is the comment for Parse a clear explanation as to why they do this?
I have no Idea what that comment is talking about. Many things about CIDs are not well explained. For example, the player in platformer-tutorial
is constructed using CID 0, suggesting that is a valid CID, but the doc for GlobalBind
states that cid 0 is "a non entity". It is also not clear whether Init() should be called after creating an entity. Should CIDs be adjacent, or can you have 1 and 100 as the only CIDs without problems?
It feels like CIDs work best when hand picked with constants attached (you could even use iota
), but if you are creating TONS of entities by loading, say, a TMX file, it isn't clear what to do. Can I just give them all CID 0? Is there a way to disable bindings to prevent having hundreds of goroutines?
I'll try to answer your questions with as much information as possible.
1. Explaining the comment
When using the entities
package, constructors in that package can optionally be passed a 0
CID or an already existing CID. If they are given an already existing, valid CID, they will not register themselves as an entity in the event
package and will not create a new CID. This is done when you have an existing entity that builds on top of an entities
type, as you can see all of the types in entities
do already-- Doodad builds on Point, Solid builds on Doodad-- to avoid needing to change logic in multiple places when basic logic is updated.
If they are given 0
instead, they will Init
themselves and register themselves as a new entity in the event
package so event bindings can be bound to them. This is what CID.Parse
is shorthand for.
The above should explain why the tutorials provide a 0 CID. Because they do not create their own struct type that has new fields, but just use the fields of the entities they are creating, they bind their event bindings to to the entities
struct they are using for their player character or object in game.
Another source of this information: in the platformer tutorial wiki explaining the line you are asking about we state : We don't use friction, so we set it to zero, and both collision.Tree and event.CID are arguments that will default to sensible values if we pass in zero values for them.
TL;DR: 0
means 'make a new CID'.
2. CID (Caller ID) iteration
CIDs must only be obtained from event.NextID
. Any CID not obtained this way is useless, as they can't be retrieved at event start. This is because NextID
registers the entity it accepts as an argument with the event package's entity list, which is what each binding must call as it starts to ensure it is applying its changes to the appropriate data.
Essentially, GetEntity
:
Line 37 in 34e40df
event.NextID
. (They are also all cleared out on scene changes.)
TL;DR: CIDs must only be obtained from event.NextID
3. Entities and TMX files
If you don't want your TMX file entities spinning up goroutines for events, perhaps they shouldn't be entities? There are three distinct systems in oak / game engines that are relevant here: entities responding to logic (event
), renderables being drawn to screen (render
), and collision spaces reacting to collisions (collision
). If your TMX components don't need to respond to logic, they don't need Caller IDs and they don't need bindings, and they can just be a collision space + renderable (or just the latter if they are non-colliding terrain).
So to answer the question: yes, you can partially disable bindings by not adding them for data in the program that does not need to respond to bindings. There is no way with oak to disable events being triggered, but you have no requirement to react to or bind response functions to any of these triggers, and you can reduce the load of these triggers by replacing the event handler with a NOP event handler if you do not want to interact with the event system at all.
TL;DR: Yes, you can disable bindings
4. Hundreds of goroutines
A small note on this: this is how Go is designed to work, with lots and lots of goroutines (ref https://golang.org/doc/faq#goroutines). Oak embraces this, but we have planned a mode of operation that minimizes goroutines for web browsers, where they cannot be efficiently simulated.
Wow, thanks! This clears up basically all the confusion I had regarding CIDs.
My remark about the number of goroutines stemmed mostly from an annoyance when debugging (delve
has no way to list a subset of the active goroutines, if you want goroutines listed, you have to list all of them).
I'll try a custom Tile
type, instead of just using something from the entities
package.