Closed cubemoon closed 11 years ago
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 ?
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.
@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 ?
@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 GroupObject
s API. Other GroupObject
s 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?
Oops! Mobile failed me (no backtick character on the virtual keyboard) I've updated my comment above with proper formatting!
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).
@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
?
@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)
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!
@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...
@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 :)
@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.
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:
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?
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 ?
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. :)
composition object is very necessary.I think ObjectEntity is best used to expand the object,
@parasyte 0.9.8 as well ? i won't myself do anything on this one on 0.9.7 (at least I think)
@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 ?
@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 :
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 :)
Ticket #211 redesign object entity and provide a more lightweight default one
@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. :smile:
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 TODO
s left, but I assume you're aware of those! :wink:
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
@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 !
@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 :
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).
@parasyte
one more question : how do you think we should manage collision with these entity container objects ?
@obiot I would be concerned that multiple levels of EntityContainer
s 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.
@parasyte
Among other things, Sort functions done !
Basically :
• I removed all the childIndex
stuff as I realized it was not really useful
• me.game now also defines a global propertyToSortOn
(“x”, “z”, “y”)
• Upon EntityContainer creation, the local propertyToSortOn
is set to the me.game current one (but can be then overwrite)
• The engine now auto-sort objects, unless the container autoSort
property is set to false ( I don’t however throw an error if the sort function is called with autoSort on, It just do nothing)
• The engine now implement all 3 possible sorting algorithm, so no need to have that sort_func
function for sorting on something else than z
.
TODO :
propertyToSortOn
is maybe a bit long?)As always your wise code review is always appreciated ! :P
that's all for today !
Errrr... came across this article tonight : http://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/
Most interesting point is the "Do not loop backward within an array." that apparently creates some cache miss... Will play a bit with jsperf tomorrow :)
@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 :
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 ?@obiot wow! a lot more commits for me to go through. :smile:
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 ...
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 !
@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 :
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 :)
this might be my last commit on this ticket as well, i think it's done now :)
@obiot Probably good to leave at true
for now. We can remove this limitation when #228 and #103 land. :smile:
probably a good idea :)
@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?
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);
}
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!
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?
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.
@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
?
I'm closing this one now, as I really don't see anything else to be done for now !:)
Similar to the "DisplayObjectContainer" class in ActionScript3.