Games Position in (z) axis for objects from Tiled

developer_123

Active Member
Licensed User
Longtime User
This is a follow up request for https://www.b4x.com/android/forum/t...cts-send-to-front-or-back.139480/#post-883779

I'm traing change BodyWrapper.DrawLast / DrawFirst properties, but the behavior are not the expected.

In my Game I have several characters which move between "layers". Additionally I have some landscape images in front of everything. The inconvenience is at the moment when I want my character to go from the front of the screen to the middle, that is, to be ahead of 2 other objects but behind the last one. By using BodyWrapper.DrawLast / DrawFirst the only thing I achieve is that it is sent to the front or to the end, but not to intermediate positions. I tried writing the order of the objects in which I want to place the characters but the behavior is not as expected. Any ideas?
 

developer_123

Active Member
Licensed User
Longtime User
This is a follow up request for https://www.b4x.com/android/forum/t...cts-send-to-front-or-back.139480/#post-883779

I'm traing change BodyWrapper.DrawLast / DrawFirst properties, but the behavior are not the expected.

In my Game I have several characters which move between "layers". Additionally I have some landscape images in front of everything. The inconvenience is at the moment when I want my character to go from the front of the screen to the middle, that is, to be ahead of 2 other objects but behind the last one. By using BodyWrapper.DrawLast / DrawFirst the only thing I achieve is that it is sent to the front or to the end, but not to intermediate positions. I tried writing the order of the objects in which I want to place the characters but the behavior is not as expected. Any ideas?

Here is an illustration of what happens. It is not possible to place elements in the middle.

1651457347290.png
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Here is an example of fully controlling the draw order.
In this case I wanted the blocks to be drawn in front of the circles. The important code is:
B4X:
Public Sub Tick (GS As X2GameStep)
    If X2.RndFloat(0, 1000) < X2.TimeStepMs Then CreateBlock
    If X2.RndFloat(0, 1000) < X2.TimeStepMs Then CreateCircle
    'draw circles
    For Each body As B2Body In X2.mWorld.AllBodies
        Dim bw As X2BodyWrapper = body.Tag
        If bw.DelegateTo Is StubBody Then
            'only circles
            If bw.Tag = True Then
                DrawBody(bw, GS)
            End If
        End If
    Next
    
    'draw blocks
    For Each body As B2Body In X2.mWorld.AllBodies
        Dim bw As X2BodyWrapper = body.Tag
        If bw.DelegateTo Is StubBody Then
            'only blocks
            If bw.Tag = False Then
                DrawBody(bw, GS)
            End If
        End If
    Next
End Sub

Private Sub DrawBody(bw As X2BodyWrapper, gs As X2GameStep)
    'code from X2BodyWrapper
    If (bw.TimeToLiveMs > 0 And (gs.GameTimeMs - bw.StartTime) >= bw.TimeToLiveMs) Then
        bw.Delete(gs)
        Return
    End If
    If bw.GraphicName <> "" Then bw.UpdateGraphic (gs, True)
End Sub
And the StubBody class that overrides the default behavior.
 

Attachments

  • Project.zip
    42.4 KB · Views: 135

developer_123

Active Member
Licensed User
Longtime User
Thanks Erel. When I was to try test the attached proyect in B4J appear the below error. I verify the file Blue_Donut_7.png is inside share folder and inside the Folder Manager of the B4j Program. In B4I and B4A Just needed to related the StubBody Module, and works fine. So, I'm going to chek line to line of the code to understand the behavior.

I'm not familiar like bw.DelegateTo works. I appreciate if you clarify me how it works!

Loading objecttypes.json v0.98
TileMap: AABB: AABB[(0.0,0.0) . (6.0,4.5011253)], Map Pixels (X) per Meter: 213.33, Map Pixels (Y) per Meter: 213.28
b4xpagesmanager._createpageifneeded (java line: 307)
java.lang.RuntimeException: java.lang.RuntimeException: java.io.FileNotFoundException: Blue_Donut_7.png
at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:523)
at anywheresoftware.b4a.keywords.Common.CallSubNew2(Common.java:469)
at b4j.example.b4xpagesmanager._createpageifneeded(b4xpagesmanager.java:307)
at b4j.example.b4xpagesmanager._showpage(b4xpagesmanager.java:722)
at b4j.example.b4xpagesmanager._addpage(b4xpagesmanager.java:113)
at b4j.example.b4xpagesmanager._addpageandcreate(b4xpagesmanager.java:120)
at b4j.example.b4xpagesmanager._initialize(b4xpagesmanager.java:491)
at b4j.example.main._appstart(main.java:58)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:98)
at b4j.example.main.start(main.java:37)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.RuntimeException: java.io.FileNotFoundException: Blue_Donut_7.png
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:140)
at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:514)
... 23 more
Caused by: java.io.FileNotFoundException: Blue_Donut_7.png
at anywheresoftware.b4a.objects.streams.File.OpenInput(File.java:235)
at anywheresoftware.b4j.objects.ImageViewWrapper$ImageWrapper.Initialize(ImageViewWrapper.java:138)
at anywheresoftware.b4a.objects.B4XViewWrapper$XUI.LoadBitmap(B4XViewWrapper.java:926)
at anywheresoftware.b4a.objects.B4XViewWrapper$XUI.LoadBitmapResize(B4XViewWrapper.java:933)
at b4j.example.x2utils._loadbmp2(x2utils.java:676)
at b4j.example.x2utils._loadbmp(x2utils.java:663)
at b4j.example.x2tilemap._loadgraphicforshape(x2tilemap.java:1051)
at b4j.example.x2tilemap._createbodydefandfixturedef(x2tilemap.java:384)
at b4j.example.x2tilemap._prepareobjectsdef(x2tilemap.java:1303)
at b4j.example.game._initialize(game.java:158)
at b4j.example.b4xmainpage$ResumableSub_B4XPage_Created.resume(b4xmainpage.java:99)
at b4j.example.b4xmainpage._b4xpage_created(b4xmainpage.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:111)
... 24 more
 
Last edited:

developer_123

Active Member
Licensed User
Longtime User
Perfect, I can change I as please the order of the bodies un "z" axis. Although I still don't understand how bw.DelegateTo works, I managed to understand the order of operation and made a small change to the code to make it generic for any body.

It is important to keep in mind for understanding that the order in which the bodies are drawn is established in the same order in which the "FOR" instructions of each type of Body are written within the SUB TICK.

I couldn't get it to work for B4J. It keeps throwing me the same error. What can be?

I tried to attach the file but apparently it is very large although it only occupies 3 Mb. I relate it in the following link.
 

ilan

Expert
Licensed User
Longtime User
Here is an example of fully controlling the draw order.
In this case I wanted the blocks to be drawn in front of the circles. The important code is:
B4X:
Public Sub Tick (GS As X2GameStep)
    If X2.RndFloat(0, 1000) < X2.TimeStepMs Then CreateBlock
    If X2.RndFloat(0, 1000) < X2.TimeStepMs Then CreateCircle
    'draw circles
    For Each body As B2Body In X2.mWorld.AllBodies
        Dim bw As X2BodyWrapper = body.Tag
        If bw.DelegateTo Is StubBody Then
            'only circles
            If bw.Tag = True Then
                DrawBody(bw, GS)
            End If
        End If
    Next
   
    'draw blocks
    For Each body As B2Body In X2.mWorld.AllBodies
        Dim bw As X2BodyWrapper = body.Tag
        If bw.DelegateTo Is StubBody Then
            'only blocks
            If bw.Tag = False Then
                DrawBody(bw, GS)
            End If
        End If
    Next
End Sub

Private Sub DrawBody(bw As X2BodyWrapper, gs As X2GameStep)
    'code from X2BodyWrapper
    If (bw.TimeToLiveMs > 0 And (gs.GameTimeMs - bw.StartTime) >= bw.TimeToLiveMs) Then
        bw.Delete(gs)
        Return
    End If
    If bw.GraphicName <> "" Then bw.UpdateGraphic (gs, True)
End Sub
And the StubBody class that overrides the default behavior.
i reading this thread and a question came to me.

having the control to draw each body in the wanted Z position is very important in game making. i understand what you are doing in your code erel but if i would have many different bodies in my game i will need to call many loops and each loop will always go through the whole body list and that may be not very much efficient
normally what i do is i have different lists for each group and i draw them i the order i want.

so is there a different approach in X2 for that problem or the only solution is going again and again the whole body list?

thanx
 

developer_123

Active Member
Licensed User
Longtime User
i reading this thread and a question came to me.

having the control to draw each body in the wanted Z position is very important in game making. i understand what you are doing in your code erel but if i would have many different bodies in my game i will need to call many loops and each loop will always go through the whole body list and that may be not very much efficient
normally what i do is i have different lists for each group and i draw them i the order i want.

so is there a different approach in X2 for that problem or the only solution is going again and again the whole body list?

thanx
Precisely at this moment I was analyzing what @ilan indicates, since my game can have 120 bodies simultaneously, which could generate a considerable delay in each loop that affects the general performance of the game.

On the other hand, instead of using lists, I was reviewing the possibility of creating a new attribute to the bodies from the TILED to, from there, indicate in which "plane" it should be drawn and then for each specific body, as the case may be, modify the value. of this attribute to update the new "plane" in which we must continue drawing, since I have the .tag attribute occupied for other purposes. So my question now is: Is there a way to create a new attribute from the TILED and then be able to call it from B4X and edit it, something like Bw.Body.Newattribute ?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
Precisely at this moment I was analyzing what @ilan indicates, since my game can have 120 bodies simultaneously, which could generate a considerable delay in each loop that affects the general performance of the game.
Unlikely (test in release mode).

You can set the tag value to any string you like and then parse it at runtime.
 

developer_123

Active Member
Licensed User
Longtime User
You can set the tag value to any string you like and then parse it at runtime.
Sorry if I'm a little slow, but this flew by. How do I achieve this, is say, where do I declare it and then how can I call it from code?
 

ilan

Expert
Licensed User
Longtime User
since my game can have 120 bodies simultaneously
120 bodies is not much.

anyway, in spritekit you have a .zPosition property for each node. so from the documentation (what i understand) that on each render loop the frameworks goes through all node list and order a new list with the correct zPosition and then it goes through the new list and render everything correctly. so also if you add new nodes on runtime you can set the zPosition and it will be rendered correctly. in my opinion this is the correct approach to render sprites and you only use 2 loops. 1 to create the new list and 2. to draw everything correctly. i don't know how X2 handle it but settings it only in Tiled is not a good solution because you add lots of new nodes on runtime.

 

developer_123

Active Member
Licensed User
Longtime User
I present an unexpected inconvenience, and it is that when implementing this routine to control the Z-axis location of the bodies, when for some reason I need to delete the bodies, it is not possible. These continue to be drawn and the body does not disappear.
 
Top