There are all kinds of units and scales in XUI2D. It is important to understand them and use them consistently.
XUI2D (like Box2D) is based on the metric system.
- Length is measured in meters.
- Velocity is measured in meters / second.
- Mass is measured in kilograms.
- Acceleration is measured in meters / second ^ 2
No pixels and no DIP units.
The worlds coordinates go from left to right and from the bottom to the top, unlike the screen coordinates that go from the top to the bottom.
The screen dimensions are configured in Game.Initialize:
The first parameter is the coordinate of the screen center. X = 0 meters and y = 3.5 meters.
The second parameter is the width length. It is 8 meters here.
If we run the hello world example with width set to 30 meters then it will look like this:
Note that changing the dimensions will not affect the already loaded graphics.
You can change the world center with X2.UpdateWorldCenter.
When you load image files with X2.LoadBmp you set their width and height (in meters). This is the simplest way and in many cases the best way to create the bodies graphics.
Two other common ways to create the graphics are with B4XCanvas or BitmapCreator.
Creating the a box with specific size based on BitmapCreator:
The important method here is X2.MetersToBCPixels. It converts the length measured in meters to "BCPixels".
Creating the box with B4XCanvas:
To avoid creating a new B4XCanvas we can get one of the canvases used by GraphicCache.
These canvases are square sized.
1. Get the canvas:
We need to divide the requested size with X2.BmpSmoothScale. This scale is used internally for antialiasing of rotated graphics.
2. Draw:
Again we use MetersToBCPixels to convert the lengths.
3. Get the bitmap and add it to the cache:
Cvs.CreateBitmap returns the internal mutable bitmap in B4A. As call Crop here it doesn't really matter as we get a copy of the bitmap. However if we weren't calling Crop then we should have made a copy with:
Time Units
It takes some time to get used to thinking in meters instead of pixels. The same is true to time units. It is tempting to count frames or game loop iterations. This is a mistake as both these measurements are not consistent.
The game time is measured in milliseconds. X2.TimeStepMs returns the duration of the last iteration.
The value of X2.TimeStepMs is determined by X2.TargetFPS. By default X2.TargetFPS is set to 60 in release mode and 30 in debug mode. Note that it isn't affected by the actual number of frames per second (when needed the engine make drawings every two iterations).
You can also slow down the game or make it run faster by setting X2.SlowDownPhysicsScale. Make sure to call X2.UpdateTimeParameters after you change it.
The physical engine works with seconds.
XUI2D (like Box2D) is based on the metric system.
- Length is measured in meters.
- Velocity is measured in meters / second.
- Mass is measured in kilograms.
- Acceleration is measured in meters / second ^ 2
No pixels and no DIP units.
The worlds coordinates go from left to right and from the bottom to the top, unlike the screen coordinates that go from the top to the bottom.
The screen dimensions are configured in Game.Initialize:
B4X:
X2.ConfigureDimensions(world.CreateVec2(0, 3.5), 8)
The second parameter is the width length. It is 8 meters here.
If we run the hello world example with width set to 30 meters then it will look like this:
Note that changing the dimensions will not affect the already loaded graphics.
You can change the world center with X2.UpdateWorldCenter.
When you load image files with X2.LoadBmp you set their width and height (in meters). This is the simplest way and in many cases the best way to create the bodies graphics.
Two other common ways to create the graphics are with B4XCanvas or BitmapCreator.
Creating the a box with specific size based on BitmapCreator:
B4X:
BoxSize = X2.CreateVec2(0.5, 1)
Dim bc As BitmapCreator
bc.Initialize(X2.MetersToBCPixels(BoxSize.X), X2.MetersToBCPixels(BoxSize.Y))
bc.FillGradient(Array As Int(xui.Color_White, xui.Color_Black), bc.TargetRect, "TL_BR")
Dim sb As X2ScaledBitmap
sb.Bmp = bc.Bitmap
sb.Scale = 1
X2.GraphicCache.PutGraphic("block", Array(sb))
Creating the box with B4XCanvas:
To avoid creating a new B4XCanvas we can get one of the canvases used by GraphicCache.
These canvases are square sized.
1. Get the canvas:
B4X:
Dim CvsMinSize As Int = X2.MetersToBCPixels(Max(BoxSize.X, BoxSize.Y))
Dim Cvs As B4XCanvas = X2.GraphicCache.GetCanvas(CvsMinSize / X2.BmpSmoothScale)
2. Draw:
B4X:
Dim r As B4XRect
r.Initialize(0, 0, X2.MetersToBCPixels(BoxSize.X) + 1, X2.MetersToBCPixels(BoxSize.Y) + 1)
Cvs.ClearRect(r)
Cvs.DrawRect(r, xui.Color_Black , True, 0)
Cvs.DrawCircle(r.CenterX, r.CenterY, X2.MetersToBCPixels(0.15), xui.Color_White, True, 0)
3. Get the bitmap and add it to the cache:
B4X:
Dim sb As X2ScaledBitmap
sb.Bmp = Cvs.CreateBitmap.Crop(0, 0, r.Right, r.Bottom)
sb.Scale = 1
X2.GraphicCache.PutGraphic("block", Array(sb))
B4X:
sb.Bmp = X2.CreateImmutableBitmap(Cvs.CreateBitmap)
B4X:
Dim CvsMinSize As Int = X2.MetersToBCPixels(Max(BoxSize.X, BoxSize.Y))
Dim Cvs As B4XCanvas = X2.GraphicCache.GetCanvas(CvsMinSize) 'not divided by X2.BmpSmoothScale
Dim scale As Float = X2.mBCPixelsPerMeter * X2.BmpSmoothScale
Dim r As B4XRect
r.Initialize(0, 0, BoxSize.X * scale, BoxSize.Y * scale)
Cvs.ClearRect(r)
Cvs.DrawRect(r, xui.Color_Black , True, 0)
Cvs.DrawCircle(r.CenterX, r.CenterY, 0.15 * scale, xui.Color_White, True, 0)
Dim sb As X2ScaledBitmap
sb.Bmp = Cvs.CreateBitmap.Crop(0, 0, r.Right, r.Bottom)
sb.Scale = X2.BmpSmoothScale '<-----
X2.GraphicCache.PutGraphic2("block", Array(sb), True, 5)
Time Units
It takes some time to get used to thinking in meters instead of pixels. The same is true to time units. It is tempting to count frames or game loop iterations. This is a mistake as both these measurements are not consistent.
The game time is measured in milliseconds. X2.TimeStepMs returns the duration of the last iteration.
The value of X2.TimeStepMs is determined by X2.TargetFPS. By default X2.TargetFPS is set to 60 in release mode and 30 in debug mode. Note that it isn't affected by the actual number of frames per second (when needed the engine make drawings every two iterations).
You can also slow down the game or make it run faster by setting X2.SlowDownPhysicsScale. Make sure to call X2.UpdateTimeParameters after you change it.
The physical engine works with seconds.
Last edited: