Top-down rendering order

Hi,

I've been following development of Orx for some time now. Recently I finally have found some time to do something with it :).

I'm interested in writing a top-down perspective RPG/Adventure game (most likely simple puzzle/adventure game my kids could play ;) ) something with look of SNES FinalFantasy games.

However as the viewing perspective is at certain angle I would like to obtain a semi-realistic feeling of thickness of objects. To do this I was planning to use a physics bounding box that is smaller then the sprite bounding box. It's Y coordinate would correspond to the depth (Z) of an object cast on the viewport plane. This way the physics engine would do all the work for me.

Still what I would like to have is an ability for the player or NPCs to go behind objects. Which means that when a player is in front of an object it should be obscured by the player sprite and when the player is behind an object then the player sprite is obscured.

To illustrate what I have in mind I attached a mockup image.

One could try to play with Z offset of sprites dynamically but it would get ugly pretty quickly.

I guess a sane solution is to use top-down rendering order. The renderer will draw objects based on their Y coordinate starting from top and progressing towards bottom. Strictly speaking the objects with smaller bottom Y are drawn first - as position in Y actually translates to Z in this kind of perspective.

As I've not seen anything in the docs or the code that would allow anything like this in Orx, I've implemented my solution in the "Home" render plugin. It does honour the Z ordering and is enabled via [Render] config section so should play nicely with the rest of Orx features. The patch against SVN HEAD in attachment.

There are still some issues with the code. The main problem will be with small objects placed on larger ones and also with rotating objects.

E.g. when placing fruits on a table the fruit sprite, as having smaller bottom Y, will be drawn under the table. To cope with this we can set an Z offset. But if we place some tall object in front of the table then the fruits will be drawn on top of it which is not what I want.

That's why I came up with an idea of "Renderer hints". Basically one could define an additional bounding box to an object/sprite (similarly to physics boxes so we would consider also circles and polygons) which would be used by the renderer to determine the shape of the object when doing the Y ordering. This way setting the hint bbox of fruit sprite to be slightly larger then the size of table sprite would do the trick.

However as this involves diving into the config parsing code I would prefer to discuss it first.

I hope that someone will find this useful :unsure: ...

Cheers,
Graag TopBottomRendered.png https://forum.orx-project.org/uploads/legacy/fbfiles/files/TopBottomRenderOrder.txt

Comments

  • edited August 2011
    Hi graag, and welcome!

    graag wrote:
    I've been following development of Orx for some time now. Recently I finally have found some time to do something with it :).

    Nice, it's always nice to see new people around! =)
    I'm interested in writing a top-down perspective RPG/Adventure game (most likely simple puzzle/adventure game my kids could play ;) ) something with look of SNES FinalFantasy games.

    Nice project, I hope we'll be able to follow it and learn a bit more via the project section of the site. =)
    However as the viewing perspective is at certain angle I would like to obtain a semi-realistic feeling of thickness of objects. To do this I was planning to use a physics bounding box that is smaller then the sprite bounding box. It's Y coordinate would correspond to the depth (Z) of an object cast on the viewport plane. This way the physics engine would do all the work for me.

    Oh I see, I never thought of doing this that way. Interesting.
    Still what I would like to have is an ability for the player or NPCs to go behind objects. Which means that when a player is in front of an object it should be obscured by the player sprite and when the player is behind an object then the player sprite is obscured.

    To illustrate what I have in mind I attached a mockup image.

    One could try to play with Z offset of sprites dynamically but it would get ugly pretty quickly.

    Mmh, I need to think about it a bit.
    I guess a sane solution is to use top-down rendering order. The renderer will draw objects based on their Y coordinate starting from top and progressing towards bottom. Strictly speaking the objects with smaller bottom Y are drawn first - as position in Y actually translates to Z in this kind of perspective.

    That's definitely the traditional way of doing it for this kind of view.
    As I've not seen anything in the docs or the code that would allow anything like this in Orx, I've implemented my solution in the "Home" render plugin. It does honour the Z ordering and is enabled via [Render] config section so should play nicely with the rest of Orx features. The patch against SVN HEAD in attachment.

    Thanks for that, I'll check it later this week end!
    There are still some issues with the code. The main problem will be with small objects placed on larger ones and also with rotating objects.

    E.g. when placing fruits on a table the fruit sprite, as having smaller bottom Y, will be drawn under the table. To cope with this we can set an Z offset. But if we place some tall object in front of the table then the fruits will be drawn on top of it which is not what I want.

    Yes, it's a bit tricky, you need a reference position within each object that you can use for your rendering/sorting purposes.
    That's why I came up with an idea of "Renderer hints". Basically one could define an additional bounding box to an object/sprite (similarly to physics boxes so we would consider also circles and polygons) which would be used by the renderer to determine the shape of the object when doing the Y ordering. This way setting the hint bbox of fruit sprite to be slightly larger then the size of table sprite would do the trick.

    I think I see where you're going with this. But is a shape really needed or wouldn't a reference position being sufficient?
    However as this involves diving into the config parsing code I would prefer to discuss it first.

    I'm not sure I understand why you'd need to tinker with the config parsing on that one. Would you mind giving more details? (It might also become clearer to me after a good night of sleep. :))
    I hope that someone will find this useful :unsure: ...

    Cheers,
    Graag TopBottomRendered.png https://forum.orx-project.org/uploads/legacy/fbfiles/files/TopBottomRenderOrder.txt

    The drawings definitely helped me understanding your point but I think I still need at least a few hours of sleep and maybe pick at your patch before understanding all the details.

    Off the top of my head, if I had to do such a game, I'd probably bind the Y position to the Z value (the smaller Y the bigger Z).

    Actually, to make things simple, I'd only work in the (X, Z) plane for my game logic, using Z as a reverse Y. The Z would then be used for the normal sorting step in the home render plugin.
    Then, upon receiving the orxOBJECT_EVENT_RENDER_OBJECT_START event for each object, I'd alterate the rendering frame to have a Y that would place the object correctly on screen, with respect to the expected result.
    Or if the Y component is need for collision detection, for example, I'd simply write a wrapper for the orxObject_SetPosition() which would compute the Y component correctly from the Z component and the pivot.

    I also have the feeling I could solve the ordering issue by using the Z component of the objects' pivot.

    Did I miss something obvious? Again, being quite sleep deprived is probably making me write a bunch of nonsensical stuff. :blush:

    EDIT: Also, if you don't want to use the pivot for solving the object size/sort issue as it might become unwieldy for sprite sheets and animations, you can still add your own property to your object stored in the UserData field and use that info in your SetPosition() wrapper.
  • edited August 2011
    iarwain wrote:
    graag wrote:
    There are still some issues with the code. The main problem will be with small objects placed on larger ones and also with rotating objects.

    E.g. when placing fruits on a table the fruit sprite, as having smaller bottom Y, will be drawn under the table. To cope with this we can set an Z offset. But if we place some tall object in front of the table then the fruits will be drawn on top of it which is not what I want.

    Yes, it's a bit tricky, you need a reference position within each object that you can use for your rendering/sorting purposes.
    That's why I came up with an idea of "Renderer hints". Basically one could define an additional bounding box to an object/sprite (similarly to physics boxes so we would consider also circles and polygons) which would be used by the renderer to determine the shape of the object when doing the Y ordering. This way setting the hint bbox of fruit sprite to be slightly larger then the size of table sprite would do the trick.

    I think I see where you're going with this. But is a shape really needed or wouldn't a reference position being sufficient?

    Hmm, you mean kind of pivot that would give an offset from objects position to be used by the renderer to work out the drawing order. Neat idea.

    I was considering shapes and in particular circle to cope with rotating objects where the object shape does not correspond to sprite bbox e.g. wings of a windmill or hands of a clock. But setting a reference position that would not be transformed by rotations should also work.

    I see one minor problem with using a reference position.
    A point will be harder to indicate in a map editor compared to a shape. I guess a vector will have to suffice B).
    However as this involves diving into the config parsing code I would prefer to discuss it first.

    I'm not sure I understand why you'd need to tinker with the config parsing on that one. Would you mind giving more details? (It might also become clearer to me after a good night of sleep. :))

    Well bad wording I guess. I meant rather modifying orxObject_CreateFromConfig or other more suited CreateFromConfig.

    The idea was to use the same shapes as in physics case, probably using the same code to create them based on a description in config file.
    Off the top of my head, if I had to do such a game, I'd probably bind the Y position to the Z value (the smaller Y the bigger Z).

    Actually, to make things simple, I'd only work in the (X, Z) plane for my game logic, using Z as a reverse Y. The Z would then be used for the normal sorting step in the home render plugin.
    Then, upon receiving the orxOBJECT_EVENT_RENDER_OBJECT_START event for each object, I'd alterate the rendering frame to have a Y that would place the object correctly on screen, with respect to the expected result.
    Or if the Y component is need for collision detection, for example, I'd simply write a wrapper for the orxObject_SetPosition() which would compute the Y component correctly from the Z component and the pivot.

    Very interesting idea with the advantage that Orx would not need to be touched ;-). Initially I discarded it based on my misunderstanding of collision behaviour. I though that physics bboxes are point-like in Z (objects at different Z offsets do not collide), however I did some tests and they behave as being infinite in Z. Nice to know :-D.

    Still I have some issues with this approach. To most of them I found workarounds still it would mean that some more though would be needed when designing the game besides one switch and placing the objects properly on a map ;-)

    1) Layers
    - Some additional layers would be required:
    - ground tiles
    - speech bubbles
    - flying objects like birds, cannon bals, balloons, whatever
    - GUI

    Those could be set at Z values outside from Y coordinate range. However I'm not sure if OrxFrustrum would like to be that large. Scaling the Y->Z relation would help but then I would definitely have to calculate it upon object creation (which leads to point 2).

    Still to make it convenient to use some limit on Y map size and it's top coordinate would have to be imposed.

    2) How would I make sure that Y->Z translation is done automatically upon object creation. Some OnCreate call back??

    3) Does not solve the small/rotating objects issue. Though I guess SetPosition could be made to use Reference Position you proposed ...

    3) I was hoping to use Scroll and ScrollEd. However they seem to use layers defined as Z offsets, and the concept looks quite entrenched.

    BTW
    I took Scroll from MushroomStew and modified it to work with Orx SVN HEAD. Also started to write down what I've learned about usage/interior of Scroll. Interested?
    I also have the feeling I could solve the ordering issue by using the Z component of the objects' pivot.

    EDIT: Also, if you don't want to use the pivot for solving the object size/sort issue as it might become unwieldy for sprite sheets and animations, you can still add your own property to your object stored in the UserData field and use that info in your SetPosition() wrapper.

    Those two comments I did not understand (it's quite late here so maybe this time I'm to sleepy ...). How would it differ from adjusting Z offset? From my quick tests Z component of the pivot does not seem to affect renderer in any way ...
    Did I miss something obvious? Again, being quite sleep deprived is probably making me write a bunch of nonsensical stuff. :blush:

    Thanks for your ideas. Quite some stuff to think over. Still if my modifs to the renderer would got incorporated it would mean less work for me ;-).

    One more thing, in my implementation rotation of an object is taken into account which I think would not be the case for simple XZ game logic (not relevant for a scenario that has to use SetPosition). Though I'm starting to reconsider if that is a good thing :S.

    Cheers,
    Graag
  • edited August 2011
    graag wrote:
    Hmm, you mean kind of pivot that would give an offset from objects position to be used by the renderer to work out the drawing order. Neat idea.

    I was considering shapes and in particular circle to cope with rotating objects where the object shape does not correspond to sprite bbox e.g. wings of a windmill or hands of a clock. But setting a reference position that would not be transformed by rotations should also work.

    I see one minor problem with using a reference position.
    A point will be harder to indicate in a map editor compared to a shape. I guess a vector will have to suffice B).

    Ahah, yes, well you can still have a custom display like a circle with gradient to make it more obvious to find. :)

    Speaking of editor, are you interested in trying Scroll/ScrollEd. It's a thin C++ wrapper on top of orx (nothing precompiled) that brings a few convenient wrappers for events and object handling as well as a level editor coupled with your game (you can run your game directly from the editor and load/save is part of the gig). You can also bind C++ classes to config sections for your objects this way every time an object is built from a section the corresponding C++ class will get instanciated for you in contiguous memory chunks, linked to the orx object and you get notified through virtual method calls.
    Even when I don't use the level editing I still use Scroll for all my personal devs as I find it much faster to develop using it.
    The downside is it's still in late alpha so the stability might not be as good as orx itself and most of all, there's no real doc available yet. It's also licensed under zlib license, so no problem on this.

    So far there are 3 testers that develop their game with it but I'm looking to get a wider audience. :)
    Well bad wording I guess. I meant rather modifying orxObject_CreateFromConfig or other more suited CreateFromConfig.

    The idea was to use the same shapes as in physics case, probably using the same code to create them based on a description in config file.

    Ah ok, I get it now! :)
    Very interesting idea with the advantage that Orx would not need to be touched ;-). Initially I discarded it based on my misunderstanding of collision behaviour. I though that physics bboxes are point-like in Z (objects at different Z offsets do not collide), however I did some tests and they behave as being infinite in Z. Nice to know :-D.

    Ahah yeah, the only physics plugin available right now is based on Box2D that doesn't even have a 3rd coordinate component. You can achieve filtering with flags/mask and play with that if you want to group by depth, but of course you have much less options in flags/masks than with depth values.
    Still I have some issues with this approach. To most of them I found workarounds still it would mean that some more though would be needed when designing the game besides one switch and placing the objects properly on a map ;-)

    1) Layers
    - Some additional layers would be required:
    - ground tiles
    - speech bubbles
    - flying objects like birds, cannon bals, balloons, whatever
    - GUI

    If you use Scroll, there are 9 emulated layers in the editor by default, but you can use any number of layers as long as it's an odd number (it'll assume that the gameplay layer is always 0 and then you can N-1/2 layers for the foreground and as many for the background). It'll also output a warning message if you use physics bodies for objects not in the gameplay layer but they can easily be removed.

    As for GUI I always use the camera parent space in order to have a resolution independent positioning and/or scaling of GUI objects. It's also easy to keep them in a layer rendered last by doing so.
    Those could be set at Z values outside from Y coordinate range. However I'm not sure if OrxFrustrum would like to be that large. Scaling the Y->Z relation would help but then I would definitely have to calculate it upon object creation (which leads to point 2).

    You can have a frustum as deep as you want but as it's a float32 precision you get much more precise values closer to 0.
    Still to make it convenient to use some limit on Y map size and it's top coordinate would have to be imposed.

    2) How would I make sure that Y->Z translation is done automatically upon object creation. Some OnCreate call back??

    Using Scroll, yes, otherwise you have to manually listen to the object events and specifically to the one of ID = orxOBJECT_EVENT_CREATE (that's actually how Scroll hooks the ScrollObject::OnCreate() method).
    3) Does not solve the small/rotating objects issue. Though I guess SetPosition could be made to use Reference Position you proposed ...

    Yes, you'd use your own SetPosition that would do the actual transformation before sending it to orx.
    3) I was hoping to use Scroll and ScrollEd. However they seem to use layers defined as Z offsets, and the concept looks quite entrenched.

    Ah well, see, I should read the posts entirely before replying, now I know that all my Scroll/ScrollEd talk in this post was completely useless. ;)

    Yes, for the layers it's just a convenience concept for the editor itself. You can define as many as you want or only 1 if you'd rather. Layers are primarily like in photoshop/gimp, simply used so that you will only edit objects in the current layer and control the order of display, nothing really more.
    BTW
    I took Scroll from MushroomStew and modified it to work with Orx SVN HEAD. Also started to write down what I've learned about usage/interior of Scroll. Interested?

    Again, I should have read all that. Well, what I offer is that I send you the latest version I have. The editor (especially the object selection) has been improved (it now uses a catalog with sets). There's been a bunch of improvements and bug fixes too. And for you writing what you've learned about it, that'd be great and most welcomed!

    You can contact me directly at the email address you can find in the README file, I'll send you an up-to-date version of Scroll that runs with the current svn HEAD of orx too.
    Those two comments I did not understand (it's quite late here so maybe this time I'm to sleepy ...). How would it differ from adjusting Z offset? From my quick tests Z component of the pivot does not seem to affect renderer in any way ...

    I meant using the pivot to store a Z offset you'd then use in your SetPosition() wrapper. It's was really poorly explained, sorry about that. :)
    Thanks for your ideas. Quite some stuff to think over. Still if my modifs to the renderer would got incorporated it would mean less work for me ;-).

    I totally understand. I'll try to have a look today if I find the time otherwise it might be delayed for another week, having a newborn and a toddler is definitely affecting a lot my spare time. ;)
    One more thing, in my implementation rotation of an object is taken into account which I think would not be the case for simple XZ game logic (not relevant for a scenario that has to use SetPosition). Though I'm starting to reconsider if that is a good thing :S.

    Cheers,
    Graag

    Mmh, I'll look at it when I'm more awake, right now I can't think straight. 5:45 AM, time to hit the hay! :D

    Cheers!

    EDIT: And with the new version of Scroll comes an email with most steps needed to use it and the editor, but I'm sure you've figured most if not all of them! :)
Sign In or Register to comment.