Games [XUI2D] Hello World - First app

Discussion in 'Game Development' started by Erel, Jul 18, 2018.

  1. Erel

    Erel Administrator Staff Member Licensed User

    A simpler example based on Tiled Map Editor is available: [XUI2D] Hello World 2 based on Tile Map

    The purpose of this tutorial is to help you run your very first app based on XUI2D.

    A great benefit of XUI2D being cross platform is that you can do most of the development in B4J. Developing directly on the desktop is simpler and faster.
    Later you can create B4A and B4i projects and add references to the exact same modules.

    Before we start, make sure to use the latest version of XUI2D: https://www.b4x.com/android/forum/threads/b4x-xui2d-box2d-game-engine.95208/#content

    1. Create a new B4J UI project.
    2. Add references to the following internal libraries: jBitmapCreator, jGameViewHelper (for the sounds), jXUI and XUI2D.
    3. Add the five X2 class modules to the project. I'm always adding them as linked modules though it is possible that you will want to modify them in the future so it is fine to copy them to the project.

    You will see an error in the logs about a missing game type.
    You should add a new class module named Game. Unlike the other X2 modules which are generic and ideally will not need to be modified, the Game class is specific to your game.

    A template is included inside XUI2D library (not available in v0.91.0):
    [​IMG]

    4. Create the layout.

    It should include two ImageViews named ivBackground and ivForeground and a label named lblStats at the bottom (anchored to the BOTTOM and BOTH sides).

    The ImageViews layout is set in the designer script:
    Code:
    GameRatio = 1.333 'width / height - change as needed

    ScreenRatio = 
    100%x / 100%y
    If ScreenRatio < GameRatio Then
     ivForeground.SetLeftAndRight(
    0100%x)
     ivForeground.Height = ivForeground.Width / GameRatio
     ivForeground.VerticalCenter = 
    50%y
    Else
     ivForeground.SetTopAndBottom(
    0100%y)
     ivForeground.Width = ivForeground.Height * GameRatio
     ivForeground.HorizontalCenter = 
    50%x
    End If
    ivBackground.SetLeftAndRight(ivForeground.Left, ivForeground.Right)
    ivBackground.SetTopAndBottom(ivForeground.Top, ivForeground.Bottom)
    The above code makes sure that the width to height ratio is always as defined in GameRatio variable.
    Set the main form color to black.

    Main module code to:
    Code:
    #Region Project Attributes
       
    #MainFormWidth: 800
       
    #MainFormHeight: 600
    #End Region

    Sub Process_Globals
       
    Private fx As JFX
       
    Private MainForm As Form
       
    Private gm As Game
    End Sub

    Sub AppStart (Form1 As Form, Args() As String)
       MainForm = Form1
       MainForm.Show
       gm.Initialize(MainForm.RootPane)
       gm.X2.Start
    End Sub

    Sub MainForm_Resize (Width As Double, Height As Double)
       gm.Resize
    End Sub
    You can run the program now. You should see this:

    [​IMG]

    The small crosses are drawn because DebugDraw is enabled. They mark the world grid.
    The next tutorial will cover the units used in XUI2D. It is very important to understand them. For now you should know that all the dimensions are measured in meters.
    Unlike the pixels coordinates which start at the top of the screen and go downwards, the world coordinates start at the bottom and go upwards.

    5. Lets add a few bodies.

    This code creates a rectangle body and position it at the top of the screen:
    Code:
    Private Sub CreateBlock
       
    'create the body
       Dim bd As B2BodyDef
       bd.BodyType = bd.TYPE_DYNAMIC 
    'regular body
       Dim x As Float = X2.RndFloat(X2.ScreenAABB.BottomLeft.X, X2.ScreenAABB.TopRight.X)
       bd.Position = X2.CreateVec2(x, 
    5)
       
    Dim wrapper As X2BodyWrapper = X2.CreateBodyAndWrapper(bd, Null"Block")
       
    'add fixture
       Dim rect As B2PolygonShape
       
    rect.Initialize
       
    rect.SetAsBox(0.250.5'parameters are half width and half height. Size is 0.5 x 1 meters.
       wrapper.Body.CreateFixture2(rect1)
    End Sub
    Adding a new block approximately every 500ms:
    Code:
    Public Sub Tick (GS As X2GameStep)
       
    If X2.RndFloat(0500) < X2.TimeStepMs Then CreateBlock
    End Sub
    6. Drawing the background:
    Code:
    Private Sub CreateStaticBackground
       
    Dim bc As BitmapCreator
       bc.Initialize(ivBackground.Width / xui.Scale, ivBackground.Height / xui.Scale)
       bc.FillGradient(
    Array As Int(0xFF006EFF0xFFB04700), bc.TargetRect, "TOP_BOTTOM")
       ivBackground.SetBitmap(bc.Bitmap)
    End Sub
    The background is static so it is only needed to be drawn once when Game is initialized.

    At this point it should look like this:

    [​IMG]

    Notes:
    - The blocks fall out of the screen.
    - The blocks do not yet have real graphics. We can only see them because debug drawing is enabled.

    To fix the first issue we need to add a ground body:
    Code:
    Private Sub CreateGround
       
    Dim bd As B2BodyDef
       bd.BodyType = bd.TYPE_STATIC 
    'the engine should not move it
       Dim wrapper As X2BodyWrapper = X2.CreateBodyAndWrapper(bd, Null"ground")
       
    Dim edge As B2EdgeShape
       edge.Initialize(X2.CreateVec2(-
    201), X2.CreateVec2(201))
       wrapper.Body.CreateFixture2(edge, 
    1)
    End Sub
    This sub should be called once. Note that we can use X2.ScreenAABB to get the screen coordinates.

    7. The last step is to add graphics to the blocks. There are all kinds of ways to do it. In most cases the graphics will come from image files. The best way to kill the game performance is by frequently creating new graphics, especially with antialiasing enabled.

    I will use a canvas here to draw a rectangle:
    Code:
    'The canvas is returned from a cache of square canvases.
    'It will be larger than the size requests.
    Dim CvsMinSize As Int = X2.MetersToBCPixels(Max(BoxSize.X, BoxSize.Y))
    'We need to divide the size by X2.BmpSmoothScale.
    Dim Cvs As B4XCanvas = X2.GraphicCache.GetCanvas(CvsMinSize / X2.BmpSmoothScale)
    Dim r As B4XRect
    r.Initialize(
    00, X2.MetersToBCPixels(BoxSize.X) + 1, X2.MetersToBCPixels(BoxSize.Y) + 1)
    Cvs.ClearRect(r)
    Cvs.DrawRect(r, 
    0xFF2100ABTrue0)
    'Create a scaled bitmap type. This holds the bitmap and its scale (1 in this case)
    Dim sb As X2ScaledBitmap
    sb.Bmp = Cvs.CreateBitmap.Crop(
    00, r.Right, r.Bottom)
    sb.Scale = 
    1
    'last step is to add the scaled bitmap to the cache.
    X2.GraphicCache.PutGraphic("block"Array(sb))
    Note that I've also set the graphic name property:
    Code:
    wrapper.GraphicName = "Block"
    The project is attached. I've also added a circle body based on an image file.


    test.gif
     

    Attached Files:

    Last edited: Aug 16, 2018 at 4:07 PM
  2. sorex

    sorex Expert Licensed User

    Indeed, I read that but I have 1.00 in my libs panel.

    Custom view (Xui) was added in the class menu tho.
     
  3. Erel

    Erel Administrator Staff Member Licensed User

    You are correct. The current version of XUI2D is 1.00. The template will be available in the next update.
     
  4. ilan

    ilan Expert Licensed User

    hi erel, i have tried the example but something doesn't look very much "box2d".
    the collisions are not precise. you can see sometimes that 2 bodies are going through each other.

    i am not sure what is the reason but trying a simple example using jbox2d gives me a better (more realistic) result.

    https://drive.google.com/open?id=1IJKmhUysImkD00_HL0_9yvEOqk0e_0V5
     
  5. Erel

    Erel Administrator Staff Member Licensed User

    The collisions are 100% based on Box2D. There are all kinds of parameters that affect the collisions accuracy.

    1. Enable debug drawing.
    2. Set bd.Bullet = True when you create the bodies. This will probably "fix" the issue you see.

    There are other parameters that can affect the collisions behavior as well.
     
    Last edited: Jul 22, 2018
  6. sorex

    sorex Expert Licensed User

    you can see it in the animated image above aswell.

    for example the red block at the bottom left should be at angle 0 since it's on a flat surface.

    I had some test with it yesterday (B4J version) and it's very interesting altho it's a lot of code to understand.
     
  7. Erel

    Erel Administrator Staff Member Licensed User

    This is related to a different thing.
    It will be more accurate in the next update of the X2 framework.

    Note that you are not expected to learn all the code in the X2 modules. This is part of the framework.
     
  8. sorex

    sorex Expert Licensed User

    nono, I meant the creation of an image + fixtures etc mainly the code in the main game module.

    the only thing missing to go really advanced is the joints.

    well done for the current state by the way.
     
  9. ilan

    ilan Expert Licensed User

    this setting is only for very fast moving bodies. so if i add a very high velocity to a body i could use that but for simple bodies that fall down this is not the right way to fix it. a bullet body will use much more calculation time than a non bullet body so change all bodies to a bullet body will decrease performance.

    i see that you dont set the density in your example. what is the default density that i set when you create a body?

    do you want to have a look on how the bodies are set in my example using jbox2d?

    EDIT: do u set the world.step in your example?
    in my projects i use this settings

    world.Step(1/60, 8, 3)

    it is recommended to update the world with this step. this is the time the all collisions are updated.

    worldstep.png
     
  10. ilan

    ilan Expert Licensed User

    ok i found the wrong settings:

    change this:

    Code:
    World.TimeStep(TimeStepMs / 100023)
    to this:

    Code:
    World.TimeStep(TimeStepMs / 100083)
     
  11. Erel

    Erel Administrator Staff Member Licensed User

    The Density is set here:
    Code:
    Dim f As B2Fixture = wrapper.Body.CreateFixture2(rect1)
    There is no right or wrong settings. You need to find out the correct balance between performance and accuracy (and you must test it on all relevant platforms).

    I will make it configurable so you won't need to change X2Utils code.
     
  12. ilan

    ilan Expert Licensed User

    ok. so f.density does nothing?
     
  13. Erel

    Erel Administrator Staff Member Licensed User

    It is really better to start a new thread for these questions. You have two options to create a fixture:

    1. Create a FixtureDef, configure it and then call Body.CreateFixture. This is especially useful when you want to reuse the FixtureDef object.
    2. Create the shape and call Body.CreateFixture2 with the shape and density.
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    About the collision overlapping, you should make sure to test in release mode. In debug mode the target FPS is set to 30 and it causes the physical engine to be less accurate.
     
    Peter Simpson likes this.
  15. Erel

    Erel Administrator Staff Member Licensed User

    Example was updated based on XUI2D v0.92.

    Note that the velocity iterations and position iterations defaults are now 8 and 3.
    The issue discussed above with inaccurate angles was also fixed.
     
    Peter Simpson and Johan Hormaza like this.
  16. walterf25

    walterf25 Well-Known Member Licensed User

    Can't run the HelloWorld example, i have some errors in the X2DebugDraw class right at this function

    Code:
    Private Sub DrawContactPoints
        
    Dim contact As B2Contact = X2.mWorld.FirstContact
        
    Dim wm As B2WorldManifold
        
    Do While contact <> Null
            
    contact.GetWorldManifold(wm)
            
    For i = 0 To wm.PointCount - 1
                
    Dim WorldPoint As B2Vec2 = wm.GetPoint(i)
                
    Dim vec As B2Vec2 = X2.WorldPointToMainBC(WorldPoint.X, WorldPoint.Y)
                vec.MultiplyThis(DebugScale)
                cvs.DrawCircle(vec.X, vec.Y, 
    30xFFFF2E00True0)
            
    Next
            
    contact = contact.NextContact
        
    Loop
    End Sub
    the variable wm doesn't have a PointCount property and it also complains that the vec variable doesn't have a X property.

    Am I missing another module/class?

    I have all X2 classes in the project.

    Walter
     
  17. Erel

    Erel Administrator Staff Member Licensed User

    walterf25 likes this.
  18. walterf25

    walterf25 Well-Known Member Licensed User

Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice