B4J Tutorial [B4X] [BitmapCreator] Creating a cross platform Tetris game

Edit: XUI2D version of Tetris: https://www.b4x.com/android/forum/threads/xui2d-tetris.107698/

tetris.gif


SS-2018-06-17_16.17.39.png


This example shows how BitmapCreator can be used to create a cross platform Tetris game.
The code is an evolution of the code introduced in the "walking character" example.

There are three types of modules in these projects:
  • Main module which is mostly empty and is different in each of the projects.
  • The game framework classes, shared by all three projects, and not specific to this game.
    The following classes are included:
    • GameUtils - Manages the main loop and also includes various utility methods.
    • Sprite - Each custom sprite object holds a Sprite object. The Sprite object implements all the sprite common features.
    • DummySprite - Useful for simple sprites that do not need special implementation.
    • ScoreLabel - A custom view that shows the score
  • Game specific classes, shared by all three projects:
    • Game - The main game class. GameUtils calls all kinds of methods of this class.
    • Background - The background sprite. Note that the moving pieces start as sprites and once they stop moving they are drawn onto the background sprite.
    • Piece - Represents a moving piece
If you are interested in cross platform development then it is most important to understand how to add modules as linked modules:

modules.gif


This way, changes in one project will be updated automatically in other projects.

I will not go over all the code. If you are interested then download it, play with it and feel free to ask any question you have.

Some interesting points:

- The pieces structure is loaded from a text file. It defines all the pieces. For example:
P1.Color=FF0000
P1.Pattern=(0,0)-(0,-1)-(0,1)-(0,2)
P1.Orientations=2
P1.Center=(1,1)
P2.Color=1400FF
P2.Pattern=(0,0)-(-1,1)-(0,1)-(1,1)
P2.Orientations=4
P2.Center=(1,1)

Each piece is defined with a 4x4 grid. The Pattern field defines the blocks in this grid where block (0,0) position is defined by the Center field.

- The Rows list stores the state of all blocks. There are 20 rows and 10 blocks in each row. Each item in the Rows list is an array of booleans. Each boolean represents the state of the column in that row.
- When a piece stops moving we check for full rows. Full rows are removed from the list and new empty rows are inserted at position 0.
- When one or more rows are removed, the existing graphical rows are copied to a temporary BC and after the moving animation completes, back to the background bc.
- The B4A game uses Immersive Mode: https://www.b4x.com/android/forum/threads/90882/#content
- The B4i game uses full screen: https://www.b4x.com/android/forum/threads/full-screen-apps.47866/#content
- The clickable labels in B4A and B4i provide haptic feedback. It is done with NativeObject / JavaObject.
- The blocks graphics are made from this greyscale image:
SS-2018-06-17_16.40.11.png

- GameUtils.GreyscaleToColor sub is used to create copies of this image with different colors.
- All the layout handling is done with two layout files. The first sets the main layout and the second uses designer script to set the ImageView width/height ratio:
B4X:
GameRatio = 2
ScreenRatio = 100%y / 100%x
If ScreenRatio > GameRatio Then
 Pane1.SetLeftAndRight(0, 100%x)
 Pane1.Height = Pane1.Width * GameRatio
 Pane1.VerticalCenter = 50%y
Else
 Pane1.SetTopAndBottom(0, 100%y)
 Pane1.Width = Pane1.Height / GameRatio
 Pane1.HorizontalCenter = 50%x
End If
ImageView1.SetLeftAndRight(2dip, Pane1.Width - 2dip)
ImageView1.SetTopAndBottom(2dip, Pane1.Height - 2dip)
The ImageView is inside a Panel named Pane1.
- All the game logic was developed and tested with B4J. Once the main things worked I ported it to B4A and B4i.

Credits: Font and inspiration: https://github.com/spypunk/tetris
- Tetris itself is a trademark of The Tetris Company. It is used here for educational purposes only.

Edit: This game was created before XUI2D and the X2 framework were available. It is recommended to use XUI2D for new games.
 

Attachments

  • B4A_Tetris.zip
    184.6 KB · Views: 1,175
  • B4i_Tetris.zip
    285.5 KB · Views: 890
  • B4J_Tetris.zip
    177.1 KB · Views: 1,083
Last edited:

stevel05

Expert
Licensed User
Longtime User
Thanks Erel, it's my favourite game.

I have noticed a bug if you try to rotate a piece as soon as it is displayed, the row number calculated in the CanMove Sub can be -1 resulting in the error in the Game IsTaken sub:

java.lang.RuntimeException: java.lang.RuntimeException: java.lang.ArrayIndexOutOfBoundsException: -1

It doesn't do it every time, but often enough to be repeatable.

Tested with the B4j implementation
 

jamal

New Member
Public Sub ToDrawTask As DrawTask unknwon
problem solved! thanks Erel
 
Last edited:

stevel05

Expert
Licensed User
Longtime User
Thanks Erel, the problem I see now is that the pieces do not rotate if they are in the first row. I've changed the 3 Row number calculations to

B4X:
Dim RowNumber As Int = Max(0,b(1) + CenterPositionY + dy)

Or
B4X:
Dim RowNumber As Int = Max(0,b(1) + CenterPositionY)

Which seems to work and allows rotation in the first row. I can't see that it will cause any other problems, but I wanted to ask you just in case I missed something. I haven't been through all of the code yet.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
the problem I see now is that the pieces do not rotate if they are in the first row
I'm not sure that it is a problem. There are some edge cases where it is not possible to rotate the piece.

If you do want to allow it then the best solution is to allow blocks to be located in negative rows. It will require a few changes.
 

stevel05

Expert
Licensed User
Longtime User
There are some edge cases where it is not possible to rotate the piece.
Yes of course, I hadn't considered that. It's best left as it is then :)
 
Top