How to render TCastleScene between two layers of Tiledmap?

I’m back again. I’m trying to make a 2D pixel game, but I’ve encountered an unsolved problem. Tiledmap has many layers, I want the sprite to be rendered above the building layer, but below the Front layer, but I don’t know how to do it. I have tried to modify the Z coordinate of the Sprite, but it was ineffective. The test project has been uploaded.

tiledmaptest.zip (50.9 KB)

This is a good question,This is what I want to ask

If you draw a map yourself, this is easy to solve. First Draw the floor layer , the combination of sprite and wall is used as a layer, and sort the XYZ axis. Because sprite and wall need sorting and processing occlusion.

deprecated_to_upgrade\isometric_game , this old demo is ok, but this is not a recommended way

But recommended example — isometric_game has bug, no consider occlusion.
if Random(10) = 0 then
AddImage(RandomTree, X, Y, Vector2(0.5, 0.1), 1);

modify

if Random(3) = 0 then
AddImage(RandomTree, X, Y, Vector2(0.5, 0.1), 1);

The problem is obvious

I looked at this carefully — Occlusion Query | Manual | Castle Game Engine , No example, no understanding

I tested that the difference in Z value between each layer of the Tiledmap is 10. After setting the correct Z coordinate, I used TCastleScene to load PNG images and it correctly renders between the two layers. However, loading spritesheets does not work.So it may be that there is still some code that needs to be completed for rendering sprites.

testa

The Tiled Map cannot be regarded as a whole, some layers in the tiled map must participate in cover sorting.

1 Like

test2

Character is translucent cover

If I draw it myself, this is easy, using TDrawableImage should be roughly satisfied

But if I use the officially recommended method, I don’t know what to do

2 Likes

As you found, each Tiled layer is placed at a different Z coordinate, increased by 10 for each layer.

So in principle it is possible to place objects between layers by placing them at appropriate Z, like Z = 5 will be between 1st and 2nd layer.

That said, as you discovered above:

  • This fails when combined with blending – because current blending (used if your tileset texture has some partially transparent pixels) approach will render whole map completely behind or completely in front of the other things. So unfortunately this fails due to blending implementation shortcomings.

    This is mentioned as TODO on Blending (Rendering Partially-Transparent Objects) | Manual | Castle Game Engine , Roadmap | Manual | Castle Game Engine .

  • Even if it would work (we will improve blending at some point) I can see this is far from intuitive. We don’t even document that magic number “10” anywhere, and it is possibe that in the future I will get rid of it (we could render with special “depth function” that avoids the need for such Z shift at all).

But I have a solution :slight_smile:

I just made a new component TCastleTiledMap, that uses previous “Tiled in a TCastleScene” approach under the hood, adding some additional comfort and API. And it includes a Layers property (it is a set, if you click “…” on Layers property in CGE editor you will get a nice specialized dialog showing layers as checkboxes).

I documented it on Tiled maps | Manual | Castle Game Engine . It is also now used by examples/tiled/map_viewer_in_viewport in CGE.

With this you can address this issue: You can essentially split a Tiled map into 2 components, and make them explicitly at different Z, and blending will not be a problem. So:

  • Create 2x instances of TCastleTiledMap that always have the same transformation (translation etc.)
  • In both of them set URL to the same Tiled map
  • Configure their Layers such that each has different set of layers
  • Move one of them in Z as much as you want
  • place objects between them at appropriate Z
  • Either set Viewport.Items.BlendingSort to bs2D to properly sort layers when displaying based on Z (see Blending (Rendering Partially-Transparent Objects) | Manual | Castle Game Engine ), or just manually make sure they are in proper order (back to front) in the Viewport.Items tree.

If you will make an animation and object may sometimes get behind, sometimes in front of some map layer, it is best to set Viewport.Items.BlendingSort to bs2D and keep all objects (tiled map layers and moving object) at top-level right under Viewport.Items. This way the blending will correctly account for them each frame.

Attaching a silly demo :slight_smile:

map_viewer_in_viewport-0.1-src.zip (52.6 KB)

Note: I realize this is not perfect. We still want to improve blending, and the Viewport.Items.BlendingSort = bs2D should work in more universal way (without ever requiring to put stuff at top-level of Viewport.Items for correct sorting). This is still TODO. But I hope the current solution is workable in the meantime :slight_smile:

1 Like

After using two Tiledmap, rendering is no longer a problem. Then I can insert my own objects between the two maps, almost without manual rendering. It’s great! Next, I will try to read the custom attributes of the grid to cooperate with the game, and I will check if CGE can complete it.

1 Like

The tiled map has two layers, floor layers and wall layers.

Add two TCastleTiledMap as
map_viewer_in_viewport0.2.zip (814.1 KB)

Set Viewport.Items.BlendingSort to bs2D
Set Floor layer Z=0
Set Wall layer Z=20

I add three images

Image1 Z=19
Image2 Z=20
Image3 Z=20

Image1 and Image3 is a normal display

Image2 can’t automatically sort with the wall layer. How can I make IMAGE2 and wall layers automatically sort without manual change of the Z value

This is a problem with the map you designed. Your tower should be placed on two layers, the upper part of the tower always on the top layer, and the lower part set to impassable.

I just borrowed the tower to express the wall,You think of the tower as a wall,The character is in and outside the house. This is a common situation in 2D games

If I draw myself, I will mix the characters and the walls to sort,This is easy to solve the problem. But use TCastleTiledMap, I have no such flexibility

The following is the effect of my own drawing, although it is more troublesome, but the effect I want




04
05

I hope to enable rendering using TDrawableImage in a TCastleScene,I hope to draw myself as I want, and now there are too many restrictions

After looking at your demo images, it seems that your game type requires manual rendering, as some tiles may need to be displayed above or below the character. Using a viewport also requires strict adherence to the dimensions of the art assets, otherwise manually adjusting the character’s Z-coordinate will be quite troublesome and would need to be updated in real-time based on the Y-coordinate.

@soastao Hm, I’m thinking about it.

I created GitHub issue to track it – Tiled maps: Make it possible to render a character (any TCastleTransform) in a flexible way behind or in front of a layer with walls · Issue #440 · castle-engine/castle-engine · GitHub .

I see the problem – when you want layer to behave like a wall, then you want characters to be sometimes behind, sometimes in front of it. Effectively the character should be perceived at the same depth as the tile it is standing on.

To be clear, I have ideas how to do it, but they both are uneasy for now:

  1. We could augment Z values of walls to provide space for it: Each row could be at slightly larger Z. This is a direct way to say “each row of walls if effectively at different depth, a bit closer to camera”. And then you can insert character at any Z you want. But doing this in practice requires some uneasy things:

    • It would need to wait for a blending fix I mentioned in one of the earlier posts. That is, one scene (character) would have to be rendered between 2 shapes of another scene (tiled map).
    • It would mean that each row with different depth is a different shape. OK, this is not really a problem, this is trivial – when something like RowShiftZ is non-zero, then split shapes between rows.
    • Ideally, you should not need to calculate the Z of characters yourself to make them hit perfectly between wall rows. There should be automatic mechanism for it. I was already thinking about a behavior like TCastleMapPiece that could “snap” character to a proper position of given tile - in X, Y and/or in Z.
  2. Another approach would be to render with depth testing off, and then we don’t need to care about dealing with Z. We just need to render in proper order. This is the same thing as when rendering with 2D with TDrawableImage, one just has to keep strict order – so the order “rules everything”, and Z is meaningless.

    • Again for this we need a way to “attach” a character to map tile.

This echoes what @saaf writes,

manually adjusting the character’s Z-coordinate will be quite troublesome and would need to be updated in real-time based on the Y-coordinate.

Indeed – I mean such synchronization is needed by AD 1 above, and we need to make this easy, so that you don’t need to do this manually.

I do not yet have a good answer, just acknowledging the problem. This is something for me to think about.

Ultimately we need a way to “attach” a TCastleTransform (like TCastleScene) to a map tile, and ideally it should just make it rendered at the same layer as the tile, and user should not need to “fiddle” with Z values.

I have created a GitHub issue Tiled maps: Make it possible to render a character (any TCastleTransform) in a flexible way behind or in front of a layer with walls · Issue #440 · castle-engine/castle-engine · GitHub , and I encourage to subscribe to it – I will post there about the progress.

To be clear, if you want to draw the map yourself, using TDrawableImage (inside overridden Render of some TCastleUserInterface) then you can. As we talked in thread CGE 2D game development road - #2 by michalis where I gave pointers to manual how to draw using TDrawableImage.

Although you cannot “render using TDrawableImage in TCastleScene”. TCastleScene doesn’t work like that — to put things in TCastleScene you define nodes to render in TCastleScene. So you could define the nodes, that define tiles, in TCastleScene, and you could update these nodes each frame. But it is much easier to just render everything using TDrawableImage inside a TCastleUserInterface, if you just want a 2D map.

To be clear, I admit you found a critical problem with TCastleTiledMap here. We will solve it, but this one is not so trivial that I’ll come back tomorrow with a solution :slight_smile: I advised earlier to use a built-in solution from CGE to render Tiled maps, and I think we made a good progress in TCastleTiledMap (and more will come, I hope to add animations to map this weekend, as promised on TTiledMap cannot render animations - #3 by saaf ). TCastleTiledMap makes sense for some use-cases. But I absolutely admit that this is a “killer” – TCastleTiledMap cannot really be used in this situation, it cannot give you a “layer with walls created in Tiled” that will be satisfactory here. Yet. So, mea culpa – I admit I was wrong, I simply didn’t predict this problem.

But if you are ready to just do direct rendering yourself, then you can. TDrawableImage, with all optimizations (batching introduces last weekend) remains available, the Tiled map data (TCastleTiledMapData, previously it was just called TTiledMap) also remains available and you can read map from file this way.

So while we try to have a solution for Tiled maps: Make it possible to render a character (any TCastleTransform) in a flexible way behind or in front of a layer with walls · Issue #440 · castle-engine/castle-engine · GitHub in CGE, if you are prepared to render map yourself, then this is remains an option.

( And use castle-engine/castletiledmap_control.inc at master · castle-engine/castle-engine · GitHub as a starting point. )

I don’t expect TCastleTiledMap to solve all problems, I think TCastleTiledMap is mainly used for map editor development.

2D RPG game has more detail requirements for the map.

Some objects are picked, for example, treasure chest、cabinet、door、switch etc.

When the mouse moves to these objects(touch the shape of the object), the mouse should be replaced with other styles. When you click these objects, you may trigger an event. It can be triggered by judging the character movement to the nearby. If the character is far from the treasure chest, the opening event cannot be triggered

You need to detect whether the mouse has a collision with these objects.

There are three ways to deal with events, one is the script, and there are more possibilities. The other is to store good information in advance and perform the corresponding functions according to the information. The last one is the first 2 types of mixing.

All I described is the most basic needs of a 2D game.Practice is the best means. When a full -function 2D game is developed, the function in these processes is the real needs of the game engine.In fact, some functions are the best way to write by yourself.


For example:When the mouse is on the sign(when touch the shape of the signboard), the mouse must be changed to the graphic.After clicking the mouse, the event will be triggered.

Sure.

To be clear, we have these types of interactions in CGE :slight_smile:

Clicking on TCastleTransform, detecting what is clicked – see e.g. examples/viewport_and_scenes/detect_scene_hit/ .

With TCastleTiledMap, you can use Map property and PositionToTile method to detect on which exactly tile we clicked.

We have a demo examples/tiled/strategy_game_demo/ that performs the game on a Tiled map using this API. It uses now TCastleTiledMapControl (will be upgraded to TCastleTiledMap soon). It’s a very simple demo, but has basic interactions – you can indicate tiles on map, units are rendered on top of map etc.

You can also change mouse cursor to a custom image (or even animation), see examples/user_interface/custom_cursor/ .

The thing we miss in CGE is Tiled maps: Make it possible to render a character (any TCastleTransform) in a flexible way behind or in front of a layer with walls · Issue #440 · castle-engine/castle-engine · GitHub , and this will indeed for now mean you will need to do your own map rendering, and your own logic to detect what has been clicked with mouse. I’m just saying we do have these basic interactions in CGE too, in case it was not clear. We have used CGE to make 2D games, like https://unholy-society.com/ , though we didn’t use it with Tiled for larger games so far.

Hm, I was thinking hard about this, and I have in my mind a sketch of implementation how “attaching a TCastleTransform to a layer (and row in that layer) of Tiled map” could look like.

If this goes well, the idea is that

  • you will not need to fiddle with character Z,
  • we will not need to fiddle with Z for each row of the map layer, we will instead just run rendering of given TCastleTransform right in the middle of map rendering,
  • you will be able to indicate that given TCastleTransform should be rendered as part of given TCastleTiledMap A, as part of layer B there,
  • layer B rendering will be automatically adjusted to allow for rendering additional transformations in the middle (that is, attached thing can be behind some stuff on B, in front of other stuff on B),
  • blending will not be an issue – as we will just run rendering of TCastleTransform in the middle of map rendering,
  • any TCastleTransform will be possible to be attached to a map row, including TCastleScene with animated sprite sheets.

Please give me time, before this happens I need to finalize “shadow-volumes-new” branch ( GitHub - castle-engine/castle-engine at shadow-volumes-new ) – the improvements there are no longer just for shadows, they also enable more flexibility in rendering shapes more flexibly. The gist of the idea is to introduce a node, that can be in the middle of the map, that serves as proxy for rendering TCastleTransform.

The goal will be to make a demo a’la “Diablo” using CGE :slight_smile:

I think it is necessary to explain the details of the map cover.This is also a common situation

This map has 4 floors, of which the floor has two layer, and the wall also has two layers

The bottom layer is the basic terrain,The upper layer is the cover of the floor, such as carpets, stains, etc.
These two layers do not need to participate in the wall sorting, just draw it directly.

The wall layer is the third floor (such as walls, doors, tables and chairs)
The objects on the wall are the fourth floor (such as wall lamps, hanging paintings, windows)
The third and fourth layers and various characters need to be mixed sorted

We look forward to good news

Thanks.

We need a general system to account for various maps in CGE, and in particular this case, so raw spec would be

“”"
Layer may be:

  • “Flat” layer. Attaching TCastleTransform to tiles on “flat” layers makes them rendered always in front of the whole “flat” layer. (This doesn’t achieve anything new in regards to sorting, this is just like current usage with multiple TCastleTiledMap with different layers.)

  • Part of a group that express “Depth” (like walls). Layers (only adjacent) may be grouped to form such “Depth group”. TCastleTransform can be attached to a “Depth group” and in effect, TCastleTransform is in front of some and behind some other rows in layers of this group.

“”"

In your case,

  • 1st and 2nd layers are “flat”
  • 3rd and 4th layers form one “Depth group”

And this way in general we allow other scenarios. E.g. you could also have 5th layer with “lower clouds”. And attach to it birds flying over clouds, and then have 6th layer of
“upper clouds”.

Idea:

Maybe you can provide just a small subset of your map for testing? That is, as TMX map, ready to load in Tiled in CGE. This way I would be able to test it and know that the end result makes sense in your case. Otherwise I can miss some detail (e.g. grouping 3rd and 4th layer was important info for me above, I wouldn’t account for it otherwise).

Even better if you could share them on an open-source license so that we can use them in CGE example:) But that is of course up to you. But the more you can share, the more you guarantee that our final solution is what you need :slight_smile:

Thinking about your description of 3rd and 4th layers, a test TMX would be definitely useful. It does seem that some pieces of 4th layer (lamps, decorations) would need to be placed behind walls on 3rd layer. Which would go against normal assumptions about layers.

Again, if you can show a test map it would be best – so that I can understand what you do and how we want to support it.

I made a complex map,I used the CC0 arts and the arts I drawn myself, they are free

The map consists of 4 layers, 2nd layers and 3rd and 4th layers form one “Depth group”

Tiled drawing maps are wrong(I uploaded this wrong picture), Because Tiled is to draw a layer and draw a layer

The correct way of drawing is to paint by Tile, From top to bottom, from left to right, draw three layers in turn

This map can be used for testing.
rpgmap.zip (1.5 MB)