Android Tutorial [B4X] [BitmapCreator] Creating cross platform games

Discussion in 'Tutorials & Examples' started by Erel, Jun 7, 2018.

  1. Erel

    Erel Administrator Staff Member Licensed User

    Please use XUI2D for new games: https://www.b4x.com/android/forum/threads/xui2d-example-pack.96454/

    BitmapCreator is a relatively new cross-platform class for low level drawings.
    The drawing performance when used correctly is good and it can serve as the basis for 2d games:



    Requirements:

    - BitmapCreator v3.5+ (B4A, B4J, B4i)
    - B4A v8.3+, B4i v5.0+ and B4J v6.3+

    Before we start it is important to understand the performance characteristics of BitmapCreator:
    [B4X] [BitmapCreator] Maximizing Performance with BC

    The main advantage of using BitmapCreator for games is that it is cross platform. Together with XUI library you can use the same code in all three platforms.
    I recommend starting with B4J and later creating B4A and B4i projects that reference the same classes. It should look like this:

    [​IMG]

    All modules, except of the Main module, are shared between the three projects.

    Lets Start

    I'll explain the "walking character" example.
    1. Nothing prevents you from implementing things in a different way.
    2. I will not cover all the code. If you want to better understand it then run the example and go over the code. Overall the code is not too complicated.

    The core of the game code is inside MainLoop in the Game class.
    The main things that happen every iteration:

    - The GameTime counter is incremented by 1.
    - The Tick sub of each sprite is called. A GameStep object is passed to these subs. This object can be used to pass information related to the current tick.
    - Each of the sprites does whatever it needs to do in the Tick event. This includes: updating the position, changing the current frame, checking for collisions and so on.
    - Deleted sprites are removed from the list of sprites.
    - Future tasks are checked and executed.
    - Each of the visible sprites creates a DrawTask.
    - All the drawing tasks are drawn asynchronously.
    - The TargetView (ImageView) is updated with the updated bitmap.

    Note that nothing should happen outside of this loop. For example input events should only set flags that will later be treated from inside the loop.

    Sprites

    Each visual element is represented with a custom class instance. This class instance holds a reference to a Sprite object. Sprite.Target points back to the class instance. It is a composition pattern.
    The sprite objects are added to the main game list.
    The Tick events are called from the main loop like this:
    Code:
    For Each Sprite As Sprite In Sprites
       Sprite.Index = Sprite.Index + 
    1
       Sprite.Tick(gs)
    Next

    'Sprite.Tick:
    Public Sub Tick (gs As GameStep)
       
    CallSub2(Target, "Tick", gs)
    End Sub
    The Sprite object holds all kinds of fields and methods that can be useful for working with the sprites.
    For example lets see the code of the Tick sub of the Bird class:
    Code:
    Public Sub Tick (gs As GameStep)
       
    If MySprite.Index Mod MySprite.TickInterval = 0 Then
           MySprite.CurrentFrame = (MySprite.CurrentFrame + 
    2Mod MySprite.mFrames.Size
       
    End If
       MySprite.UpdatePosition
       
    If MySprite.InsideViewRect = False Then
           MySprite.Delete(gs)
           
    Return
       
    End If
       MySprite.Frame = MySprite.mFrames.Get(MySprite.CurrentFrame)
    End Sub
    MySprite.Index is a counter that is incremented automatically every iteration.
    MySprite.TickInterval is an optional field that is used here to change the current frame every x ticks.
    MySprite.UpdatePosition updates MySprite.Position based on MySprite.Velocity.
    Note that the position points to the sprite center.
    MySprite.InsideViewRect checks whether the sprite is inside the currently visible rectangle. In this case we want to delete it once the bird goes outside of the screen.
    The last line updates the current Frame (it is a BitmapCreator object).

    In many cases you can use the DummySprite class instead of creating a custom class. This class is useful for any sprite that doesn't have "special" logic. In this example it is used for the score numbers that appear after a collision with a coin. It could have also been used instead of Bird and Explosion classes (it was created after those classes were written).

    Coordinates

    By default the reference for the sprites positions is the game virtual coordinates.
    MySprite.ViewRect returns the visible rectangle.
    It is moved in the Kid class:
    Code:
    'check if near edges and change ViewRect as needed
           Dim DistanceToLeft As Int = MySprite.Position.x - MySprite.Frame.mWidth / 2 - MySprite.ViewRect.Left
           
    Dim DistanteToRight As Int = MySprite.ViewRect.Right - MySprite.Frame.mWidth / 2 - MySprite.Position.x
           
    If  DistanceToLeft < MinDistanceToEdge Or DistanteToRight < MinDistanceToEdge Then
               MySprite.GameUtils.PushRect(MySprite.ViewRect, MySprite.Velocity.vx, 
    0)
               MySprite.mGame.ViewRectPushed
           
    End If
    You can however switch to the screen coordinates. Screen coordinates are relative to TargetView. This is used in this example for the score sprites that always move to the top left corner. We don't want their position to be affected by changes to the game ViewRect.
    Code:
    'set the score sprite position based on the coin position
    ds.MySprite.Position = MySprite.ToScreenPosition
    'set ScreenCoordinates to True
    ds.MySprite.ScreenCoordinates = True

    Future Tasks


    There are cases where you want to do something later.
    For example 20 ticks before a coin disappears it starts moving up. This is done with this code:
    Code:
    MySprite.mGame.AddFutureTask(Me, "Move_Up", MySprite.TimeToLive - 20Null)

    Public Sub Move_Up (ft As FutureTask)
       MySprite.Velocity.vy = -
    10
    End Sub
    The underscore in the sub name is important if you want to compile with obfuscation.

    Tips

    - Avoid loading the same resources multiple times. Load then when the game starts and reuse them.
    - jGameViewHelper (B4J) and iGameView (B4i) are used for the low latency sound effects and keyboard events in B4J. Make sure to update to iGameView v1.05+ if you are using a local builder.
    - B4i multitouch handling is based on: https://www.b4x.com/android/forum/threads/87027/#content
    In this case the moving event is ignored.

    Art Credits

    The sounds and images were downloaded from: https://opengameart.org

    https://opengameart.org/content/pixel-explosion-12-frames
    https://opengameart.org/content/coin-animation
    https://opengameart.org/content/2d-character-animation-sprite
    https://opengameart.org/content/picked-coin-echo-2
    https://opengameart.org/content/several-scrolling-backgrounds-and-layerable-runners

    The three projects links:
    B4A: www.b4x.com/b4j/files/games/B4A_WalkingCharacter.zip
    B4i: www.b4x.com/b4j/files/games/B4i_WalkingCharacter.zip
    B4J: www.b4x.com/b4j/files/games/B4J_WalkingCharacter.zip

    All the classes are identical.

    Updates:

    - The code in B4A and B4i (Main) was updated. The game size is set to 600 / 400 and the ImageView is scaled based on the screen size.
    The code in MainLoop was changed with:
    Code:
    mTargetView.SetBitmap(bmp)
    #if B4A
    'B4XView.SetBitmap sets the gravity in B4A to CENTER. This will prevent the bitmap from being scaled as needed so
    'we switch to FILL
    Dim iv As ImageView = mTargetView
    iv.Gravity = 
    Gravity.FILL
    #End If
    Latest version of the code is available in the B4A and B4i examples.
     
    Last edited: Nov 7, 2018
    wonder, Jmu5667, koaunglay and 21 others like this.
  2. Johan Hormaza

    Johan Hormaza Active Member Licensed User

    wooo !!! Great job teacher EREL!
     
  3. Johan Hormaza

    Johan Hormaza Active Member Licensed User

    @Erel in the BitmapCreator library of B4A missing the XML file?
     
    Erel likes this.
  4. Erel

    Erel Administrator Staff Member Licensed User

    Fixed.
     
    Johan Hormaza likes this.
  5. sorex

    sorex Expert Licensed User

    Nice!

    I'm getting a crash on this line > gmh.PlayAudioClip(COIN_SOUND, 1) (unknown source error)

    in B4J debug mode tho, seems to go away in release mode.

    does this mean we should just disable sound in debug mode or is it a bug somewhere?
     
  6. Erel

    Erel Administrator Staff Member Licensed User

    It should work in debug mode. Try to rename the audio file name to 1.wav and update the code. Does it work?

    Which OS are you using?
     
  7. LucaMs

    LucaMs Expert Licensed User

    [B4A] on my device, 1280 x 800 - scale 1, the walking man can not jump so high as to reach the coins.

    upload_2018-6-9_9-58-6.png
     
    Erel likes this.
  8. Erel

    Erel Administrator Staff Member Licensed User

  9. Erel

    Erel Administrator Staff Member Licensed User

    Made another small fix and also applied the change in the B4i example.
     
  10. sorex

    sorex Expert Licensed User

    that was my first thought aswell that the spaces could be a problem but it works fine for the images.

    I renamed it to 1.wav and changed the code but it still crashes.

    Even more bizarre is the fact that when I swap the filenames in the 2 lines of code I hear the coin sound when that explode animation appears
    and when I touch a coin I also get the crash instead of the explosion sound.


    changing the variable from COIN_SOUND to BOMB_SOUND in this line > gmh.PlayAudioClip(COIN_SOUND,1)

    makes it work too.

    it's like the init of the second sound fails but it's not reported to the debug window.


    It was Friday on a win 8.1 box and also happening on this win 7 box.
     
  11. Erel

    Erel Administrator Staff Member Licensed User

    Lets discuss it in a new thread. Also create a project that just plays each of the sound files and see when it breaks.
     
  12. R D Boozer

    R D Boozer Member Licensed User

    Thanks for doing this Erel! Just want you to know how much your efforts are appreciated. I will use this class for sure, and not necessarily just for games.
     
    Erel likes this.
  13. Jaames

    Jaames Active Member Licensed User

    Thank you for sharing this and for BitmapCreator.

    Is it too hard to implement pinch-zoom / pan with this framework?
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    Should be possible. Especially with v3.6+ that supports drawing scaled BCs. v3.6 is included in B4A v8.30. It will be soon released to the other platforms.
     
    Jaames and Johan Hormaza like this.
  15. Jmu5667

    Jmu5667 Well-Known Member Licensed User

    Project links have 404 errors
     
  16. Erel

    Erel Administrator Staff Member Licensed User

    Johan Hormaza and Jmu5667 like this.
  17. Jmu5667

    Jmu5667 Well-Known Member Licensed User

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