Games [x2][solved] Help needed regarding Object Movement

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

  1. fredo

    fredo Active Member Licensed User

    This is a follow-up request to https://www.b4x.com/android/forum/t...egarding-screen-and-objects-positions.108254/
    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.

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

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

    Code:
    '
    ' Java source --> file:///.\Objects\src\b4j\gametest\sn\game.java
    '
    ' ------- -------------- ------
    '''#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
        
    Private LastDiceRollVal As Int = 0 ' ####testingonly
       
        
    ' 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
       
        
    'Private ActiveCharacterBody As X2BodyWrapper
        Private ActiveCharacterFigure As Figure
       
        
    ' Templates
        Type FigureTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private FigureTemplatesList As List  
       
        
    Type PointTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private PointTemplatesList As List  
        
    Private PointTemplatesListLoop0 As List  
       
        
    Type TextTemplates (Template As X2TileObjectTemplate, XPosition As Float)
        
    Private TextTemplatesList As List  
       
        
    Type LocationTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private LocationTemplatesList As List  
       

        
    ' Layout elements
        Private ivForeground As B4XView
        
    Private ivBackground As B4XView
        
    Public lblStats As B4XView
        
    Private pnlTouch As B4XView
        
    Private RadioButton1 As RadioButton' ####testingonly
        Private RadioButton2 As RadioButton' ####testingonly
        Private Button1 As Button' ####testingonly
        Private Label2 As Label' ####testingonly
        Private Pane1 As Pane' ####testingonly
        Private fx As JFX' ####testingonly
        Private TempTestPane As Pane' ####testingonly
    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)
       
        CSSUtils.SetBackgroundColor(Pane1, fx.Colors.LightGray)
    ' ####testingonly
       
        
    ' ──────────────────────────────────
        ' 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 PositionObjects
        
    For Each LocationTemplateX As LocationTemplates In LocationTemplatesList
            
    ' Initial position on location-objects (works ok)
            Select Case True
                
    Case LocationTemplateX.Template.Name.ToLowerCase.EndsWith("c1")
                    mChar1.bw.Body.SetTransform(LocationTemplateX.Template.Position, 
    0)
                
    Case LocationTemplateX.Template.Name.ToLowerCase.EndsWith("c2")
                    mChar2.bw.Body.SetTransform(LocationTemplateX.Template.Position, 
    0)
            
    End Select
        
    Next
    End Sub
    private Sub CreateObjects
        
    Log("#-Sub game.CreateObjects")
        FigureTemplatesList.Initialize
        PointTemplatesList.Initialize
        PointTemplatesListLoop0.Initialize
        TextTemplatesList.Initialize
        LocationTemplatesList.Initialize

        TempTestPane.RemoveAllNodes    
    ' ####testingonly

        
    Dim ol As X2ObjectsLayer = TileMap.Layers.Get(ObjectLayer)
        
    For Each TileMapTemplateX As X2TileObjectTemplate In ol.ObjectsById.Values
            
    'Log("#-    x203, TileMapTemplateX.Name = " & TileMapTemplateX.Name)
            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)
                
    If Not(TileMapTemplateX.Name.Contains(".")) And Not(TileMapTemplateX.Name.Contains("x")) Then
                    PointTemplatesListLoop0.Add(pt)
                
    End If
               
                
    ' ####testingonly
                Dim lblx As Label
                lblx.Initialize(
    "")
                lblx.Text = TileMapTemplateX.Name
                lblx.TextColor = fx.Colors.Yellow
                lblx.Alignment = 
    "CENTER"
                
    Dim bp As B2Vec2 = X2.WorldPointToMainBC( TileMapTemplateX.Position.X, TileMapTemplateX.Position.Y)
                
    Private DebugScale As Float = 1.1 ' found by trial and error
                bp.MultiplyThis(DebugScale)
                TempTestPane.AddNode(lblx, bp.X, bp.Y, 
    40dip40dip)
                
    ' /####testingonly
               
               
            
    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
                    
    Log("#-      x252, mChar1.Initialize, bwChX=" & bwChX.Name)
                    mChar1.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar1.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id

                    
    ' not working...
                    Dim MotorDefChar1 As B2MotorJointDef
                    MotorDefChar1.Initialize(Border.Body, mChar1.bw.Body)
                    MotorDefChar1.MaxMotorTorque = 
    1
                    MotorDefChar1.MaxMotorForce = 
    1
                    MotorDefChar1.CollideConnected = 
    True 'let the Char collide with the borders
                    CharMotor = X2.mWorld.CreateJoint(MotorDefChar1)
                    CharMotor.CorrectionFactor = 
    0.1
                   


                
    else If TileMapTemplateX.Name.ToLowerCase.EndsWith("2"Then
                    
    Log("#-      x268, mChar2.Initialize, bwChX=" & bwChX.Name)
                    mChar2.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar2.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id
                   
                    
    '' not working...
                    'Dim MotorDefChar2 As B2MotorJointDef
                    'MotorDefChar2.Initialize(Border.Body, mChar2.bw.Body)
                    'MotorDefChar2.MaxMotorTorque = 1
                    'MotorDefChar2.MaxMotorForce = 1
                    'MotorDefChar2.CollideConnected = True 'let the Char collide with the borders
                    'CharMotor = X2.mWorld.CreateJoint(MotorDefChar2)
                    'CharMotor.CorrectionFactor = 0.1

                
    End If
           
                   

           
           
            
    else If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("loc"Then
                
    Dim lt As LocationTemplates
                lt.Template = TileMapTemplateX
                lt.XPosition = TileMapTemplateX.Position.X
                LocationTemplatesList.Add(lt)
                TileMap.CreateObject(TileMapTemplateX)
               
    '            If TileMapTemplateX.Name.ToLowerCase
    '            LocC1Body = TileMap.CreateObject2ByName(ObjectLayer, "locC1")
               
            
    End If
        
    Next
       
        FigureTemplatesList.SortType(
    "XPosition"True)
        PointTemplatesList.SortType(
    "XPosition"True)
        TextTemplatesList.SortType(
    "XPosition"True)
        LocationTemplatesList.SortType(
    "XPosition"True)
       
        
    Log("#-  x206, FigureTemplatesList.size   = " & FigureTemplatesList.Size)
        
    Log("#-  x207, PointTemplatesList.size    = " & PointTemplatesList.Size)
        
    Log("#-  x208, TextTemplatesList.size     = " & TextTemplatesList.Size)
        
    Log("#-  x209, LocationTemplatesList.size = " & LocationTemplatesList.Size)
       
    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
        PositionObjects
        ActiveCharacterFigure = mChar1
       
        
    ' ──────────────────────────────────
        ' Start the Main loop
        ' ──────────────────────────────────
        X2.Start
       
    End Sub
     
    Sub pnlTouch_Touch (Action As Int, X As Float, Y As Float)
        
    ' Click is on a "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)
       
        
    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(ActiveCharacterFigure.bw.Body.Position.X, ActiveCharacterFigure.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

    Sub MoveChar(gs As X2GameStep)
       
        
    '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 = ActiveCharacterFigure.bw.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
           
    '        Log("#-  x467, ActiveCharacterBody = " & ActiveCharacterBody.Name)
            CharMotor.AngularOffset = FindAngleToTarget(ActiveCharacterFigure.bw.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
    Private Sub World_PostSolve (Contact As B2Contact, Impulse As B2ContactImpulse)
       
    End Sub

    Sub ActiveCharacterSelect_SelectedChange(Selected As Boolean) ' ####testingonly
        LastDiceRollVal = 0
        Label2.Text = 
    "..."
        
    If Not(Selected) Then Return
       
        
    Log("#-ActiveCharacterSelect_SelectedChange, Selected=" & Selected)
        
    Dim rbx As RadioButton = Sender
        
    Dim tagx As String = rbx.Tag
        
    Select Case True
            
    Case tagx.ToLowerCase = "rbc1"
                ActiveCharacterFigure = mChar1
               
            
    Case tagx.ToLowerCase = "rbc2"
                ActiveCharacterFigure = mChar2
               
        
    End Select
        
    Log("#-  x536, tagx.ToLowerCase = " & tagx.ToLowerCase)
        
    Log("#-  x537, ActiveCharacterBody.Name = " & ActiveCharacterFigure.bw.Name)
    End Sub
    Sub Button1_Click ' ####testingonly
        LastDiceRollVal = Rnd(1,12)
        Label2.Text = LastDiceRollVal
        CharAdvance(LastDiceRollVal)
    End Sub
    Sub CharAdvance(NumberOfSteps As Int)
        
    Log("#-Sub game.CharAdvance, NumberOfSteps=" & NumberOfSteps)
        
    Dim NewPointTemplatesListIndex As Int =    ActiveCharacterFigure.LastPositionIndex +NumberOfSteps
        
    Log("#-  x579, NewPointTemplatesListIndex=" & NewPointTemplatesListIndex)
       
        
    For i=ActiveCharacterFigure.LastPositionIndex To NewPointTemplatesListIndex
            
    Dim GotToPosIndex As Int = i Mod PointTemplatesListLoop0.Size
           
            
    Dim pt As PointTemplates = PointTemplatesListLoop0.Get(GotToPosIndex)
            
    Log("#-    x580, GotToPosIndex=" & GotToPosIndex & ", pt.Template.Position=" & pt.Template.Position)
           
           
            
    '##### An experiment to move the active character the "nonmotor" way      
            Dim v As B2Vec2 = ActiveCharacterFigure.bw.Body.Position.CreateCopy
            ActiveCharacterFigure.bw.Body.LinearVelocity = v
            
    '/####
           
                   
        
    Next
        ActiveCharacterFigure.LastPositionIndex = NewPointTemplatesListIndex
    End Sub
    Code:
    ' Class "Figure"

    Sub Class_Globals
        
    Public FigureNameAndId As String = ""
        
    Public bw As X2BodyWrapper
        
    Public InAir As Boolean
        
    Public IsSmall As Boolean = True
        
    Public LastPositionIndex As Int = 0
       
        
    Private x2 As X2Utils 'ignore
        Private LastTickTime As Int
        
    Private SpecialState As Boolean
        
    Private FaceRight As Boolean = True
        
    Private MaxVelocity As Float = 10
        
    Private ImpulseVector As B2Vec2
        
    Private ProtectedTime As Int
    End Sub

    Public Sub Initialize (wrapper As X2BodyWrapper)
    '    Log("#-Sub figure.Initialize")
        LastPositionIndex = 0
        bw = wrapper
        x2 = bw.X2
        bw.DelegateTo = Me
        UpdateImpulseVector
        CreateChar1Legs
    End Sub

    Private Sub CreateChar1Legs
        
    ' see 1--> https://www.b4x.com/android/forum/threads/xui2d-super-mario-example-1.96151/
        ' see 2--> https://www.b4x.com/android/forum/threads/xui2d-super-mario-example-2.96236/
        Dim rect As B2PolygonShape
        
    rect.Initialize
        
    rect.SetAsBox2(0.450.05, x2.CreateVec2(0, -x2.GetShapeWidthAndHeight(bw.Body.FirstFixture.Shape).y / 2 + 0.05), 0)
        
    Dim f As B2Fixture = bw.Body.CreateFixture2(rect0.1)
        f.Friction = 
    1
        f.Tag = 
    "legs"
    End Sub

    Private Sub UpdateImpulseVector
        
    Log("#-Sub figure.UpdateImpulseVector, bw.Name=" & bw.Name)
        ImpulseVector = x2.CreateVec2(
    0.5 * bw.Body.Mass * x2.TimeStepMs / 160)
    End Sub

    Public Sub Hit_Start (ft As X2FutureTask)
        
    If SpecialState Then Return
        
    If x2.gs.GameTimeMs < ProtectedTime Then Return


       
    End Sub

    Private Sub StartGameOver
        SpecialState = 
    True
        bw.GraphicName = 
    "Char1 small strike"
        bw.Body.FirstFixture.SetFilterBits(
    00)
        bw.Body.FirstFixture.NextFixture.SetFilterBits(
    00)
        bw.Body.LinearVelocity = x2.CreateVec2(
    015)
        bw.mGame.GameOver
    End Sub

    Public Sub Tick (GS As X2GameStep)
    '    Log("#-Sub figure.Tick")
        If LastTickTime = GS.GameTimeMs Then Return
        LastTickTime = GS.GameTimeMs

        
    ' ???
       
        
    If GS.ShouldDraw Then
            bw.UpdateGraphic(GS, 
    True)
        
    End If
    End Sub

    Public Sub IsLegsFixture (Fixture As B2Fixture) As Boolean
        
    Return Fixture.Tag <> Null And Fixture.Tag = "legs"
    End Sub

    2019-08-06_13-49-32.png

    While positioning works quite well so far, there are still problems understanding the movement of objects from one point to another.

    1. By reviewing the examples, the MotorJoint was found in the mouse example and tested without success.
    2. A movement with Body.LinearVelocity was tried, but without real control over the behavior.

    The intended process is as follows:
    • In Game.CreateObjects a list with the positions of certain points from TiledMap is created (works)
    • After building the screen the first character is selected and a random integer (1..12) is created (by button)
    • The figure Char1 is moved from the current position along the list of points to the next position (oldindex +randomvalue).

    As it looks, I currently need concrete help on code level.

    I would be grateful if experienced X2 experts could take a quick look at the test project and help me to implement the movement using motorjoint.
     

    Attached Files:

  2. Erel

    Erel Administrator Staff Member Licensed User

    Code to move char 1 with the motor joint:
    Code:
    Sub MoveChar1To (vec As B2Vec2)
       vec.SubtractFromThis(Border.Body.Position)
       CharMotor.LinearOffset = vec
    End Sub
    For example to move it to 20, 20:
    Code:
    MoveChar1To(X2.CreateVec2(2020))
    I've tested it with these settings:
    Code:
    mChar1.bw.Body.LinearDamping = 1
    Dim MotorDefChar1 As B2MotorJointDef
    mChar1.bw.Body.SleepingAllowed = 
    False
    MotorDefChar1.Initialize(Border.Body, mChar1.bw.Body)
    MotorDefChar1.MaxMotorForce = 
    20
    MotorDefChar1.CollideConnected = 
    True 'let the Char collide with the borders
    CharMotor = X2.mWorld.CreateJoint(MotorDefChar1)
    CharMotor.CorrectionFactor = 
    0.05
     
    fredo likes this.
  3. fredo

    fredo Active Member Licensed User

    Thanks, that got me further.

    2019-08-06_19-09-13.png

    Now I need a solution how to prevent that overshooting.
     

    Attached Files:

  4. Erel

    Erel Administrator Staff Member Licensed User

    Always try to avoid repeating the same code. In this case you should create a sub that creates the motor:
    Code:
    Sub CreateMotor(character As Figure) As B2MotorJoint
       
    Dim MotorDefChar2 As B2MotorJointDef
       MotorDefChar2.Initialize(Border.Body, character.bw.Body)
       MotorDefChar2.MaxMotorForce = 
    500
       MotorDefChar2.CollideConnected = 
    True 'let the Char collide with the borders
       Dim mc As B2MotorJoint = X2.mWorld.CreateJoint(MotorDefChar2)
       mc.CorrectionFactor = 
    0.02
       
    Return mc
    End Sub
    I'm getting good results with the above code (in release mode).
     
    fredo likes this.
  5. fredo

    fredo Active Member Licensed User

    Sure, you're right

    Code:
    '
    ' Java source --> file:///.\Objects\src\b4j\gametest\sn\game.java
    '
    ' ------- -------------- ------
    '#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
        
    Private ActiveCharIndex As Int = 1
        
    Private LastDiceRollVal As Int = 0
        
    Private CharLastPositionIndex(3As Int
        
        
        
    ' Bodies and joints
        Private Border As X2BodyWrapper
        
    Private MotorChar1 As B2MotorJoint
        
    Private MotorChar2 As B2MotorJoint
        
        
    Private PathMainBCForward As BCPath
        
    Private PathMainBCBackwards As BCPath
        
    Private PathWorld As List
        
    Private BrushRed As BCBrush
        
        
        
    ' Templates
        Type FigureTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private FigureTemplatesList As List
        
        
    Type PointTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private PointTemplatesList As List
        
    Private PointTemplatesListLoop0 As List
        
        
    Type TextTemplates (Template As X2TileObjectTemplate, XPosition As Float)
        
    Private TextTemplatesList As List
        
        
    Type LocationTemplates(Template As X2TileObjectTemplate, XPosition As Float)
        
    Private LocationTemplatesList As List
        

        
    ' Layout elements
        Private ivForeground As B4XView
        
    Private ivBackground As B4XView
        
    Public lblStats As B4XView
        
    Private pnlTouch As B4XView
        
    Private RadioButton1 As RadioButton' ####testingonly
        Private RadioButton2 As RadioButton' ####testingonly
        Private Button1 As Button' ####testingonly
        Private Label2 As Label' ####testingonly
        Private Pane1 As Pane' ####testingonly
        Private fx As JFX' ####testingonly
        Private TempTestPane As Pane' ####testingonly
        Private Label3 As Label' ####testingonly
        Private Label4 As Label' ####testingonly
    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)
        
        CSSUtils.SetBackgroundColor(Pane1, fx.Colors.LightGray)
    ' ####testingonly
        
        
    ' ──────────────────────────────────
        ' 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)
        CharLastPositionIndex(
    0) = -1 ' not used
        CharLastPositionIndex(1) = 0 ' for Char1
        CharLastPositionIndex(2) = 0 ' for Char2
        
        
    ' ──────────────────────────────────
        ' Preparations for graphics
        ' ──────────────────────────────────
        GraphicCache_Put_Characters
        
        
    ' ──────────────────────────────────
        ' Preparations for screen
        ' ──────────────────────────────────
        SetBackground
        
    'CreateStaticBackground
        'CreateBorder
        
        
        
    ' ──────────────────────────────────
        ' Preparations for sounds
        ' ──────────────────────────────────
        X2.SoundPool.AddSound("rolldice"File.DirAssets, "dice-4.wav")
        
    '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 PositionObjects
        
    For Each LocationTemplateX As LocationTemplates In LocationTemplatesList
            
    ' Initial position on location-objects (works ok)
            Select Case True
                
    Case LocationTemplateX.Template.Name.ToLowerCase.EndsWith("c1")
                    mChar1.bw.Body.SetTransform(LocationTemplateX.Template.Position, 
    0)
                
    Case LocationTemplateX.Template.Name.ToLowerCase.EndsWith("c2")
                    mChar2.bw.Body.SetTransform(LocationTemplateX.Template.Position, 
    0)
            
    End Select
        
    Next
    End Sub
    private Sub CreateObjects
        
    Log("#-Sub game.CreateObjects")
        FigureTemplatesList.Initialize
        PointTemplatesList.Initialize
        PointTemplatesListLoop0.Initialize
        TextTemplatesList.Initialize
        LocationTemplatesList.Initialize

        TempTestPane.RemoveAllNodes    
    ' ####testingonly

        
    Dim tempcounter_pt0 As Int = 0'####temp
        Dim ol As X2ObjectsLayer = TileMap.Layers.Get(ObjectLayer)
        
    For Each TileMapTemplateX As X2TileObjectTemplate In ol.ObjectsById.Values
            
    'Log("#-    x203, TileMapTemplateX.Name = " & TileMapTemplateX.Name)
            
            
    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)
                
    If Not(TileMapTemplateX.Name.Contains(".")) And Not(TileMapTemplateX.Name.Contains("x")) Then
                    
    Log("#-    x250, " & $"PointTemplatesListLoop0(${tempcounter_pt0})= $1.0{pt.Template.Position.X}, $1.0{pt.Template.Position.Y}  "$)
                    PointTemplatesListLoop0.Add(pt)
                    tempcounter_pt0 = tempcounter_pt0 +
    1
                
    End If
                
                
    ' ####testingonly
                ' Show the labels of points
                Dim lblx As Label
                lblx.Initialize(
    "")
                lblx.Text = TileMapTemplateX.Name
                lblx.TextColor = fx.Colors.Yellow
                lblx.Alignment = 
    "CENTER"
                
    Dim bp As B2Vec2 = X2.WorldPointToMainBC( TileMapTemplateX.Position.X, TileMapTemplateX.Position.Y)
                
    Private DebugScale As Float = 1.1 ' found by trial and error
                bp.MultiplyThis(DebugScale)
                TempTestPane.AddNode(lblx, bp.X, bp.Y, 
    40dip40dip)
                
    ' /####testingonly
                
                
            
    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
                    mChar1.bw.Body.LinearDamping = 
    0.01
                    mChar1.bw.Body.SleepingAllowed = 
    False
                    MotorChar1 = CreateMotor(mChar1)


                
    else If TileMapTemplateX.Name.ToLowerCase.EndsWith("2"Then
                    mChar2.Initialize(bwChX) 
    ' Set the delegate (the class "Figure")
                    mChar2.FigureNameAndId = TileMapTemplateX.Name & "~" & TileMapTemplateX.id
                    mChar2.bw.Body.LinearDamping = 
    0.01
                    mChar2.bw.Body.SleepingAllowed = 
    False
                    MotorChar2 = CreateMotor(mChar2)
                    
                
    End If
            
            
    else If TileMapTemplateX.FirstTime And TileMapTemplateX.Name.ToLowerCase.StartsWith("loc"Then
                
    Dim lt As LocationTemplates
                lt.Template = TileMapTemplateX
                lt.XPosition = TileMapTemplateX.Position.X
                LocationTemplatesList.Add(lt)
                TileMap.CreateObject(TileMapTemplateX)
                
    '            If TileMapTemplateX.Name.ToLowerCase
    '            LocC1Body = TileMap.CreateObject2ByName(ObjectLayer, "locC1")
                
            
    End If
        
    Next
        
        FigureTemplatesList.SortType(
    "XPosition"True)
        PointTemplatesList.SortType(
    "XPosition"True)
        TextTemplatesList.SortType(
    "XPosition"True)
        LocationTemplatesList.SortType(
    "XPosition"True)
        
        
    Log("#-  x206, FigureTemplatesList.size   = " & FigureTemplatesList.Size)
        
    Log("#-  x207, PointTemplatesList.size    = " & PointTemplatesList.Size)
        
    Log("#-  x208, TextTemplatesList.size     = " & TextTemplatesList.Size)
        
    Log("#-  x209, LocationTemplatesList.size = " & LocationTemplatesList.Size)
        
    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
    private Sub CreateMotor(character As Figure) As B2MotorJoint
        
    ' Erel --> https://www.b4x.com/android/forum/threads/x2-help-needed-regarding-object-movement.108390/#post-677540
        Dim MotorDefChar2 As B2MotorJointDef
        MotorDefChar2.Initialize(Border.Body, character.bw.Body)
        MotorDefChar2.MaxMotorForce = 
    500
        MotorDefChar2.CollideConnected = 
    True 'let the Char collide with the borders
        Dim mc As B2MotorJoint = X2.mWorld.CreateJoint(MotorDefChar2)
        
    'mc.CorrectionFactor = 0.02
        mc.CorrectionFactor = 0.03
        
    Return mc
    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
        PositionObjects
        ActiveCharacterFigure = mChar1
        
        
    ' ──────────────────────────────────
        ' Start the Main loop
        ' ──────────────────────────────────
        X2.Start
        
    End Sub
     
    Sub pnlTouch_Touch (Action As Int, X As Float, Y As Float)
        
    ' Click is on a "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)
        
        
    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(ActiveCharacterFigure.bw.Body.Position.X, ActiveCharacterFigure.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


    Sub MoveCharTo (CharIndex As Int, vec As B2Vec2)
        vec.SubtractFromThis(Border.Body.Position)
        
    Select Case CharIndex
            
    Case 1
                MotorChar1.LinearOffset = vec
            
    Case 2
                MotorChar2.LinearOffset = vec
        
    End Select
    End Sub

    'Sub MoveChar(gs As X2GameStep)
    '   
    '    '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 = ActiveCharacterFigure.bw.Body.Position
    '        Dim distance As B2Vec2 = NextPoint.CreateCopy
    '        distance.SubtractFromThis(CurrentPoint)
    '        If (distance.Length < 0.3 And PathWorld.Size > 1) Or (distance.Length < 0.1) Then
    '            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
    '       
    ''        Log("#-  x467, ActiveCharacterBody = " & ActiveCharacterBody.Name)
    '        CharMotor.AngularOffset = FindAngleToTarget(ActiveCharacterFigure.bw.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, True, 0))
    '       
    ''        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
    Private Sub World_PostSolve (Contact As B2Contact, Impulse As B2ContactImpulse)
        
    End Sub

    Sub ActiveCharacterSelect_SelectedChange(Selected As Boolean) ' ####testingonly
        LastDiceRollVal = 0
        Label2.Text = 
    "..."
        
    If Not(Selected) Then Return
        
    Dim rbx As RadioButton = Sender
        
    Dim tagx As String = rbx.Tag
        
    Select Case True
            
    Case tagx.ToLowerCase = "rbc1"
                ActiveCharIndex = 
    1
            
    Case tagx.ToLowerCase = "rbc2"
                ActiveCharIndex = 
    2
        
    End Select
    End Sub
    Sub Button1_Click ' ####testingonly
        X2.SoundPool.PlaySound("rolldice")
        Sleep(
    500)
        LastDiceRollVal = 
    Rnd(1,6)
        Label2.Text = LastDiceRollVal
        ActiveCharAdvance(LastDiceRollVal)
    End Sub
    Sub ActiveCharAdvance(NumberOfSteps As Int)
    '    Log("#-Sub game.CharAdvance, NumberOfSteps=" & NumberOfSteps)
        Dim NewPointTemplatesListIndex As Int =    CharLastPositionIndex(ActiveCharIndex) +NumberOfSteps
        
    Dim GotToPosIndex As Int = NewPointTemplatesListIndex Mod PointTemplatesListLoop0.Size
        
    Dim pt As PointTemplates = PointTemplatesListLoop0.Get(GotToPosIndex)

        
    '####test
        Log("#-  x594, " & $"ActiveCharAdvance --> ActiveCharIndex=${ActiveCharIndex}, DiceRollVal=${LastDiceRollVal}, MoveCharTo(${GotToPosIndex})= $1.0{pt.Template.Position.X}, $1.0{pt.Template.Position.Y}  "$)
        
    If ActiveCharIndex =1 Then
            Label3.Text = 
    "Go p" & (GotToPosIndex +1)
        
    else If ActiveCharIndex =2 Then
            Label4.Text = 
    "Go p" & (GotToPosIndex +1)
        
    End If
        
    '/####
        
        MoveCharTo(ActiveCharIndex, pt.Template.Position)
        CharLastPositionIndex(ActiveCharIndex) = GotToPosIndex
    End Sub

    test1.gif
     

    Attached Files:

    RandomCoder and Erel like this.
  6. Erel

    Erel Administrator Staff Member Licensed User

    Another way to move objects is demonstrated in the mouse example. This code is called from the game's Tick event:
    Code:
    Private Sub MoveEnemy
       
    Dim v As B2Vec2 = Mouse.Body.Position.CreateCopy
       v.SubtractFromThis(Enemy.Body.Position)
       
    If v.Length > 0.7 Then
           v.NormalizeThis
           Enemy.Body.LinearVelocity = v
           Enemy.Body.SetTransform(Enemy.Body.Position, 
    ATan2(v.Y, v.X) + cPI / 2)
       
    Else
           Enemy.Body.LinearVelocity = X2.CreateVec2(
    00)
       
    End If
    End Sub
    It causes the second mouse, the enemy, to move (and point) towards the first one.
    When the second mouse is close enough it stops immediately.
     
    fredo likes this.
  7. ilan

    ilan Expert Licensed User

    another way:



    can also be implemented using box2d (xui2d, libgdx, ispritekit)
     
    Johan Hormaza, fredo and inakigarm like this.
  8. fredo

    fredo Active Member Licensed User

    Can I execute a fornext within the game.tick sub to simulate a relative slow step-by-step setting of the figure?

    Or can I have an asynchronous task list processed with the movements while the main process continues?


    2019-08-07_13-54-57.png
     

    Attached Files:

  9. Erel

    Erel Administrator Staff Member Licensed User

    There is no such thing. Each game step represents a single moment. It should complete as fast as possible.

    You don't need to. It is quite simple to move an object between several points.

    Example:
    Code:
    Public Sub Tick (GS As X2GameStep)
       TileMap.DrawScreen(
    Array("Tile Layer 1"), GS.DrawingTasks)
       
    If Char1Points.Size > 0 Then
           
    If Char1Points.Size = 1 Then
               MotorChar1.CorrectionFactor = 
    0.02
           
    Else
               MotorChar1.CorrectionFactor = 
    0.05
           
    End If
           
    Dim NextPoint As B2Vec2 = Char1Points.Get(0)
           
    Dim vec As B2Vec2 = mChar1.bw.Body.Position.CreateCopy
           vec.SubtractFromThis(NextPoint)
           
    If vec.Length < 1 Then
               Char1Points.RemoveAt(
    0)
           
    Else
               MoveCharTo(
    1, NextPoint.CreateCopy)
           
    End If
       
    End If
    End Sub
    Code:
    Char1Points.AddAll(Array(X2.CreateVec2(101), X2.CreateVec2(1010), X2.CreateVec2(2020)))
    You will probably need to change the max force and correction factors.
     
    fredo likes this.
  10. fredo

    fredo Active Member Licensed User

    Sure, it's also easy to create catchy guitar riffs in gm pentatonic if you're Richie Blackmore.

    Thank you for your guidance.
    It's starting to dawn on me what it's all about with the ticks.


    test5.gif
     

    Attached Files:

    RandomCoder and Erel like this.
  11. 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