Games [BANanoPhaser 0.2] Dino Dash

Mashiane

Expert
Licensed User
Longtime User
Ola

Download




This is our 3rd game with BANanoPhaser and thus more developments and enhancements on the library especially with separation of concerns. Let me explain.

The phaser code javascript code is like this..

B4X:
this.load.image('play', 'assets/image1.png')

With version 0.1 of BANanoPhaser you would write the code like this...

B4X:
Scene.SceneLoadImage("play", "./assets/image1.png")

Now with the latest version 0.2. this has to be written as

B4X:
Scene.load.image("play", "./assets/image1.png")

Version 0.2 is better because it closely resembles what the javascript equivalent code looks like and is now the recommended way in using BANanoPhaser. This also helps as it ensures that code is easier to maintain and build as each class is separate from others and thus independent.

DinoDash is a part wrap of this GitHub

PURPOSE OF THE GAME

We have a dino thats running around collecting meat and dogding bombs. Each time the dino eats the meat we play a collect sound. Each time the dino hits a bomb, we play a bomb sound. During the game execution, we are playing background music.

We feature sounds, scrolling tiles besides the bombs and collections of 'meat' this time around.
We also feature using multiple scenes in the game. The first scene is the 'welcome' scene and the other the 'actual' game scene where all the action happens.

As you will note on the game, we have HTML this time around to ask the user for their Name, show the welcome scene and when selected start the game. This information can be used to keep scores per player and save to a db (which the github repo does).

In this game, some meat and bombs are added at 1 second and 3 seconds during a run respectively.
We also introduce tiles that scroll by incrementing their values by 10.

We add interaction on images so that we can click them and also detect hover in and hover out on them. We also indicate how you can start different scene on button click.

The only thing we have not explored is having a 'loader' that shows loading progress when the game starts, we will explore creating this later. Let's learn how we have created this more advanced game from the previous 2.

REPRODUCTION

github.png

1. Download contents
2. Extract and compile BANanoPostProcessor (tweaked version) THIS IS NOT COMPULSORY
3. Compile the BANanoPhaser 0.2 library by running the project with B4J.
4. Open the DinoDash project under games with B4J, reference the libraries.

Let's look at the game hey...
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
CREATING THE 'WELCOME' scene: Ask the user for their name...

welcome.png



When the game starts, we see a page that asks the user for the name. This is nothing more than basic BANano basic. In this page we create HTML with input controls and a form and we prepare the game. We only want to start the game after the user enters their names and clicks submit. We however ensure that the game is ready for starting, thus we create the game structure when we start and then start the game.


B4X:
Sub Init
    'set the body of the page
    body = BANano.GetElement("#body")
    body.Empty
    body.Append($"<section id="header" class="section">
    <div class="inner">
        <div id='canvas'></div>
        <div>
            <div id='form'>
                <span class="icon major fa-cloud"></span>
                <h1 id='enter'>Enter your name to play:</h1>
                <br>
                <form id="user_form">
                    <input id="user_input" type="text" name="user" required />
                    <br>
                    <input type="submit" value="Submit" />
                </form>
            </div>
        </div>
    </div>
</section>"$)
    'try and set the focus to the name
    BANano.Window.GetField("document").RunMethod("getElementById", Array("user_input")).RunMethod("focus", Null)
    userform = BANano.GetElement("#user_form")
    'add an event listener to the form that calls createUser
    Dim e As BANanoEvent
    userform.addEventListener("submit", BANano.CallBack(Me, "createUser", Array(e)), True)
    'prepare the game for launch
    CreateGame
End Sub

The CreateGame sub does that. It prepares the game for loading. Here we specify the game configuration and also add the scenes that will be used in the game.

B4X:
'set the game configuration
Sub CreateGame
    game.Initialize
    game.config.typeOf = game.TypeOf_WEBGL
    game.config.Width = 800
    game.config.Height = 600
    game.config.Parent = "canvas"
    game.config.PixelArt = True
    game.config.physics.defaultt = "arcade"
    game.config.physics.arcade.gravity.Put("y",1000)
    game.config.physics.arcade.debug = False
    'initialize scenes and add them to the game
    titleOf.Initialize(game)
    gameOf.Initialize(game)
    'add the scenes, the game starts with the top most scene
    game.addScene(titleOf.TitleScene)
    game.addScene(gameOf.GameScene)
End Sub

Noticed the slight difference here with the previous version? We have a config object this time, just like how the javascript code looks like.

This time around we use 2 code modules for our scenes. Here we initialize the scenes and then add them to the game. In the previous code examples we did indicate that a game can have multiple scenes. This is now where you do it.

B4X:
titleOf.Initialize(game)
    gameOf.Initialize(game)
    'add the scenes, the game starts with the top most scene
    game.addScene(titleOf.TitleScene)
    game.addScene(gameOf.GameScene)

Each scene will have its own preload, create and update methods. Cool isnt it? The first scene added will be the default scene the game starts with. In this case, we add the tileOf scene. The tileOf scene shows the logo of the game, has a Start button for the game and shows the background of the game which is made from combining different layer images..

When the user clicks the submit button, this executes the createUser sub.

B4X:
Sub createUser(e As BANanoEvent)
    e.PreventDefault
    'get the user name
    userName = BANano.GetElement("#user_input").GetValue
    'hide the form
    BANano.GetElement("#form").SetStyle(BANano.ToJson(CreateMap("display":"none")))
    'add the user
    addUser(0)
    'start the game
    game.start
End Sub

Sub addUser(score As Long)
    BANano.SetLocalStorage(userName, score)
End Sub

This gets the user's name, hides the form and then addUser which just saves the user's name to localStorage. After that game.Start is fired, which actually starts the game.

Here we go...
 
Last edited:

Mashiane

Expert
Licensed User
Longtime User
THE FIRST SCENE - tileOf

tileOf.gif


Here we show the logo of the game, some scrolling tiles and a button where the player can click Play to start the game. This is the tileOf code module..

We create a scene and define the respective loaders.

B4X:
'the game title
Sub Initialize(game As BANanoPhaser)
    TitleScene = game.CreateScene("TitleScene")
    TitleScene.SetOnPreload(Me, "onPreLoad")
    TitleScene.SetOnCreate(Me, "onCreate")
    TitleScene.SetOnUpdate(Me, "onUpdate")
End Sub

We preload our resources

B4X:
Sub onPreload
    TitleScene.load.image("logo", "./assets/logo.png")
    TitleScene.load.image("play", "./assets/play.png")
    TitleScene.load.image("background1", "./assets/plx-1.png")
    TitleScene.load.image("background2", "./assets/plx-2.png")
    TitleScene.load.image("background3", "./assets/plx-3.png")
    TitleScene.load.image("background4", "./assets/plx-4.png")
    TitleScene.load.image("background5", "./assets/plx-5.png")
    TitleScene.load.image("platform", "./assets/platform.png")
End Sub

We have explained this use in the 2 prevous examples of BANanoPhaser.

References

BreakOut
Star Catcher

We then create the actual scene content. Here we load the background, we load the play button and add events to it.

B4X:
Sub onCreate
    'add the trees one behind another
    background1 = TitleScene.add.tileSprite(400, 300, 800, 600, "background1")
    background2 = TitleScene.add.tileSprite(400, 300, 800, 600, "background2")
    background3 = TitleScene.add.tileSprite(400, 300, 800, 600, "background3")
    background4 = TitleScene.add.tileSprite(400, 300, 800, 600, "background4")
    background5 = TitleScene.add.tileSprite(400, 300, 800, 600, "background5")
    'add a platform
    ground = TitleScene.add.tileSprite(400, 568, 800, 100, "platform")
    TitleScene.physics.add.existing(ground)
    ground.body.Immovable = True
    ground.body.Moves = False
    'add the game logo
    logo = TitleScene.add.image(400, 180, "logo")
    logo.setScale(1.5)
    'add a play button
    play = TitleScene.add.image(400, 400, "play")
    play.setScale(4)
    play.setInteractive()
    'detect events on the play button
    play.on("pointerdown", Me, "StartTheGame", Null)
    play.on("pointerover", Me, "SetTintOver", Null)
    play.on("pointerout", Me, "SetTintOut", Null)
    
End Sub

When the player, click start, start the GameScene scene. This has been linked via a BANano.CallBack call.

B4X:
'start the game on a particular scene
Sub StartTheGame
    TitleScene.Start("GameScene")
End Sub

We want to create a scrolling effect of the loaded sprites. This will do when the FPS is firing. Lets increment each background X position by 10px each time during the loop. We do this for all of them.

B4X:
'scroll the trees as we move along
Sub onUpdate
    background1.IncrtilePositionX(10)
    background2.IncrtilePositionX(10)
    background3.IncrtilePositionX(10)
    background4.IncrtilePositionX(10)
    background5.IncrtilePositionX(10)
    ground.IncrtilePositionX(10)
End Sub

Now we wait for the player to click 'Play'...
 

Mashiane

Expert
Licensed User
Longtime User
REMEMBER:

If you look at the process_globals for this scene, you will notice the following.

B4X:
'Static code module
Sub Process_Globals
    Public TitleScene As PhaserScene
    Public background1 As PhaserObject
    Public background2 As PhaserObject
    Public background3 As PhaserObject
    Public background4 As PhaserObject
    Public background5 As PhaserObject
    Public ground As PhaserObject
    Public logo As PhaserObject
    Public play As PhaserObject
End Sub

We have different objects here. We have PhaserScene and PhaserObject objects. Each Phaser 'Thing' is defined as a PhaserObject. This has helped us just pass properties and events to each item we can have. Most of these share the same methods so having one defined object helps. One can add more methods / properties depending on what they need.

PhaserObject is just a BANanoObject that has its own properties, events and other interesting thing. We also have a .ToPhaserObject sub we have created that takes a BANanoObject and then ensures that we can pass all properties and events that we need for a Phaser based object.

So when you thing PhaserObject, think of a BANanoObject, however to get the BANanoObject of a PhaserObject, get its .Thing.

The things that can be added to a phaser game are in the .add object. Let's see what autosense is giving us..

phaserthings.png
 

Mashiane

Expert
Licensed User
Longtime User
PLAYING THE GAME

As soon as the player selects, PLAY, the game loads and it stars (as per video above). How dd we build this?

Its a different scene, so we load the resources it needs and then add them to the scene..

After we have added the game scrolling forest on the Create method..

We add the dino and a group of meats and bombs..

B4X:
'add the dino
    player = GameScene.physics.add.sprite(100, 450, "doux")
    player.getBounds
    player.setBounce(0.2)
    player.setCollideWorldBounds(True)
    player.setScale(characterScale)
    player.setSize(13, 17, 0, 0)
    'we get to eat meats and dodge some bombs
    meats = GameScene.physics.add.group
    bombs = GameScene.physics.add.group

On each 1 second and on each 3 seconds events, we want to add a piece of meat and a bomb during the dino dash, all whilst playing the background music.

B4X:
'add events for every 1 second and every 3 seconds
    timedEvent = GameScene.time.addEvent(1000, Me, "onEvent", GameScene.Scene, True)
    timedEvent1 = GameScene.time.addEvent(3000, Me, "onEvent1", GameScene.Scene, True)
    'play the music
    music = GameScene.sound.add("music")
    music.setLoop(True)
    music.play

Just like star catcher, we have a dino runing. Lets add the animations based on the frames in our resources.

B4X:
'define animation
    GameScene.Anims.Create("run", "doux", 10, 3, 9, -1)
    GameScene.Anims.Create("hurt", "doux", 10, 14, 16, -1)
    GameScene.Anims.Create("boom", "bomb", 10, 0, 3, -1)

We add a scoreboard

B4X:
'create a score card
    scoreText = GameScene.add.text(16, 16, "SCORE: 0", CreateMap("fontSize": "32px", "fill": "#FFFFFF"))

The dino collides with the ground, the meat with the ground, the bomb with the ground

B4X:
'detect collision
    GameScene.physics.add.collider(player, ground)
    GameScene.physics.add.collider(meats, ground)
    GameScene.physics.add.collider(bombs, ground)

When a player / dino overlaps with the meat, collect the meat, play the collect sound, increase the score, move the meat from the scene. The game camera should follow the player.

B4X:
'on player and meat overlap, collectMeat
    Dim thisPlayer As Object
    Dim thisMeat As Object
    Dim thisBomb As Object
    Dim overlapCB As BANanoObject = BANano.callback(Me, "collectMeat", Array(thisPlayer, thisMeat))
    GameScene.physics.add.overlap(player, meats, overlapCB, Null, GameScene.Scene)
    'on player and bomb collision, fire hitBomb which ends the game
    Dim collideCB As BANanoObject = BANano.CallBack(Me, "hitBomb", Array(thisPlayer, thisBomb))
    GameScene.physics.add.collider1(player, bombs, collideCB, Null, GameScene.Scene)
    'the main camera should follow the player
    GameScene.cameras.mainC.startFollow(player, True, 0.05, 0.05)
    GameScene.cameras.mainC.setBounds(0, 0, 800, 600)

When a player/dino collides with a bomb, fire the hitBomb sub. This ends the game and allows the user to restart the game.

COLLECTING THE MEAT: Play a collect sound and increase the score

B4X:
'when meat is overlapping, collect it
'play the pickup sound
Sub collectMeat(cplayer As BANanoObject, cmeat As BANanoObject)
    GameScene.ToPhaserObject(cmeat).destroy
    Dim pickup As PhaserObject = GameScene.sound.add("pickup")
    pickup.play
    score = score + 100
    scoreText.setText("SCORE: " & score)
End Sub

COLLIDING WITH THE BOMB - destroy the bomb from the scene, stop the background music, play the death sound, pause the game, pause any addition of meats and bombs, play the hurt animation on the dino, the game is over, enable the player to restart the game and show the Game Over logo.

B4X:
'when a bomb is hit, end the game
'enable the user to restart
Sub hitBomb(hplayer As BANanoObject, hbomb As BANanoObject)
    GameScene.ToPhaserObject(hbomb).destroy
    music.stop
    Dim death As PhaserObject = GameScene.sound.add("death")
    death.play
    GameScene.physics.pause
    isGameOver = True
    timedEvent.paused = True
    timedEvent1.paused = True
    player.setTint("0xff0000")
    player.anims.play("hurt",Null)
    '
    restart = GameScene.add.image(400, 350, "restart")
    restart.setScale(4)
    restart.setInteractive
    '
    restart.on("pointerdown", Me, "StartTheGame", Null)
    restart.on("pointerover", Me, "SetTintOver", Null)
    restart.on("pointerout", Me, "SetTintOut", Null)
    '
    gameover = GameScene.add.image(400, 180, "gameover")
    gameover.setScale(1.2)
End Sub
 
Top