Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a Entity of Display Entity's Container #59

Closed
cubemoon opened this issue Jun 7, 2012 · 42 comments
Closed

Add a Entity of Display Entity's Container #59

cubemoon opened this issue Jun 7, 2012 · 42 comments
Assignees
Milestone

Comments

@cubemoon
Copy link

cubemoon commented Jun 7, 2012

Similar to the "DisplayObjectContainer" class in ActionScript3.

@melonjs
Copy link
Collaborator

melonjs commented Jun 11, 2012

Hi,

Actually we have something that could look similar in melonJS, as all objects are actually currently regrouped in TMXOBjectGroup (that’s actually the view you have on Tiled).
For now they just contains the Tiled object definition (and not object instance), but with some enhancement and a few more api, it could be turned into something more usable.

What would be the usage on your side for it ?

@cubemoon
Copy link
Author

cubemoon commented Jul 2, 2012

my game for a one-time moving all entity in the same manner.
I think if provides a container to do it. will be very easy and simple.

@melonjs
Copy link
Collaborator

melonjs commented Feb 27, 2013

@parasyte
first thank you very much for merging back the main branch into the ticket #15 branch ! i definitely need to spend some time playing with git...

then, and before going further, I was thinking that what I did for ticket #15 could be extended to cover this one, and eventually the entity composition you did in neverwell moor,

it's just a raw idea in my mind, but after all, sprite object could be seen a child of an entity container too, assuming that sprite object would also implement the interface (update/draw ?) required by child object.

what do you think ?

@parasyte
Copy link
Collaborator

@obiot I'm thinking about this one like a generic class that resembles ObjectEntity and includes the same API as the game manager; add(), remove(), sort(), removeAll(), countObjects(), update(), and draw() (I think that's everything). Call the class GroupObject.

All the game manager stuff in 'me.game' gets replaced with stub functions that call the main GroupObjects API. Other GroupObjects can be added to it, etc. update() and draw() functions iterate all child objects, calling the requested function.

GroupObject also acts like ObjectEntity/SpriteObject because it supports scaling (draw() scales the context before iterating child objects) and child pos vectors are relative to it (draw() translates the context before iterating child objects).

Another thing it needs is a method that returns an array of rectangles for all children in the object tree. This is for the dirtyRects feature.

So it's kind of like the sprite composition in Neverwell Moor, but with a more familiar API and more powerful features. :)

A GroupObject tree might look like this:

+ main (GroupObject)
|
+--- bg (TMXLayer)
|
+--- player (GroupObject)
|    |
|    +--- body (ObjectEntity)
|    |    |
|    |    +--- body sprite (SpriteObject)
|    |
|    +--- clothes (SpriteObject)
|    |
|    +--- hair (SpriteObject)
|    |
|    +--- weapon (SpriteObject)
|
+--- coin (ObjectEntity)
|    |
|    +--- coin sprite (SpriteObject)
|
+--- power up (ObjectEntity)
|    |
|    +--- power up sprite (SpriteObject)
|
+--- HUD (GroupObject)
     |
     +--- score (GUIObject)
     |
     +--- health (GUIObject)
     |
     +--- pause button (GUIObject)

Interested to hear what you have in mind for SpriteObject. It sounds like it really could become an array of SpriteObjects! Is your vision similar?

@parasyte
Copy link
Collaborator

Oops! Mobile failed me (no backtick character on the virtual keyboard) I've updated my comment above with proper formatting!

@melonjs
Copy link
Collaborator

melonjs commented Feb 28, 2013

I exactly had the same idea with the sprite. the point is that when adding a child object to the entity, it could either be another entity, or a sprite, or anything else.

However we could also establish that a base container can only contains entities, and that for each entity can support one "renderable" (I call it "renderable" here as it could be either a SpriteObject or something else). the advantage here is that we have one API/Interface to manage (object entity) rather than two (Object Entity and Sprite Object), and then sprite object can evolve freely (as far as it support a update/draw function) and other format be added.

one thing we need as well is to change the constructor parameters for SpriteObject, AnimationObject and ObjectEntity. Today they receive two parameters (x,y) for their intitial position, and it would be better to change this to a vector2d object. the advantage being that in that case a base container can pass a reference to it's own initial position (it simplify the way to manage child position when drawing them).

@melonjs
Copy link
Collaborator

melonjs commented Feb 28, 2013

@parasyte

additionally I would like to hide (private) the current property holding the sprite or animation object.
I was then thinking about function name like the following one
setRenderable(Object);
getRenderable()

any better idea about the name ? setDisplayObject ?

@melonjs
Copy link
Collaborator

melonjs commented Mar 1, 2013

@parasyte

ok more thoughts about this during the night and after reading some article on the internet :

I would propose creating a renderable base object, from which (SpriteObject) for example would derivate :

me.Renderable = me.Rect.extend({

    isRenderable : true,

    /**
     * update function
     * @return true if the object has been updated
     **/
    update : function() {
        return false;
    },

    /**
     * object draw
     * @param {Context2d} context 2d Context on which draw our object
     **/
    draw : function(context) {
        // do something
    }

});

ObjectEntity would obviously not extend this class, but could eventually contains a child implementing this class, that could then be added using a addChild type function, like in the above proposiion.

In the update() function, an Object Entity would then call the update function of each of ALL his child
components/entities

In the draw() function, an Object Entity would then call the draw function of each of ALL his child implementing the Renderable class (i added a isRenderable boolean here, but typeof could be used too)

@parasyte
Copy link
Collaborator

parasyte commented Mar 1, 2013

In your last statement, I guess you mean instanceof() ? I don't know if that works with the inheritance pattern, or how it performs compared to checking a Boolean. :)

I like the idea though; it provides separation between objects that just want to be updated and objects that want to be updated and draw. I would be happy with any API that allows creating object hierarchies. Because it would enable us to create modal stacks and similar concepts.

It sounds like your proposal turns the ObjectEntity class into the container. That's cool, too. It already implements scaling and alpha, etc. so it's a good place to start. Also I can't think of any limitations that it might impose on object hierarchies; and ObjectEntity can contain an ObjectEntity child, so it just works. I like it!

@melonjs
Copy link
Collaborator

melonjs commented Mar 1, 2013

@parasyte
yep sorry, I meant instanceof() :)

About turning ObjectEntity into a container, I don't know to be honest, but we could also have a speciifc "renderable" property that would allow to link a single sprite object or whatever to an ObjectEntity, and then have a specific container class as you were proposing before.

I'm not sure I really see the big advantage of one or the orher so far...

@melonjs
Copy link
Collaborator

melonjs commented Mar 2, 2013

@parasyte
So what do we decide we want to do? :)

I have my today afternoon free on my side, but i'm not really sure which approach is the best :)

@melonjs
Copy link
Collaborator

melonjs commented Mar 3, 2013

@parasyte

So yesterday I finally worked on turning the entity object into some simple containers, but I finally toss it out this morning, as for simple stuff (basic entity with 1 basic sprite) it requires a lots of complexity (1 loop in the entity update function, and 1 more in the draw function where this time we add a test on renderable object) which won't help with perfomances.

Furthermore an object container would be more inline with the TMXObjectGroup "philosophy" and could be reused as you were explaining in the actual main loop (as after all it loop throu a first level of object)

I kept however the renderable base class idea, as I think it could be used some place else in e engine when refactoring other objects.

I also kind of solved the child sprite object position, by assuming that its position is relative to the object ancestor (which means pos 0,0 by default for the child object), so I juste translated the display to the ancestor position, draw the child, and translate back to previous point. Same can be used for the container.

@parasyte
Copy link
Collaborator

parasyte commented Mar 3, 2013

I expect its just a matter of consolidating the features we expect and go with whatever interface makes most sense for implementing those features. Here are the "must have" features for this ticket, IMHO:

  • Ability to create a hierarchical tree of objects using a simple API that mirrors the "game manager objects" API.
  • The "branching" class in the tree must not restrict the type of objects it contains.
  • The update() and draw() methods called on the "branching" class must call the child methods in the same way the game manager does currently. E.g. Only call draw() when the update() has returned true.

Hmmm I think that's it? Given these requirements, I thought it would be best to move the game manager logic to this new "branching" class (aka "container" or "group") and replace the original game manager with an instance of a single default/main container. Then the code become reusable, and some interesting things could be done like modal dialogs; a dialog and its child objects live inside a container somewhere in the tree, and the game manager just switches to the context of that object, pausing every object outside of the modal dialog's branch. This can be used to implement multiple levels of modality. A "modal stack" IOW.

I don't know if ObjectEntity is the best object to turn into a container like this? But for sure ObjectEntity needs to contain multiple child sprite objects. Can it be extended and generalized to handle other tasks, and is this a good idea?

@melonjs
Copy link
Collaborator

melonjs commented Mar 4, 2013

Fully in line with the above requirements.

about the last question, my concern is mostly about the code overhead in the ObjectEntity, and the performance impact for an ObjectEntity containing only one sprite, that's mostly the reason why I reverted my changes to what I submitted yesterday,

About object compisition you implemented in neverwell moor, how do you see it translated in melonJS :as an entity container, or as an object entity containing several sprite objects ?

@parasyte
Copy link
Collaborator

parasyte commented Mar 4, 2013

My composition object resembles ObjectEntity containing multiple SpriteObjects. I like the flexibility that can be afforded by a generic container. The problem is I don't know how many people would make use of it. Still surprised to see how many use cases come up on the forum that would benefit from it, though. I don't see it adding any performance overhead.

Also doing things like the Quintus Breakouts block group; they scale in together when a stage begins, yet they have individual collision detection and such things.

Speaking of performance, an ObjectEntity with only one sprite can use a different function for update() and draw() select an appropriate private function when adding and removing child SpriteObjects. :)

@cubemoon
Copy link
Author

cubemoon commented Mar 6, 2013

composition object is very necessary.I think ObjectEntity is best used to expand the object,

@obiot
Copy link
Member

obiot commented Apr 17, 2013

@parasyte 0.9.8 as well ? i won't myself do anything on this one on 0.9.7 (at least I think)

@obiot
Copy link
Member

obiot commented Jul 20, 2013

@parasyte
hi,
for the 0.9.9 I wanted to look at this one, with the idea to actually replace the current gameObject under me.game by an actual DisplayEntityContainer Object (which then contains Entities or other DisplayEntityContainer).

the point being that in the process I'm maybe planning to actually remove the dirtyRect stuff from melonJS.
I'm not sure that this is really helpuf today, as only working with fixed level anyway (which is 1% of the existing games).

what do you think ?

obiot added a commit that referenced this issue Jul 27, 2013
…bject to use it as main container

Also removed the draw manager, and the dirtyRegion feature
@obiot
Copy link
Member

obiot commented Jul 27, 2013

@parasyte

Hi, that would be great if you could have a look at what I did, as I think it's pretty cool and give something much more clean in terms of code and much more evolutive for later. As I was writing it previously I also completely removed the dirtyRegion code, as anyway it was not working properly (and only useful with fixed level, without performance benefit for scrolling level), this can be however added later anyway, in a more simple way (it was anyway better to restart from scratch on this one).

so what i did :

  • added an entity container object, that acts as a object group (see me.EntityContainer)
  • revamped me.game to use a container by default and store all "root" level objects inside
  • me.EntityContainer now handles all logic in terms of update and draw loop, allowing as well (though I did not tested to cascade entityContainer).
  • me.EntityContainer auto-sort objects when a child is added, no more need to call sort if sorting is done on one property, this is also configurable. Eventually that would be great to have something that would allow top-down game to benefit from the same thing.

and I think that's it for now, still some stuff that need to be cleaned up under me.game, but for now all examples are running just fine, and i'm not seeing any major regressions :)

@aaschmitz
Copy link
Contributor

Ticket #211 redesign object entity and provide a more lightweight default one

@parasyte
Copy link
Collaborator

@obiot I commented the heck out of the patch! I haven't yet tried the code, so keep that in mind.

Glad to see the dirty region stuff removed. It was very hard to maintain. See #101! That ticket can completely rewrite the "intelligent" rectangle merging code now, starting from a clean slate. Still very tricky, but much better, IMHO.

I agree, the recursive update + draw looks good! It's exactly what I always wanted. 😄

The auto-sorting is a good idea in the general case, but could make efficient particle emitters difficult to create. One option just off the top of my head is that things like particle emitters (dynamically adding and removing many object all the time) could be added/removed on its own EntityContainer which has auto-sorting disabled. Then the add just becomes this.children.append(obj); and the remove is this.children.splice(this.children.indexOf(obj), 1); That requires a new boolean property on EntityContainer to enable auto-sorting, and would also be good to include the old sort() method for "manual" sorting:

sort : function (sortFunc) {
    if (this.autoSort !== true) {
        // ...
    }
    else {
        throw "melonJS : Do not call sort() with autoSort enabled";
    }
}

Also there are some TODOs left, but I assume you're aware of those! 😉

@parasyte
Copy link
Collaborator

I just noticed the EntityContainer.[pos|width|height] properties are initialized but not used for anything. This would be the perfect opportunity to use these in EntityContainer.draw() to translate to pos.x and pos.y, and update the rect passed to child.draw()!

The reasons for this are all listed above in earlier posts; first described by @cubemoon. Imagine a game of Space Invaders, where rows and columns of multiple entities all move in unison. I would implement such a game by placing all of the Invaders into an EntityContainer, and move them around by adjusting the position vector on the EntityContainer. That also lends itself to scaling and rotating the entire group, too (also mentioned before, citing the Quintus Breakouts port).

That makes the child draw positions relative to their parent container, by default. I like it!! :D

@obiot
Copy link
Member

obiot commented Jul 28, 2013

@parasyte yep, this is what i had in mind as well, like we did for the renderable property for entities.

thank you very much for all the comments and feedback, i started this thing on Friday, believing it would take me a few hours, but at the end it took me two days to reach this first result (but yeah not full time of course) ! As in the process i asked myself a tons of questions, by realising more of the thing that could be done with it, or by redoing the same thing several times.

very good progress here, i'm very happy !

@obiot
Copy link
Member

obiot commented Jul 28, 2013

@parasyte I was looking at the possibility to position object respecting to their parent (ancestor) container, and had a couple of question :

in order to follow something more or less standard, i wanted to name it after the corresponding CSS property (position) with the following possible values :

  • "relative" : child object position are defined respecting to the base container position
  • "absolute" : child object position are defined relatively to the viewport origin point (0,0)
    is it a correct understanding ?

however in case of relative positioning, but also scaling or rotating, what points shall we use ? top/left coordinates, or based on both items anchor points, or different following the usage (pos, scale, etc..) ?

(that makes me think that we could have used the same naming "convention" instead of the floating property, I see that CSS also defined "static" or "fixed" that probably also correspond to the same behavior).

@obiot
Copy link
Member

obiot commented Jul 28, 2013

@parasyte

one more question : how do you think we should manage collision with these entity container objects ?

@parasyte
Copy link
Collaborator

@obiot I would be concerned that multiple levels of EntityContainers with alternating "relative"/"absolute" positioning would be very difficult to support. We should say instead that a child's position is always relative to its container. Much simpler for us to build, and simpler for game developers to use.

As for scaling and rotation, me.EntityContainer already extends me.Renderable, which handles the scaling and rotation using a configurable anchor point. I don't see any more additional work needed here. ;)

Collisions should definitely be managed with the collision layering and masking as specified in #103.

obiot pushed a commit that referenced this issue Jul 31, 2013
obiot pushed a commit that referenced this issue Jul 31, 2013
Surprisingly, calling push is faster :)
@obiot
Copy link
Member

obiot commented Jul 31, 2013

@parasyte

I'm starting to feel quite happy about this one, and based on my testing results, it's getting close to ~0 regressions :)

Couple of questions though, as i'm having mix feelings on the following ones :

  • i was thinking about adding an mergeGroup option somewhere (with true as default value) that would instance one entityContainer per TMXObjetGroup when set to false. That would allow to re-group object inside the same group as it is the case in Tiled. what do you think ?
  • Shall we add the same kind of offscreen canvas we have in HUD, that would optionally allow to render the content of a EntityContainer into an offscreen canvas (the offscreen canvas being refreshed when at least one of the container child update function returns false) ? That could become handy when using EntityContainer for object composition, or to replace the HUD object ? (i'm not actually quite sure about the exact benefit in terms of performances)

@parasyte
Copy link
Collaborator

@obiot wow! a lot more commits for me to go through. 😄

I don't have any opinion on grouping TMX layers or objects instantiated from TMX. Although I could absolutely see the organization that it provides as a useful tool.

For the off-screen canvas, that has always been a thorn when working with the HUD object. Possibly because it doesn't have the right API to allow proper updates. I think maybe some benchmark is in order before spending time working on it. If it's a performance win, then yes! If no performance gain, then also keep in mind it will take up valuable texture space on mobile ...

@obiot
Copy link
Member

obiot commented Jul 31, 2013

Don't worry about all the commit, you'll give it a real life test during your next 1-game-a-month game :):):)

Else for the offscree canvas you are probably right, and one of the major complain on the HUD was the lack of scaling/rotation feature and so ovet, so that might not be a good idea to add this back here !

@ghost ghost assigned obiot Aug 2, 2013
obiot pushed a commit that referenced this issue Aug 2, 2013
…ursive search, and moved them into `EntityContainer`

while waiting for ticket #103 :)
obiot pushed a commit that referenced this issue Aug 2, 2013
…asier to understand than 'container' !

(we might as well deprecate a few function and encourage to use the
function under me.game.world ? )
obiot pushed a commit that referenced this issue Aug 2, 2013
obiot added a commit that referenced this issue Aug 3, 2013
…er` correspondingly to the TMXObjectGroup defined in Tiled

This is configurable through the `me.game.mergeGroup` setting with
default value being true (will create all object under the world root
container)

Also fixed object deletion throught the `me.game.remove` function.
@obiot
Copy link
Member

obiot commented Aug 3, 2013

@parasyte
with this last commit, the engine will (or not) create EntityContainer object correspondingly to the group objects created in Tiled.

this is configurable through the me.game.mergeGroup setting :

  • if true, all objects are added in the world root container
  • if false, one EntityContainer is created for each Object Group defined in Tiled, and objects added in the corresponding container.

for the moment I set the option to true, as this is what is matching the current (or previous I shall say) behaviour, but i'm unsure about my decision, do you have recommendations ?

when false, it adds more complexity (as you have to go through the child objects,i.e. when checking for collision), and objects are bound to their container in terms of z order.

when true, we are loosing all the benefits of the entityContainer, but might fit most of the needs ?

so, small dilemma :)

@obiot
Copy link
Member

obiot commented Aug 3, 2013

this might be my last commit on this ticket as well, i think it's done now :)

@parasyte
Copy link
Collaborator

parasyte commented Aug 3, 2013

@obiot Probably good to leave at true for now. We can remove this limitation when #228 and #103 land. 😄

@obiot
Copy link
Member

obiot commented Aug 3, 2013

probably a good idea :)

obiot added a commit that referenced this issue Aug 3, 2013
…ollision can be disabled per object container.
obiot added a commit that referenced this issue Aug 3, 2013
* moved `getContainer` under `me.game`
* optimzed the `hasChild` function
* fixed the `moveTo*` set of functions
@obiot
Copy link
Member

obiot commented Aug 5, 2013

@parasyte

I’m scratching my head on something here : what do we do with the floating property when defined on an entity container and/or on the child objects :

https://github.com/melonjs/melonJS/blob/master/src/entity/entitycontainer.js#L512

For entityContainer I believe it’s kind of obvious, when floating is true we translate the container to match with screen coordinates, child object are then draw using the default (screen) position of the container.

If floating is not defined for the container, but defined for a child I guess we ignore the initial container position and then translate the child object coordinates to the screen coordinates ?

If floating is defined for both, what do we do ? do we ignore the child floating property?

@obiot
Copy link
Member

obiot commented Aug 5, 2013

my suggestion would be to do something like :

if ( (this.floating== true) || (obj.floating==true)) {
    context.save();
    // translate back object
    context.translate(me.game.viewport.screenX -this.pos.x, me.game.viewport.screenY -this.pos.y);
}

@parasyte
Copy link
Collaborator

parasyte commented Aug 5, 2013

Well ... every entity with floating is just going to switch to screen coordinates. Every child should be positioned relative to its parent EntityContainer by default. Don't force child entities to be relative to the screen just because its parent EntityContainer is.

Imagine a HUD object implemented as a floating EntityContainer, and I place it at the bottom of the screen. Any child objects I add to this HUD will by default be positioned relative to it, so e.g. they will always be drawn within its frame. However, if I set floating = true on any of those children objects, their position switches to being relative to the viewport instead. And that will change where it gets drawn, for sure!

obiot pushed a commit that referenced this issue Aug 8, 2013
…r child objects (since we are not limited only EntityObjects)
@DonaldBaird
Copy link

Hi, so I've been playing around with the entity container object to be able to have an entity that is capable of drawing multiple renderables as segments to make up a player object. Basically legs, torso, and a head. I was told that the entitycontainer object could be used for player movement and collision, but a lot of the physics functionality of ObjectEntity aren't implimented. Such as setVelocity, setFriction, etc. Are these planned to be implemented into the entitycontainer?

@obiot
Copy link
Member

obiot commented Aug 15, 2013

If you want do use this to play with sprite composition, you should rather use it as a renderable components for your entity, and not as an EntityObject. me.ObjectContainer base class is actually me.Renderable, and this object is purely meant to be a container and won’t manage advanced physics.

However it can be included in collision check (though I did not try it yet, will also trigger the onCollision function) and also define the collidable property in order to disable collision per group.

Furthermore (also untested) it should be working in a scenario where the objectEntity detect collision using its own rectangle, and then call it’s renderable (the object container here) collide function, and see which part of the body has been touched.

@obiot
Copy link
Member

obiot commented Aug 23, 2013

@parasyte
i just realized that the name i choose (me.EntityContainer) for this is not really appropriate, since this container primary contains renderable object and then possibly entities,

so shall we rename this to me.ObjectContainer or set it back based on the original class it's based on me.DisplayObjectContainer ?

obiot pushed a commit that referenced this issue Aug 23, 2013
@obiot
Copy link
Member

obiot commented Aug 23, 2013

I'm closing this one now, as I really don't see anything else to be done for now !:)

@obiot obiot closed this as completed Aug 23, 2013
obiot pushed a commit that referenced this issue Aug 26, 2013
…g to enable/disable recursive sorting (off by default)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants