Games [x2][solved] Help needed regarding screen and objects Positions

Discussion in 'Game Development' started by fredo, Aug 1, 2019.

  1. fredo

    fredo Active Member Licensed User

    The enclosed test project is supposed to be a turn-based top down RPG board game for 2 characters.
    Planned course: Players shall roll their dice alternately and advance the corresponding number of fields, sometimes choosing which way to go.

    The x2 examples were used to create the basic structures and load the graphics.

    2019-08-01_18-31-53.png

    2019-08-01_18-33-37.png

    Code:
    ' ------- -------------- ------
    #CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"
    ' This is required to copy all files from the "Shared Files" folder to the "Files" folder of the respective platform.
    '     Erel --> https://www.b4x.com/android/forum/threads/xui2d-cross-platform-tips.96815/#content
    ' ------- -------------- ------

    ' ------- -------------- ------
    ' X2Test1 "Basic structures"
    '     x2notes    --> https://www.b4x.com/android/forum/threads/some-notes-to-better-understand-the-xui2d-examples.107702/
    '     x2examples --> https://www.b4x.com/android/forum/threads/xui2d-example-pack.96454/
    '   @Gunter’s roadmap into the game dev world --> https://www.b4x.com/android/forum/threads/video-tutorial.99172/#post-624377
    ' ------- -------------- ------

    #if B4A
    'ignore DIP related warnings as they are not relevant when working with BitmapCreator.
    #IgnoreWarnings: 6
    #end if

    Sub Class_Globals
        
    '
        ' Basic x2 libraries that are needed in every game
        Private xui As XUI 'ignore
        Public X2 As X2Utils
        
    Public world As B2World
        
    '
        ' Layout elements
        Private ivForeground As B4XView
        
    Private ivBackground As B4XView
        
    Public lblStats As B4XView
        
    Private pnlTouch As B4XView
        
    '
        ' TileMap specific definitions
        Public TileMap As X2TileMap
        
    Public Const ObjectLayer As String = "Object Layer 1"
        
    '
        ' ExtraClasses
        Private mChar1 As Figure
        
    Private mChar2 As Figure
        
        
    ' Gamestate
        Private GameOverState As Boolean
        
        
    ' Bodies and joints
        Private Border As X2BodyWrapper
        
    Private MouseMotor As B2MotorJoint
        
    '    Type EnemyTemplates(Template As X2TileObjectTemplate, XPosition As Float)
    '    Private EnemyTemplatesList As List   
        
        
    Type FigureTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private FigureTemplatesList As List   
        
        
    Type PointTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private PointTemplatesList As List   
        
        
    Type TextTemplates (Template As X2TileObjectTemplate, XPosition As Float)
        
    Private TextTemplatesList As List   
        

    End Sub

    Public Sub Initialize (Parent As B4XView)
        
    '
        ' ──────────────────────────────────
        ' Preparations for Layout and Views
        ' ──────────────────────────────────
        Parent.LoadLayout("GameLayout")
        lblStats.TextColor = xui.Color_Black
        lblStats.Color = 
    0x88ffffff
        lblStats.Font = xui.CreateDefaultBoldFont(
    20)
        
        
    ' ──────────────────────────────────
        ' Preparations for World
        ' ──────────────────────────────────
        world.Initialize("world", world.CreateVec2(0, -10))
        X2.Initialize(Me, ivForeground, world)
        
        
    Dim WorldWidth As Float = 36 'meters
        Dim WorldHeight As Float = WorldWidth / 1.333 'same ratio as in the designer script
        X2.ConfigureDimensions(world.CreateVec2(WorldWidth / 2, WorldHeight / 2), WorldWidth)
        
        
    ' ──────────────────────────────────
        ' Preparations for graphics
        ' ──────────────────────────────────
        GraphicCache_Put_Characters
        
        
    ' ──────────────────────────────────
        ' Preparations for screen
        ' ──────────────────────────────────
        SetBackground
        
    'CreateStaticBackground
        'CreateBorder
        
        
        
    ' ──────────────────────────────────
        ' Preparations for sounds
        ' ──────────────────────────────────
        'X2.SoundPool.AddSound("small jump", File.DirAssets, "small_jump.mp3")
        'X2.SoundPool.AddSound("big jump", File.DirAssets, "big_jump.mp3")
        'X2.SoundPool.AddSound("powerup", File.DirAssets, "powerup.mp3")     
        
        
    ' ──────────────────────────────────
        ' Debug settings
        ' ──────────────────────────────────
        X2.EnableDebugDraw    ' Comment out to disable debug drawing
        
    End Sub

    Private Sub SetWorldCenter
        
    ' The map size will not be identical to the screen size.
        ' This happens because the tile size in (bc) pixels needs to be a whole number.
        ' So we need to update the world center and move the map to the center.
        X2.UpdateWorldCenter(TileMap.MapAABB.Center)
    End Sub
    Public Sub WorldCenterUpdated (gs As X2GameStep)
        CreateEnemies
    End Sub
    private Sub SetBackground
        
    'X2.SetBitmapWithFitOrFill(ivBackground, xui.LoadBitmapResize(File.DirAssets, "mybackgroundimage.jpg", ivBackground.Width / 2, ivBackground.Height / 2, False))
    End Sub
     
    Private Sub GraphicCache_Put_Characters
        
    Log("#-Sub game.GraphicCache_Put_Characters")

        
    ' Use bitmap without the transparency placeholdercolor:
        Dim bc As BitmapCreator = X2.BitmapToBC( xui.LoadBitmap(File.DirAssets, "RPGCharacterSprites32x32.png"), 1)
        RemovePseudoTransparentColor(bc, 
    "#ff00ff"' pink, magenta
        Dim bmp As B4XBitmap = bc.Bitmap
        
        
    Dim NumberOfSprites As Int = 12
        
    Dim RowWidth As Int = 32
        
    Dim RowHeight As Int = 32
        
    Dim CharHeightMeters As Int = 3
        
    '
        Dim RowOfChar1 As Int = 2
        
    Dim character1 As B4XBitmap = bmp.Crop(0, RowHeight * RowOfChar1, NumberOfSprites * RowWidth, RowHeight)
        
    Dim AllChar1 As List = X2.ReadSprites(character1, 1, NumberOfSprites, CharHeightMeters, CharHeightMeters)
        X2.GraphicCache.PutGraphic(
    "character1 front walking"Array(AllChar1.Get(0), AllChar1.Get(1), AllChar1.Get(2), AllChar1.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character1 front standing"Array(AllChar1.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character1 back walking"Array(AllChar1.Get(4), AllChar1.Get(5), AllChar1.Get(6), AllChar1.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character1 back standing"Array(AllChar1.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character1 side walking"Array(AllChar1.Get(8), AllChar1.Get(9), AllChar1.Get(10)) )
        X2.GraphicCache.PutGraphic(
    "character1 side standing"Array(AllChar1.Get(9)) )
        
    '
        Dim RowOfChar2 As Int = 3
        
    Dim character2 As B4XBitmap = bmp.Crop(0, RowHeight * RowOfChar2, NumberOfSprites * RowWidth,  RowHeight)
        
    Dim AllChar2 As List = X2.ReadSprites(character2, 1, NumberOfSprites, CharHeightMeters, CharHeightMeters)
        X2.GraphicCache.PutGraphic(
    "character2 front walking"Array(AllChar2.Get(0), AllChar2.Get(1), AllChar2.Get(2), AllChar2.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character2 front standing"Array(AllChar2.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character2 back walking"Array(AllChar2.Get(4), AllChar2.Get(5), AllChar2.Get(6), AllChar2.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character2 back standing"Array(AllChar2.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character2 side walking"Array(AllChar2.Get(8), AllChar2.Get(9), AllChar2.Get(10)) )
        X2.GraphicCache.PutGraphic(
    "character2 side standing"Array(AllChar2.Get(9)) )
        
    '
        
    End Sub

    Private Sub RemovePseudoTransparentColor(TilesBC As BitmapCreator, clrstring As String)
        
    ' Erel --> https://www.b4x.com/android/forum/threads/x2-how-to-use-transparent-color.108173/#post-676534
        Dim clr As Int = 0xff000000 + Bit.ParseInt(clrstring.SubString(1), 16)
        
    Dim ptranspm As PremultipliedColor
        
    Dim trans As PremultipliedColor
        
    Dim pm As PremultipliedColor
        
    Dim argb As ARGBColor
        TilesBC.ColorToARGB(clr, argb)
        TilesBC.ARGBToPremultipliedColor(argb, ptranspm)
        
    For y = 0 To TilesBC.mHeight - 1
            
    For x = 0 To TilesBC.mWidth - 1
                TilesBC.GetPremultipliedColor(x, y, pm)
                
    If Bit.And(0xff, pm.r) = ptranspm.r And Bit.And(0xff, pm.g) = ptranspm.g And Bit.And(0xff, pm.b) = ptranspm.b And Bit.And(0xff, pm.a) = ptranspm.a Then
                    TilesBC.SetPremultipliedColor(x, y, trans)
                
    End If
            
    Next
        
    Next
    End Sub

    private Sub CreateObjects
        
    Log("#-Sub game.CreateObjects")
        FigureTemplatesList.Initialize
        PointTemplatesList.Initialize
        TextTemplatesList.Initialize

        
    Dim ol As X2ObjectsLayer = TileMap.Layers.Get(ObjectLayer)
        
    For Each TileMapTemplateX As X2TileObjectTemplate In ol.ObjectsById.Values
            
            
    If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("p"Then
                
    Dim pt As PointTemplates
                pt.Template = TileMapTemplateX
                pt.XPosition = TileMapTemplateX.Position.X
                PointTemplatesList.Add(pt)
                TileMap.CreateObject(TileMapTemplateX)
                
            
    else If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("text"Then
                
    Dim tt As TextTemplates
                tt.Template = TileMapTemplateX
                tt.XPosition = TileMapTemplateX.Position.X
                TextTemplatesList.Add(tt)
                TileMap.CreateObject(TileMapTemplateX)
            
            
    else If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("char"Then
                
    Dim ft As FigureTemplates
                ft.Template = TileMapTemplateX
                ft.XPosition = TileMapTemplateX.Position.X
                FigureTemplatesList.Add(ft)
                
                
    Dim bwChX As X2BodyWrapper = TileMap.CreateObject(TileMapTemplateX)
                bwChX.Body.BodyType = bwChX.Body.TYPE_KINEMATIC
                
                
    If TileMapTemplateX.Name.ToLowerCase.EndsWith("1"Then
                    mChar1.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar1.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id
                
    else If TileMapTemplateX.Name.ToLowerCase.EndsWith("2"Then
                    mChar2.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar2.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id
                
    End If
                
            
    End If
        
    Next
        
        FigureTemplatesList.SortType(
    "XPosition"True)
        PointTemplatesList.SortType(
    "XPosition"True)
        TextTemplatesList.SortType(
    "XPosition"True)
        
        
    Log("#-  x206, FigureTemplatesList.size = " & FigureTemplatesList.Size)
        
    Log("#-  x207, PointTemplatesList.size  = " & PointTemplatesList.Size)
        
    Log("#-  x208, TextTemplatesList.size   = " & TextTemplatesList.Size)
        
    End Sub
    Private Sub CreateEnemies
    '    Do While EnemyTemplatesList.Size > 0
    '        Dim et As EnemyTemplates = EnemyTemplatesList.Get(0)
    '        If et.XPosition <= X2.ScreenAABB.TopRight.X Then
    '            Dim bw As X2BodyWrapper = TileMap.CreateObject(et.Template)
    '            Dim enX As Enemy
    '            enX.Initialize(bw) 'this sets the delegate
    '            enX.IsGhost = (bw.GraphicName = "ghost")
    '            EnemyTemplatesList.RemoveAt(0)
    '        Else
    '            Exit
    '        End If
    '    Loop
    End Sub
    Private Sub CreateRevJoint12
    '    Dim template As X2TileObjectTemplate = TileMap.GetObjectTemplateByName(ObjectLayer, "hinge")
    '    Dim revdef As B2RevoluteJointDef
    '    revdef.Initialize(BodyXy1.Body, BodyXy2.Body, template.BodyDef.Position)
    '    revdef.SetLimits(0, cPI / 2)
    '    revdef.LimitEnabled = True
    '    revdef.MaxMotorTorque = 10
    '    revjoint12 = world.CreateJoint(revdef)
    '    revjoint12.MotorEnabled = True
    '    BodyXy2.Body.GravityScale = 0
    End Sub
    Private Sub CreateStaticBackground
        
    Dim bc As BitmapCreator
        bc.Initialize(ivBackground.Width / xui.Scale / 
    2, ivBackground.Height / xui.Scale / 2)
        bc.FillGradient(
    Array As Int(0xFF001AAC0xFFC5A400), bc.TargetRect, "TOP_BOTTOM")
        X2.SetBitmapWithFitOrFill(ivBackground, bc.Bitmap)
    End Sub
    Private Sub CreateBorder
        TileMap.CreateObject(TileMap.GetObjectTemplateByName(ObjectLayer, 
    "border"))
    End Sub

    ' ────────────────────────────────────────────────────────────────────────────────────────────────
    Public Sub Resize
        X2.ImageViewResized
    End Sub

    Public Sub DrawingComplete
        TileMap.DrawingComplete
    End Sub

    'Return True to stop the game loop.
    Public Sub BeforeTimeStep (GS As X2GameStep) As Boolean
        
    If GameOverState Then
            
    Return True
        
    End If

        
    Return False
    End Sub

    Public Sub Tick (GS As X2GameStep)
    '    Log("#-Sub game.Tick, gs.GameTimeMs = " & GS.GameTimeMs)
        TileMap.DrawScreen(Array("Tile Layer 1"), GS.DrawingTasks)
        mChar1.Tick(GS)
        mChar2.Tick(GS)
    End Sub

    ' ────────────────────────────────────────────────────────────────────────────────────────────────
    Public Sub GameOver
        X2.SoundPool.StopMusic
        X2.SoundPool.PlaySound(
    "gameover")
        X2.AddFutureTask(Me, 
    "Set_GameOver"3500Null)
    End Sub
    Private Sub Set_GameOver (ft As X2FutureTask)
        GameOverState = 
    True
        Sleep(
    500)
        StartGame
    End Sub
    Public Sub StopGame
        X2.SoundPool.StopMusic
        X2.Stop
    End Sub

    Public Sub StartGame
        
    If X2.IsRunning Then Return
        X2.Reset
        X2.UpdateWorldCenter(X2.CreateVec2(X2.ScreenAABB.Width / 
    2, X2.ScreenAABB.Height / 2))
        GameOverState = 
    False

        
    ' ──────────────────────────────────
        ' Preparations for Tilemap
        ' ──────────────────────────────────
        TileMap.Initialize(X2, File.DirAssets, "TiledMapFile_proj01.json", ivBackground)
        
    Dim TileSizeMeters As Float = X2.ScreenAABB.Height / TileMap.TilesPerColumn
        TileMap.SetSingleTileDimensionsInMeters(TileSizeMeters, TileSizeMeters)
        SetWorldCenter    
    ' Update the world center based on the map size
        TileMap.PrepareObjectsDef(ObjectLayer)

        Border = TileMap.CreateObject2ByName(ObjectLayer, 
    "border")   
        
        
        
    ' ──────────────────────────────────
        ' Draw Tilemap
        ' ──────────────────────────────────
        Dim tasks As List
        tasks.Initialize
        TileMap.Draw(
    Array("Tile Layer 1"), TileMap.MapAABB, tasks)
        
    For Each dt As DrawTask In tasks
            
    If dt.IsCompressedSource Then
                TileMap.CurrentBC.DrawCompressedBitmap(dt.Source, dt.SrcRect, dt.TargetX, dt.TargetY)
            
    End If
        
    Next
        
        
        
    ' ──────────────────────────────────
        ' Preparations for bodies
        ' ──────────────────────────────────
        CreateObjects


        
    ' ──────────────────────────────────
        ' Motors for Characters
        ' ──────────────────────────────────
        Dim MotorDefChar1 As B2MotorJointDef
        MotorDefChar1.Initialize(Border.Body, mChar1.bw.Body )
        MotorDefChar1.MaxMotorTorque = 
    1
        MotorDefChar1.MaxMotorForce = 
    1
        MotorDefChar1.CollideConnected = 
    True 'let the Char1 collide with the borders
        MouseMotor = X2.mWorld.CreateJoint(MotorDefChar1)
        MouseMotor.CorrectionFactor = 
    0.1

        
    Dim MotorDefChar2 As B2MotorJointDef
        MotorDefChar2.Initialize(Border.Body, mChar2.bw.Body )
        MotorDefChar2.MaxMotorTorque = 
    1
        MotorDefChar2.MaxMotorForce = 
    1
        MotorDefChar2.CollideConnected = 
    True 'let the Char2 collide with the borders
        MouseMotor = X2.mWorld.CreateJoint(MotorDefChar2)
        MouseMotor.CorrectionFactor = 
    0.1

        
        
    ' ──────────────────────────────────
        ' Start the Main loop
        ' ──────────────────────────────────
        X2.Start
        
    End Sub
     
    Sub pnlTouch_Touch (Action As Int, X As Float, Y As Float)
        
    If Action = pnlTouch.TOUCH_ACTION_MOVE_NOTOUCH Then Return

        
    Dim WorldPoint As B2Vec2 = X2.ScreenPointToWorld(X, Y)
        
    Dim MainBCPoint As B2Vec2 = X2.WorldPointToMainBC(WorldPoint.X, WorldPoint.Y)
        
        
    If Action = pnlTouch.TOUCH_ACTION_DOWN Then
            
    Dim FirstPointBC As B2Vec2 = X2.WorldPointToMainBC(mChar1.bw.Body.Position.X, mChar1.bw.Body.Position.Y)
            
    '        'Clone the paths before modifying them.
    '        PathMainBCForward = PathMainBCForward.Clone
    '        PathMainBCForward.Reset(FirstPointBC.X, FirstPointBC.Y)
    '        PathMainBCBackwards = PathMainBCBackwards.Clone
    '        PathMainBCBackwards.Reset(FirstPointBC.X, FirstPointBC.Y)
    '        PathWorld.Clear
            
        
    End If
        
    '    If PathWorld.Size > 0 Then
    '        Dim PrevPoint As B2Vec2 = PathWorld.Get(PathWorld.Size - 1)
    '        Dim distance As B2Vec2 = PrevPoint.CreateCopy
    '        distance.SubtractFromThis(WorldPoint)
    '        'to improve performance we skip very close points.
    '        If distance.LengthSquared < 0.1 Then
    '            Return
    '        End If
    '    End If
        
    '    PathMainBCForward = PathMainBCForward.Clone
    '    PathMainBCForward.LineTo(MainBCPoint.X, MainBCPoint.Y)
    '    PathWorld.Add(WorldPoint)
        
    End Sub

    Since the interaction of the X2 framework components has not yet been sufficiently understood, concrete references to the required "best practices" would be needed.

    In order to continue with the development, the following problem points need to be solved:
    1. The Bitmap of the Tilemap should have the same area of extension as the area of the form.
    2. The Characters should have their starting position on the sand areas on the left side.
    3. The characters should "drive" by motorjoint from one object-point (e.g. "p1") to a certain other object-point (e.g. "p6") on a path along the points series.
    4. If a character collides with a text object, an event should be triggered.
     

    Attached Files:

  2. Erel

    Erel Administrator Staff Member Licensed User

    Tip: developers who download the project should comment the #CustomBuildAction line.

    You want the world to be 36 x 36 meters. Your current world is set to be 36 x (36 * 1.333) meters.
    Set GameRatio in the designer script to 1.
    And change the world configurations in Game.Initialize to:
    Code:
    Dim WorldWidth As Float = 36 'meters
    Dim WorldHeight As Float = WorldWidth / 1 'same ratio as in the designer script
    Change the bodies type to dynamic. You cannot use forces and motors with kinematic types.
    I guess that you should set the gravity to 0, 0 and maybe also check 'is sensor'.
     
  3. fredo

    fredo Active Member Licensed User

    Thanks. I understand the "world" inits better now.

    2019-08-03_18-28-28.png


    Now I have to figure out how to move from point to point
    and check the collisions with objects that names begin with "Text"

    2019-08-03_18-40-40.png

     

    Attached Files:

  4. Erel

    Erel Administrator Staff Member Licensed User

    Peter Simpson and fredo like this.
  5. fredo

    fredo Active Member Licensed User

    OK, inspired by the mouse example
    Code:
    ' ------- -------------- ------
    #CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"

    ' This is required to copy all files from the "Shared Files" folder to the "Files" folder of the respective platform.
    '     Erel --> https://www.b4x.com/android/forum/threads/xui2d-cross-platform-tips.96815/#content
    ' ------- -------------- ------

    ' ------- -------------- ------
    ' X2Test1 "Basic structures"
    '     x2notes    --> https://www.b4x.com/android/forum/threads/some-notes-to-better-understand-the-xui2d-examples.107702/
    '     x2examples --> https://www.b4x.com/android/forum/threads/xui2d-example-pack.96454/
    '   @Gunter’s roadmap into the game dev world --> https://www.b4x.com/android/forum/threads/video-tutorial.99172/#post-624377
    ' ------- -------------- ------

    #if B4A
    'ignore DIP related warnings as they are not relevant when working with BitmapCreator.
    #IgnoreWarnings: 6
    #end if

    Sub Class_Globals
        
    '
        ' Basic x2 libraries that are needed in every game
        Private xui As XUI 'ignore
        Public X2 As X2Utils
        
    Public world As B2World
     
        
    '
        ' TileMap specific definitions
        Public TileMap As X2TileMap
        
    Public Const ObjectLayer As String = "Object Layer 1"
        
    '
        ' ExtraClasses
        Private mChar1 As Figure
        
    Private mChar2 As Figure
     
        
    ' Gamestate
        Private GameOverState As Boolean
     
        
    ' Bodies and joints
        Private Border As X2BodyWrapper
        
    Private CharMotor As B2MotorJoint
     
        
    Private PathMainBCForward As BCPath
        
    Private PathMainBCBackwards As BCPath
        
    Private PathWorld As List
        
    Private BrushRed As BCBrush
     
     
        
    ' Templates
    '    Type EnemyTemplates(Template As X2TileObjectTemplate, XPosition As Float)
    '    Private EnemyTemplatesList As List
     
        
    Type FigureTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private FigureTemplatesList As List
     
        
    Type PointTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private PointTemplatesList As List
     
        
    Type TextTemplates (Template As X2TileObjectTemplate, XPosition As Float)
        
    Private TextTemplatesList As List
     

        
    ' Layout elements
        Private ivForeground As B4XView
        
    Private ivBackground As B4XView
        
    Public lblStats As B4XView
        
    Private pnlTouch As B4XView
        
    Private RadioButton1 As RadioButton
        
    Private RadioButton2 As RadioButton
    End Sub

    Public Sub Initialize (Parent As B4XView)
        
    '
        ' ──────────────────────────────────
        ' Preparations for Layout and Views
        ' ──────────────────────────────────
        Parent.LoadLayout("GameLayout")
        lblStats.TextColor = xui.Color_Black
        lblStats.Color = 
    0x88ffffff
        lblStats.Font = xui.CreateDefaultBoldFont(
    20)
     
        
    ' ──────────────────────────────────
        ' Preparations for World
        ' ──────────────────────────────────
        world.Initialize("world", world.CreateVec2(00))
        X2.Initialize(Me, ivForeground, world)
     
        
    Dim WorldWidth As Float = 36 'meters
        Dim WorldHeight As Float = WorldWidth / 1 'same ratio as in the designer script (in GameLayout.bjl)!!!
        X2.ConfigureDimensions(world.CreateVec2(WorldWidth / 2, WorldHeight / 2), WorldWidth)
     
        
    ' ──────────────────────────────────
        ' Preparations for movements
        ' ──────────────────────────────────
        PathMainBCForward.Initialize(00)
         PathMainBCBackwards.Initialize(
    00)
        PathWorld.Initialize
        BrushRed = X2.MainBC.CreateBrushFromColor(xui.Color_Red)
     
        
    ' ──────────────────────────────────
        ' Preparations for graphics
        ' ──────────────────────────────────
        GraphicCache_Put_Characters
     
        
    ' ──────────────────────────────────
        ' Preparations for screen
        ' ──────────────────────────────────
        SetBackground
        
    'CreateStaticBackground
        'CreateBorder
     
     
        
    ' ──────────────────────────────────
        ' Preparations for sounds
        ' ──────────────────────────────────
        'X2.SoundPool.AddSound("small jump", File.DirAssets, "small_jump.mp3")
        'X2.SoundPool.AddSound("big jump", File.DirAssets, "big_jump.mp3")
        'X2.SoundPool.AddSound("powerup", File.DirAssets, "powerup.mp3")  
     
        
    ' ──────────────────────────────────
        ' Debug settings
        ' ──────────────────────────────────
        X2.EnableDebugDraw    ' Comment out to disable debug drawing
     
    End Sub

    Private Sub SetWorldCenter
        
    ' The map size will not be identical to the screen size.
        ' This happens because the tile size in (bc) pixels needs to be a whole number.
        ' So we need to update the world center and move the map to the center.
        X2.UpdateWorldCenter(TileMap.MapAABB.Center)
    End Sub
    Public Sub WorldCenterUpdated (gs As X2GameStep)
        CreateEnemies
    End Sub
    private Sub SetBackground
        
    'X2.SetBitmapWithFitOrFill(ivBackground, xui.LoadBitmapResize(File.DirAssets, "mybackgroundimage.jpg", ivBackground.Width / 2, ivBackground.Height / 2, False))
    End Sub
     
    Private Sub GraphicCache_Put_Characters
        
    Log("#-Sub game.GraphicCache_Put_Characters")

        
    ' Use bitmap without the transparency placeholdercolor:
        Dim bc As BitmapCreator = X2.BitmapToBC( xui.LoadBitmap(File.DirAssets, "RPGCharacterSprites32x32.png"), 1)
        RemovePseudoTransparentColor(bc, 
    "#ff00ff"' pink, magenta
        Dim bmp As B4XBitmap = bc.Bitmap
     
        
    Dim NumberOfSprites As Int = 12
        
    Dim RowWidth As Int = 32
        
    Dim RowHeight As Int = 32
        
    Dim CharHeightMeters As Int = 3
        
    '
        Dim RowOfChar1 As Int = 2
        
    Dim character1 As B4XBitmap = bmp.Crop(0, RowHeight * RowOfChar1, NumberOfSprites * RowWidth, RowHeight)
        
    Dim AllChar1 As List = X2.ReadSprites(character1, 1, NumberOfSprites, CharHeightMeters, CharHeightMeters)
        X2.GraphicCache.PutGraphic(
    "character1 front walking"Array(AllChar1.Get(0), AllChar1.Get(1), AllChar1.Get(2), AllChar1.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character1 front standing"Array(AllChar1.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character1 back walking"Array(AllChar1.Get(4), AllChar1.Get(5), AllChar1.Get(6), AllChar1.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character1 back standing"Array(AllChar1.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character1 side walking"Array(AllChar1.Get(8), AllChar1.Get(9), AllChar1.Get(10)) )
        X2.GraphicCache.PutGraphic(
    "character1 side standing"Array(AllChar1.Get(9)) )
        
    '
        Dim RowOfChar2 As Int = 3
        
    Dim character2 As B4XBitmap = bmp.Crop(0, RowHeight * RowOfChar2, NumberOfSprites * RowWidth,  RowHeight)
        
    Dim AllChar2 As List = X2.ReadSprites(character2, 1, NumberOfSprites, CharHeightMeters, CharHeightMeters)
        X2.GraphicCache.PutGraphic(
    "character2 front walking"Array(AllChar2.Get(0), AllChar2.Get(1), AllChar2.Get(2), AllChar2.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character2 front standing"Array(AllChar2.Get(3)))
        X2.GraphicCache.PutGraphic(
    "character2 back walking"Array(AllChar2.Get(4), AllChar2.Get(5), AllChar2.Get(6), AllChar2.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character2 back standing"Array(AllChar2.Get(7)))
        X2.GraphicCache.PutGraphic(
    "character2 side walking"Array(AllChar2.Get(8), AllChar2.Get(9), AllChar2.Get(10)) )
        X2.GraphicCache.PutGraphic(
    "character2 side standing"Array(AllChar2.Get(9)) )
        
    '
     
    End Sub

    Private Sub RemovePseudoTransparentColor(TilesBC As BitmapCreator, clrstring As String)
        
    ' Erel --> https://www.b4x.com/android/forum/threads/x2-how-to-use-transparent-color.108173/#post-676534
        Dim clr As Int = 0xff000000 + Bit.ParseInt(clrstring.SubString(1), 16)
        
    Dim ptranspm As PremultipliedColor
        
    Dim trans As PremultipliedColor
        
    Dim pm As PremultipliedColor
        
    Dim argb As ARGBColor
        TilesBC.ColorToARGB(clr, argb)
        TilesBC.ARGBToPremultipliedColor(argb, ptranspm)
        
    For y = 0 To TilesBC.mHeight - 1
            
    For x = 0 To TilesBC.mWidth - 1
                TilesBC.GetPremultipliedColor(x, y, pm)
                
    If Bit.And(0xff, pm.r) = ptranspm.r And Bit.And(0xff, pm.g) = ptranspm.g And Bit.And(0xff, pm.b) = ptranspm.b And Bit.And(0xff, pm.a) = ptranspm.a Then
                    TilesBC.SetPremultipliedColor(x, y, trans)
                
    End If
            
    Next
        
    Next
    End Sub

    private Sub CreateObjects
        
    Log("#-Sub game.CreateObjects")
        FigureTemplatesList.Initialize
        PointTemplatesList.Initialize
        TextTemplatesList.Initialize

        
    Dim ol As X2ObjectsLayer = TileMap.Layers.Get(ObjectLayer)
        
    For Each TileMapTemplateX As X2TileObjectTemplate In ol.ObjectsById.Values
         
            
    If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("p"Then
                
    Dim pt As PointTemplates
                pt.Template = TileMapTemplateX
                pt.XPosition = TileMapTemplateX.Position.X
                PointTemplatesList.Add(pt)
                TileMap.CreateObject(TileMapTemplateX)
             
            
    else If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("text"Then
                
    Dim tt As TextTemplates
                tt.Template = TileMapTemplateX
                tt.XPosition = TileMapTemplateX.Position.X
                TextTemplatesList.Add(tt)
                TileMap.CreateObject(TileMapTemplateX)
         
            
    else If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("char"Then
                
    Dim ft As FigureTemplates
                ft.Template = TileMapTemplateX
                ft.XPosition = TileMapTemplateX.Position.X
                FigureTemplatesList.Add(ft)
             
                
    Dim bwChX As X2BodyWrapper = TileMap.CreateObject(TileMapTemplateX)
                bwChX.Body.BodyType = bwChX.Body.TYPE_DYNAMIC   
    ' not .TYPE_KINEMATIC: You cannot use forces and motors with kinematic types.
             
                
    If TileMapTemplateX.Name.ToLowerCase.EndsWith("1"Then
                    mChar1.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar1.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id
                
    else If TileMapTemplateX.Name.ToLowerCase.EndsWith("2"Then
                    mChar2.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar2.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id
                
    End If
             
            
    End If
        
    Next
     
        FigureTemplatesList.SortType(
    "XPosition"True)
        PointTemplatesList.SortType(
    "XPosition"True)
        TextTemplatesList.SortType(
    "XPosition"True)
     
        
    Log("#-  x206, FigureTemplatesList.size = " & FigureTemplatesList.Size)
        
    Log("#-  x207, PointTemplatesList.size  = " & PointTemplatesList.Size)
        
    Log("#-  x208, TextTemplatesList.size   = " & TextTemplatesList.Size)
     
    End Sub
    Private Sub CreateEnemies
    '    Do While EnemyTemplatesList.Size > 0
    '        Dim et As EnemyTemplates = EnemyTemplatesList.Get(0)
    '        If et.XPosition <= X2.ScreenAABB.TopRight.X Then
    '            Dim bw As X2BodyWrapper = TileMap.CreateObject(et.Template)
    '            Dim enX As Enemy
    '            enX.Initialize(bw) 'this sets the delegate
    '            enX.IsGhost = (bw.GraphicName = "ghost")
    '            EnemyTemplatesList.RemoveAt(0)
    '        Else
    '            Exit
    '        End If
    '    Loop
    End Sub
    Private Sub CreateStaticBackground
        
    Dim bc As BitmapCreator
        bc.Initialize(ivBackground.Width / xui.Scale / 
    2, ivBackground.Height / xui.Scale / 2)
        bc.FillGradient(
    Array As Int(0xFF001AAC0xFFC5A400), bc.TargetRect, "TOP_BOTTOM")
        X2.SetBitmapWithFitOrFill(ivBackground, bc.Bitmap)
    End Sub
    Private Sub CreateBorder
        TileMap.CreateObject(TileMap.GetObjectTemplateByName(ObjectLayer, 
    "border"))
    End Sub

    ' ────────────────────────────────────────────────────────────────────────────────────────────────
    Public Sub Resize
        X2.ImageViewResized
    End Sub

    Public Sub DrawingComplete
        TileMap.DrawingComplete
    End Sub

    'Return True to stop the game loop.
    Public Sub BeforeTimeStep (GS As X2GameStep) As Boolean
        
    If GameOverState Then
            
    Return True
        
    End If

        
    Return False
    End Sub

    Public Sub Tick (GS As X2GameStep)
    '    Log("#-Sub game.Tick, gs.GameTimeMs = " & GS.GameTimeMs)
        TileMap.DrawScreen(Array("Tile Layer 1"), GS.DrawingTasks)
     
        MoveChar(GS)
     
    '    mChar1.Tick(GS)
    '    mChar2.Tick(GS)
     
     
    End Sub

    ' ────────────────────────────────────────────────────────────────────────────────────────────────
    Public Sub GameOver
        X2.SoundPool.StopMusic
        X2.SoundPool.PlaySound(
    "gameover")
        X2.AddFutureTask(Me, 
    "Set_GameOver"3500Null)
    End Sub
    Private Sub Set_GameOver (ft As X2FutureTask)
        GameOverState = 
    True
        Sleep(
    500)
        StartGame
    End Sub
    Public Sub StopGame
        X2.SoundPool.StopMusic
        X2.Stop
    End Sub

    Public Sub StartGame
        
    If X2.IsRunning Then Return
        X2.Reset
        X2.UpdateWorldCenter(X2.CreateVec2(X2.ScreenAABB.Width / 
    2, X2.ScreenAABB.Height / 2))
        GameOverState = 
    False

        
    ' ──────────────────────────────────
        ' Preparations for Tilemap
        ' ──────────────────────────────────
        TileMap.Initialize(X2, File.DirAssets, "TiledMapFile_proj01.json", ivBackground)
        
    Dim TileSizeMeters As Float = X2.ScreenAABB.Height / TileMap.TilesPerColumn
        TileMap.SetSingleTileDimensionsInMeters(TileSizeMeters, TileSizeMeters)
        SetWorldCenter    
    ' Update the world center based on the map size
        TileMap.PrepareObjectsDef(ObjectLayer)

        Border = TileMap.CreateObject2ByName(ObjectLayer, 
    "border")
     
        
    ' ──────────────────────────────────
        ' Draw Tilemap
        ' ──────────────────────────────────
        Dim tasks As List
        tasks.Initialize
        TileMap.Draw(
    Array("Tile Layer 1"), TileMap.MapAABB, tasks)
        
    For Each dt As DrawTask In tasks
            
    If dt.IsCompressedSource Then
                TileMap.CurrentBC.DrawCompressedBitmap(dt.Source, dt.SrcRect, dt.TargetX, dt.TargetY)
            
    End If
        
    Next
         
        
    ' ──────────────────────────────────
        ' Preparations for bodies
        ' ──────────────────────────────────
        CreateObjects

        
    ' ──────────────────────────────────
        ' Motors for Characters
        ' ──────────────────────────────────
        Dim MotorDefChar1 As B2MotorJointDef
        MotorDefChar1.Initialize(Border.Body, mChar1.bw.Body )
        MotorDefChar1.MaxMotorTorque = 
    1
        MotorDefChar1.MaxMotorForce = 
    1
        MotorDefChar1.CollideConnected = 
    True 'let the Char1 collide with the borders
        CharMotor = X2.mWorld.CreateJoint(MotorDefChar1)
        CharMotor.CorrectionFactor = 
    0.1

        
    Dim MotorDefChar2 As B2MotorJointDef
        MotorDefChar2.Initialize(Border.Body, mChar2.bw.Body )
        MotorDefChar2.MaxMotorTorque = 
    1
        MotorDefChar2.MaxMotorForce = 
    1
        MotorDefChar2.CollideConnected = 
    True 'let the Char2 collide with the borders
        CharMotor = X2.mWorld.CreateJoint(MotorDefChar2)
        CharMotor.CorrectionFactor = 
    0.1

     
        
    ' ──────────────────────────────────
        ' Start the Main loop
        ' ──────────────────────────────────
        X2.Start
     
    End Sub
     
    Sub pnlTouch_Touch (Action As Int, X As Float, Y As Float)
        
    ' Click is "FormPoint": x and y are the form-coordinates topleft=0,0 and bottomright=formheight,formwidth
        '
        If Action = pnlTouch.TOUCH_ACTION_MOVE_NOTOUCH Then Return
        
    Log("#-Sub pnlTouch_Touch, Action=" & Action & ", x=" & x & ", y=" & y)
     
        
    If RadioButton1.Selected Then
            
    Dim bwcAct As X2BodyWrapper = mChar1.bw
        
    Else
            
    Dim bwcAct As X2BodyWrapper = mChar2.bw
        
    End If
     
        
    Dim WorldPoint As B2Vec2 = X2.ScreenPointToWorld(X, Y)
        
    Dim MainBCPoint As B2Vec2 = X2.WorldPointToMainBC(WorldPoint.X, WorldPoint.Y)
     
        
    If Action = pnlTouch.TOUCH_ACTION_DOWN Then
            
    Dim FirstPointBC As B2Vec2 = X2.WorldPointToMainBC(bwcAct.Body.Position.X, bwcAct.Body.Position.Y)
         
            
    ' CLONE the paths before modifying them.
            PathMainBCForward = PathMainBCForward.Clone
            PathMainBCForward.Reset(FirstPointBC.X, FirstPointBC.Y)
            PathMainBCBackwards = PathMainBCBackwards.Clone
            PathMainBCBackwards.Reset(FirstPointBC.X, FirstPointBC.Y)
            PathWorld.Clear
         
        
    End If
     
        
    If PathWorld.Size > 0 Then
            
    Dim PrevPoint As B2Vec2 = PathWorld.Get(PathWorld.Size - 1)
            
    Dim distance As B2Vec2 = PrevPoint.CreateCopy
            distance.SubtractFromThis(WorldPoint)
            
    'to improve performance we skip very close points.
            If distance.LengthSquared < 0.1 Then
                
    Return
            
    End If
        
    End If
     
        PathMainBCForward = PathMainBCForward.Clone
        PathMainBCForward.LineTo(MainBCPoint.X, MainBCPoint.Y)
        PathWorld.Add(WorldPoint)
    End Sub

    Sub MoveChar(gs As X2GameStep)
        
    If RadioButton1.Selected Then
            
    Dim bwcAct As X2BodyWrapper = mChar1.bw
        
    Else
            
    Dim bwcAct As X2BodyWrapper = mChar2.bw
        
    End If

        
    'This loop might be a bit confusing. The loop ends after the first far enough point.
        Do While PathWorld.Size > 0
            
    Dim NextPoint As B2Vec2 = PathWorld.Get(0)
            
    Dim CurrentPoint As B2Vec2 = bwcAct.Body.Position
            
    Dim distance As B2Vec2 = NextPoint.CreateCopy
            distance.SubtractFromThis(CurrentPoint)
            
    If (distance.Length < 0.3 And PathWorld.Size > 1Or (distance.Length < 0.1Then
                PathWorld.RemoveAt(
    0)
             
                
    Dim v As B2Vec2 = X2.WorldPointToMainBC(NextPoint.X, NextPoint.Y)
             
                
    'clone the paths before modifying them as they are being drawn asynchronously.
                PathMainBCForward = PathMainBCForward.Clone
                PathMainBCBackwards = PathMainBCBackwards.Clone
             
                
    'remove the first point from the "forward" path and add it to the "backwards" path.
                PathMainBCForward.Points.RemoveAt(0)
                PathMainBCForward.Invalidate 
    'need to call Invalidate after we directly access the points list.
                PathMainBCBackwards.LineTo(v.X, v.Y)
                
    Continue 'skip to the next point
            End If
         
            CharMotor.AngularOffset = FindAngleToTarget(bwcAct.Body, NextPoint)
         
            
    Dim delta As B2Vec2 = NextPoint.CreateCopy
            delta.SubtractFromThis(Border.Body.Position)
            CharMotor.LinearOffset = delta
         
            
    'draw the small red circle
            v = X2.WorldPointToMainBC(NextPoint.X, NextPoint.Y)
            gs.DrawingTasks.Add(X2.MainBC.AsyncDrawCircle(v.X, v.Y, 
    5,  BrushRed, True0))
            
    Exit '<-----
        Loop
    End Sub
    Sub FindAngleToTarget(Body As B2Body, Target As B2Vec2) As Float
        
    If Abs(Body.Angle) > 2 * cPI Then
            
    'make sure that the current angle is between -2*cPI to 2*cPI
            Body.SetTransform(Body.Position, X2.ModFloat(Body.Angle, 2 * cPI))
        
    End If
        
    Dim angle As Float = ATan2(Target.Y - Body.Position.Y, Target.X - Body.Position.X) + cPI / 2
        
    Dim CurrentAngle As Float = Body.Angle
        
    'find the shortest direction
        Dim anglediff As Float = angle - CurrentAngle
        
    If anglediff > cPI Then
            angle = -(
    2 * cPI - angle)
        
    Else If anglediff < -cPI Then
            angle = angle + 
    2 * cPI
        
    End If
        
    Return angle
    End Sub


    'must handle this event if we want to handle the PreSolve event.
    Private Sub World_BeginContact (Contact As B2Contact)
        
    Dim bodies As X2BodiesFromContact = X2.GetBodiesFromContact(Contact"char1")
        
    Log("#-Sub World_BeginContact, bodies.OtherBody.Name = " & bodies.OtherBody.Name)
        
    If bodies <> Null Then
    '        If bodies.OtherBody.Name = "mushroom" Then
    '            'we cannot modify the world state inside these events. So we add a future task with time = 0.
    '            X2.AddFutureTask(mChar1, "Touch_Mushroom", 0, bodies.OtherBody)
    '        End If
        End If
     
    '    Dim bodies As X2BodiesFromContact = X2.GetBodiesFromContact(Contact, "left edge")
    '    If bodies <> Null And bodies.OtherBody.DelegateTo Is Enemy Then
    '        X2.AddFutureTask(Me, "Delete_Enemy", 0, bodies.OtherBody)
    '        Return
    '    End If
     
    End Sub
    Private Sub World_PreSolve (Contact As B2Contact, OldManifold As B2Manifold)
        
    Dim BodyA As X2BodyWrapper = Contact.FixtureA.Body.Tag
        
    Dim BodyB As X2BodyWrapper = Contact.FixtureB.Body.Tag
        
    If BodyA.IsVisible = False Or BodyB.IsVisible = False Then Return
    '    CheckMarioCollisions (Contact, X2.GetBodiesFromContact(Contact, "mario"))
    '    CheckEnemyCollisions(Contact, X2.GetBodiesFromContact(Contact, "enemy bug"))
    '    CheckEnemyCollisions(Contact, X2.GetBodiesFromContact(Contact, "enemy turtle"))
    End Sub


    Result


    2019-08-04_19-34-25.png

    Although it is still far from controlled steering, it is at least the first measurable result.
     

    Attached Files:

    Last edited: Aug 5, 2019
    Erel and inakigarm like this.
  6. Erel

    Erel Administrator Staff Member Licensed User

    Check the 'fixed rotation' property if you don't want the characters to rotate.
     
    fredo and Peter Simpson like this.
  7. fredo

    fredo Active 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