Games XUI2D

Erel

B4X founder
Staff member
Licensed User
Longtime User
can you create an example where everything is in the main activity and you cretate manually the bitmap view and then the body view without tiled or any class that does it automatically??
The main activity is not relevant as it is not cross platform. The main place for your code is the Game class.

In this example there are no other classes.
 
Last edited:

sorex

Expert
Licensed User
Longtime User
can you create an example where everything is in the main activity and you cretate manually the bitmap view and then the body view without tiled or any class that does it automatically??

here's an example of you crate stack and a crate being thrown to it

it's minimal and erel usually uses a class per object type but it doesn't seem needed for just this example.

the minimal code is like this. (it can probably be shorter but I'm still a noob with it)

B4X:
Sub Class_Globals
    Private Ground As X2BodyWrapper
    Dim blocksize As Int
End Sub

Public Sub Initialize (Parent As B4XView)
    Parent.LoadLayout("GameLayout")
    X2.Initialize(Me, ivForeground)
    world = X2.World
    X2.ConfigureDimensions(world.CreateVec2(5, 0),10)
    X2.EnableDebugDraw
    StartGame
End Sub

Public Sub StartGame
    If X2.IsRunning Then Return
    X2.UpdateWorldCenter(X2.CreateVec2(X2.ScreenAABB.Width/2,X2.ScreenAABB.Height/2))
    X2.Start
   
    blocksize=X2.ScreenAABB.Width/10  
    Dim sprites As List = X2.ReadSprites(xui.LoadBitmap(File.DirAssets, "crate.png"), 1, 1,blocksize,blocksize)
    X2.GraphicCache.PutGraphic("crate", sprites)
 CreateGround
 Create_Bullet
    For y=0 To 9
        Create_Crate(0,y*blocksize)
    Next
End Sub

Private Sub CreateGround
    Dim GroundBox As B2Vec2 = X2.CreateVec2(9.60, 0)
    Dim bd As B2BodyDef
    bd.BodyType = bd.TYPE_STATIC
    bd.Position = X2.CreateVec2(X2.ScreenAABB.Center.X, X2.ScreenAABB.BottomLeft.Y + GroundBox.Y / 2)
    Ground = X2.CreateBodyAndWrapper(bd, Null, "Ground")
    Dim rect As B2PolygonShape
    rect.Initialize
    rect.SetAsBox(GroundBox.X / 2, GroundBox.Y / 2)
    Ground.Body.CreateFixture2(rect, 1)
End Sub

Private Sub Create_Bullet  
    Dim bd As B2BodyDef
    bd.BodyType = bd.TYPE_DYNAMIC
    bd.Position = X2.CreateVec2(0,2)
    Dim wrapper As X2BodyWrapper = X2.CreateBodyAndWrapper(bd,Null, "crate")
    wrapper.GraphicName = "crate"
    Dim size As B2Vec2 = X2.GraphicCache.GetGraphicSizeMeters("crate", 0)
 Dim rect As B2PolygonShape
    rect.Initialize
    rect.SetAsBox(size.X / 2, size.Y / 2)
    wrapper.Body.CreateFixture2(rect, 1)
    wrapper.Body.ApplyLinearImpulse(X2.CreateVec2(10,10),X2.CreateVec2(0,0))  
End Sub

Private Sub Create_Crate(x As Int, y As Int)
    Dim size As B2Vec2 = X2.GraphicCache.GetGraphicSizeMeters("crate", 0)
    Dim xoffset,yoffset As Double
    Dim bd As B2BodyDef
    yoffset=blocksize/2
    xoffset=X2.ScreenAABB.Width-blocksize
    bd.BodyType = bd.TYPE_DYNAMIC
    bd.Position = X2.CreateVec2(xoffset + x*size.x,yoffset + y*size.y)
    Dim wrapper As X2BodyWrapper = X2.CreateBodyAndWrapper(bd,Null, "crate")
    wrapper.GraphicName = "crate"
    Dim rect As B2PolygonShape
    rect.Initialize
    rect.SetAsBox(size.X / 2, size.Y / 2)
    wrapper.Body.CreateFixture2(rect, 2.0)
End Sub
 

Attachments

  • Xui2D_CrateStack.zip
    15.9 KB · Views: 461
Last edited:

ilan

Expert
Licensed User
Longtime User
The main activity is not relevant as it is not cross platform. The main place for your code is the Game class.

In this example there are no other classes.

i am working right now on a game for b4i and i am making very good process. i have doubts if i should stop it using ispritekit and try to write it in xui2d so i can have it also for b4a or create it in ispritekit since it is much simpler for me and almost done. i only need to add enemies and some stages and the first beta can be uploaded.
 

ilan

Expert
Licensed User
Longtime User
here's an example of you crate stack and a crate being thrown to it

it's minimal and erel usually uses a class per object type but it doesn't seem needed for just this example.

the minimal code is like this. (it can probably be shorter but I'm still a noob with it)

B4X:
Sub Class_Globals
    Private Ground As X2BodyWrapper
    Dim blocksize As Int
End Sub

Public Sub Initialize (Parent As B4XView)
    Parent.LoadLayout("GameLayout")
    X2.Initialize(Me, ivForeground)
    world = X2.World
    X2.ConfigureDimensions(world.CreateVec2(5, 0),10)
    X2.EnableDebugDraw
    StartGame
End Sub

Public Sub StartGame
    If X2.IsRunning Then Return
    X2.UpdateWorldCenter(X2.CreateVec2(X2.ScreenAABB.Width/2,X2.ScreenAABB.Height/2))
    X2.Start
   
    blocksize=X2.ScreenAABB.Width/10  
    Dim sprites As List = X2.ReadSprites(xui.LoadBitmap(File.DirAssets, "crate.png"), 1, 1,blocksize,blocksize)
    X2.GraphicCache.PutGraphic("crate", sprites)
 CreateGround
 Create_Bullet
    For y=0 To 9
        Create_Crate(0,y*blocksize)
    Next
End Sub

Private Sub CreateGround
    Dim GroundBox As B2Vec2 = X2.CreateVec2(9.60, 0)
    Dim bd As B2BodyDef
    bd.BodyType = bd.TYPE_STATIC
    bd.Position = X2.CreateVec2(X2.ScreenAABB.Center.X, X2.ScreenAABB.BottomLeft.Y + GroundBox.Y / 2)
    Ground = X2.CreateBodyAndWrapper(bd, Null, "Ground")
    Dim rect As B2PolygonShape
    rect.Initialize
    rect.SetAsBox(GroundBox.X / 2, GroundBox.Y / 2)
    Ground.Body.CreateFixture2(rect, 1)
End Sub

Private Sub Create_Bullet  
    Dim bd As B2BodyDef
    bd.BodyType = bd.TYPE_DYNAMIC
    bd.Position = X2.CreateVec2(0,2)
    Dim wrapper As X2BodyWrapper = X2.CreateBodyAndWrapper(bd,Null, "crate")
    wrapper.GraphicName = "crate"
    Dim size As B2Vec2 = X2.GraphicCache.GetGraphicSizeMeters("crate", 0)
 Dim rect As B2PolygonShape
    rect.Initialize
    rect.SetAsBox(size.X / 2, size.Y / 2)
    wrapper.Body.CreateFixture2(rect, 1)
    wrapper.Body.ApplyLinearImpulse(X2.CreateVec2(10,10),X2.CreateVec2(0,0))  
End Sub

Private Sub Create_Crate(x As Int, y As Int)
    Dim size As B2Vec2 = X2.GraphicCache.GetGraphicSizeMeters("crate", 0)
    Dim xoffset,yoffset As Double
    Dim bd As B2BodyDef
    yoffset=blocksize/2' * size.x
    xoffset=X2.ScreenAABB.Width-blocksize
    bd.BodyType = bd.TYPE_DYNAMIC
    bd.Position = X2.CreateVec2(xoffset + x*size.x,yoffset + y*size.y)
    Dim wrapper As X2BodyWrapper = X2.CreateBodyAndWrapper(bd,Null, "crate")
    wrapper.GraphicName = "crate"
    'horseShoe.Initialize(wrapper)
    Dim rect As B2PolygonShape
    rect.Initialize
    rect.SetAsBox(size.X / 2, size.Y / 2)
    wrapper.Body.CreateFixture2(rect, 2.0)
End Sub

thanks i will have a look at it when i get home.

A minimal example is included in the examples pack. The actual code without the template code is about 10 lines.

wich one the hello world example?

the physic engine settings is not a problem i just dont understand the rendering part. how you create the bitmaps or animations using xui2d? using canvas or libgdx it is very simple just draw your frame and in ispritekit i use skaction for the animation how do i do it using xui2d? what means that graphic cache stuff???
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
wich one the hello world example?
Yes. You can also see it in the tank example.

how you create the bitmaps or animations using xui2d?
There are several ways. The simplest one is to set the 'graphic file' property in the Tiled map:

SS-2018-08-27_10.58.18.png


You can add more frames by adding more properties:
SS-2018-08-27_10.59.07.png


The 'switch frame inteval (ms)' property sets the automatic switching interval. In the tank example it is set to 0 as we only want it to switch frames while the tank is moving.
This is managed in the code:
B4X:
If RightDown Then
   Tank.Body.ApplyLinearImpulse(TankMovementForce, Tank.Body.Position)
   Tank.SwitchFrameIntervalMs = 100
Else If LeftDown Then
   Tank.Body.ApplyLinearImpulse(TankMovementForce.Negate, Tank.Body.Position)
   Tank.SwitchFrameIntervalMs = 100
Else
   Tank.SwitchFrameIntervalMs = 0
End If

You can also set 'graphic file 1' to a sprite sheet and set the number of rows and columns.
See walking character example:
SS-2018-08-27_11.01.57.png


Tip: the tile objects that you see in the various map files are not used at runtime. They only help us to build the map and to create the object polygons.

There are several other ways to create the bodies graphics. The examples demonstrate all of them.
 

ilan

Expert
Licensed User
Longtime User
There are several ways. The simplest one is to set the 'graphic file' property in the Tiled map:

SS-2018-08-27_10.58.18.png


You can add more frames by adding more properties:
SS-2018-08-27_10.59.07.png


The 'switch frame inteval (ms)' property sets the automatic switching interval. In the tank example it is set to 0 as we only want it to switch frames while the tank is moving.
This is managed in the code:

This is a very good approch but i would like to learn how it works manually and not using tiled. Then i can make my own moduls that does it automatically like u using tiled for that.

I will have a closer look at sorex example and see how the bitmap is drawn on the screen and then it should be simple to create animations and bodies.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
This is a very good approch but i would like to learn how it works manually and not using tiled.
If you want to use XUI2D then start with the recommended way and use Tiled. Open X2TileMap and you will see that it is a complex class with many features. No reason to rewrite it yourself.

Everything can be later customized.

Another way to set the graphics, still in a simple way, is demonstrated in the Mario example:
B4X:
Private Sub LoadMarioGraphics
   Dim bmp As B4XBitmap = xui.LoadBitmap(File.DirAssets, "mario_bros.png")
   Dim NumberOfSprites As Int = 14
   Dim MarioSmall As B4XBitmap = bmp.Crop(80, 32, NumberOfSprites * 16, 16)
   Dim AllSmall As List = X2.ReadSprites(MarioSmall, 1, NumberOfSprites, 1, 1)
   X2.GraphicCache.PutGraphic("mario small walking", Array(AllSmall.Get(0), AllSmall.Get(1), AllSmall.Get(2)))
   X2.GraphicCache.PutGraphic("mario small standing", Array(AllSmall.Get(6)))
   X2.GraphicCache.PutGraphic("mario small jumping", Array(AllSmall.Get(4)))
   X2.GraphicCache.PutGraphic("mario small strike", Array(AllSmall.Get(5)))
   X2.GraphicCache.PutGraphic("mario small change direction", Array(AllSmall.Get(3)))
   NumberOfSprites = 19
   Dim MarioLarge As B4XBitmap = bmp.Crop(80, 0, NumberOfSprites * 16, 32)
   Dim AllLarge As List = X2.ReadSprites(MarioLarge, 1, NumberOfSprites, 1, 2)
   X2.GraphicCache.PutGraphic("mario large walking", Array(AllLarge.Get(0), AllLarge.Get(1), AllLarge.Get(2)))
   X2.GraphicCache.PutGraphic("mario large standing", Array(AllLarge.Get(6)))
   X2.GraphicCache.PutGraphic("mario large jumping", Array(AllLarge.Get(4)))
   X2.GraphicCache.PutGraphic("mario large strike", Array(AllLarge.Get(5)))
   X2.GraphicCache.PutGraphic("mario large change direction", Array(AllLarge.Get(3)))
   X2.GraphicCache.PutGraphic("mario change size", Array(AllSmall.Get(6), AllLarge.Get(6)))
End Sub
This code reads a sprite sheet and splits it to various groups. The key to each group is the "graphic name" parameter.

Later we can switch groups of frames by changing bw.GraphicName:
B4X:
Private Sub ChangeSize (ToLarge As Boolean)
   x2.SoundPool.PlaySound("powerup")
   bw.GraphicName = "mario change size"

And now for more advanced ways...
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
<background>
GS.DrawingTask is a list of DrawingTask types.
At the end of each loop (when GS.ShouldDraw is True) the list is passed to:
B4X:
MainBC.DrawBitmapCreatorsAsync(Me, "BC", gs.DrawingTasks)

All the drawing tasks are then executed asynchronously and BC_BitmapReady is raised when the new bitmap is ready.

You are not limited to the bodies or to anything else. You can add any drawing task you like to this list and it will be drawn.
DrawingTask is a type declared in BitmapCreator. Any bitmap can be converted to BitmapCreator and then drawn with a DrawingTask. See X2Utils.BitmapToBC.

You should however be careful as you can easily kill the performance if you are doing something inefficient every tick.
</background>

A simple set of steps to create custom graphics with B4XCanvas:

- Get a cached B4XCanvas with x2.GraphicCache.GetCanvas. This step is optional. You can create your own canvas and use it instead. Just make sure not to create a new canvas each time.
- Make the drawings and extract the bitmap.
- Convert the bitmap to X2ScaledBitmap:
B4X:
Dim sb As X2ScaledBitmap
sb.Bmp = cvs.CreateBitmap.Crop(0, 0, r.Right, r.Bottom)
sb.Scale = 1

- Get a "temp name" for the new graphic, add the graphic to the cache and set the body wrapper GraphicName property:
B4X:
Dim GraphicName As String = x2.GraphicCache.GetTempName
Dim gd As X2SpriteGraphicData = x2.GraphicCache.PutGraphic(GraphicName, Array(sb))
gd.VerticalSymmetry = True
gd.HorizontalSymmetry = True
bw.GraphicName = GraphicName

See the RotatingBlock class in Walking Character example. These steps are also used in other examples.

DrawRope from the Joints example works in a different way:

1. It gets the rotated full length rope graphic from the cache.
2. It calculates the current rope size based on the bodies positions.
3. It defines a rectangle that will be used to "crop" the full image.
4. It creates a drawing task with X2.CreateDrawTaskFromCompressedBC.

X2.WorldPointToMainBC helps us here to convert the world point to the MainBC "pixel".

A simpler version of these steps happens in Pipe class of Clumsy Bird example. The idea is the same. We need to draw a part of the full graphic. It is simpler with the pipes as they cannot rotate.
 

sorex

Expert
Licensed User
Longtime User
that template method saves use from a lot of code writing.

well done.
 

developer_123

Active Member
Licensed User
Longtime User
If you want to use XUI2D then start with the recommended way and use Tiled. Open X2TileMap and you will see that it is a complex class with many features. No reason to rewrite it yourself.

Everything can be later customized.

Another way to set the graphics, still in a simple way, is demonstrated in the Mario example:
B4X:
Private Sub LoadMarioGraphics
   Dim bmp As B4XBitmap = xui.LoadBitmap(File.DirAssets, "mario_bros.png")
   Dim NumberOfSprites As Int = 14
   Dim MarioSmall As B4XBitmap = bmp.Crop(80, 32, NumberOfSprites * 16, 16)
   Dim AllSmall As List = X2.ReadSprites(MarioSmall, 1, NumberOfSprites, 1, 1)
   X2.GraphicCache.PutGraphic("mario small walking", Array(AllSmall.Get(0), AllSmall.Get(1), AllSmall.Get(2)))
   X2.GraphicCache.PutGraphic("mario small standing", Array(AllSmall.Get(6)))
   X2.GraphicCache.PutGraphic("mario small jumping", Array(AllSmall.Get(4)))
   X2.GraphicCache.PutGraphic("mario small strike", Array(AllSmall.Get(5)))
   X2.GraphicCache.PutGraphic("mario small change direction", Array(AllSmall.Get(3)))
   NumberOfSprites = 19
   Dim MarioLarge As B4XBitmap = bmp.Crop(80, 0, NumberOfSprites * 16, 32)
   Dim AllLarge As List = X2.ReadSprites(MarioLarge, 1, NumberOfSprites, 1, 2)
   X2.GraphicCache.PutGraphic("mario large walking", Array(AllLarge.Get(0), AllLarge.Get(1), AllLarge.Get(2)))
   X2.GraphicCache.PutGraphic("mario large standing", Array(AllLarge.Get(6)))
   X2.GraphicCache.PutGraphic("mario large jumping", Array(AllLarge.Get(4)))
   X2.GraphicCache.PutGraphic("mario large strike", Array(AllLarge.Get(5)))
   X2.GraphicCache.PutGraphic("mario large change direction", Array(AllLarge.Get(3)))
   X2.GraphicCache.PutGraphic("mario change size", Array(AllSmall.Get(6), AllLarge.Get(6)))
End Sub
This code reads a sprite sheet and splits it to various groups. The key to each group is the "graphic name" parameter.

Later we can switch groups of frames by changing bw.GraphicName:
B4X:
Private Sub ChangeSize (ToLarge As Boolean)
   x2.SoundPool.PlaySound("powerup")
   bw.GraphicName = "mario change size"

And now for more advanced ways...
Good day! Since I require my character to change animation according to the events that occur in the game, I stopped using the graphics files in the tiled, and started loading the sprite arrangements by assigning a name to each animated situation. I followed Mario's example and loaded the image arrangement into the cache using the next structure:

B4X:
Dim all As List = X2.ReadSprites(xui.LoadBitmap(File.DirAssets, "walking_sprite.png"), 1, 3, 1, 1)
    X2.GraphicCache.PutGraphic("walking", Array(all.Get(0), all.Get(1)))
.
.
.
sub do_any_thing
bw.GraphicName = "walking"
end sub

in the tiled is set 70 ms to interval between frames, but the image of the character is always the same (not change)! I don't know why....

maybe i'm ignoring something , so appreciate any clue
 
Top