B4A Library libGDX - Game Engine



One of the best game engines for Android is now available to B4A users. Unleash your creativity!

You can read a description of this library in this guide.

Download for B4A v10.60 and older (4 MB)
Download for B4A v10.70 and newer (4 MB)

Starting from version 1.13, the library is compiled with Java 8, and thus requires a recent version of B4A and Java 8+.
To install the library, copy the .jar file and the .xml file in your libraries folder.

This library is not compatible with the Debug mode. Ensure that you always compile in Release mode.

Download also the examples and templates.

You can reduce the weight of the library if you want to keep your APK file as small as possible. Read this post to learn how to create your Lite version.

Tutorials:
How to make games
Introduction to the libGDX library
PacDroid: from scratch to fun
Shaders

Take also a look at the Cloney Bird tutorial by andymc.

Plugins:
Box2DLights
SpecialFX

Versions:
 
Last edited by a moderator:

Informatix

Expert
Licensed User
Longtime User
The OpenGL engine runs as fast as the hardware can display the rendering. You cannot change that. It's usually about 60 fps.
If the objects move too fast in your game, then you probably chose a wrong unit for their move. All moves in a game should be expressed in dips/second (or in %xy/second). If you want for example that an alien ship moves horizontally at 200 dips/second, you increase its X position in the Render event with the following computation: lGdx.Graphics.DeltaTime * 200 * Density. The ship will move exactly at the same speed on all devices.
 

wonder

Expert
Licensed User
Longtime User
Thanks for the tip!! I will try to implement it in that manner.

Right now I have something like:
B4X:
actor_x = actor_x + actor_direction_x
actor_y = actor_y + actor_direction_y

In order to implement your method, shall I give up on my "speed limiter" and do it this way?
B4X:
actor_x = actor_x + actor_direction_x * lGdx.Graphics.DeltaTime
actor_y = actor_y + actor_direction_y * lGdx.Graphics.DeltaTime

Is this the right way?
 

Informatix

Expert
Licensed User
Longtime User
Yes. The main advantage of this solution is that it takes into account the exact time spent to render your scene. If on a device, DeltaTime is constant at 16 ms, and on another device (slower, on slowed down by other apps) DeltaTime varies from 20 to 30ms, the object will be at the same place on the two devices after the same time span (it will move faster on the slowest device, but this increase in speed will be counterbalanced by the time elapsed between two frames).
 

notedop

Member
Licensed User
Longtime User
Hi @Informatix

I'm moving the player with box2d impulses, can the same logic be applied but then with the amount of force applied to the body?

B4X:
'============================================
'============Write code for movement=========
'============================================
'Handle the player movement based on accelerator
'Only if object is player
'Accel_Base is vector2 which is set onload of the level based on the accelerator position at the moment of load.
'ac_x and ac_y are accelerator position at the moment of draw.
'Deathzone is zone where player movement should stabilize

If IsPlayer Then
    If ac_x> (Main.Accel_Base.x +DeathZone) Then        'check if outside deathzone
        'Log("Tilting top - up")
        If (Bodie.LinearVelocity.y > (MAXIMUM_VELOCITY*-1)) OR (Bodie.LinearVelocity.y > 0) Then
            Bodie.applyLinearImpulse2(0,ACCELERATION*-1, Bodie.WorldCenter.x,Bodie.WorldCenter.y, True)
        End If
    Else If ac_x < (Main.Accel_Base.x -DeathZone) Then'check if outside deathzone
        'Log("Tilting bottom - up")
        If (Bodie.LinearVelocity.y < MAXIMUM_VELOCITY) OR (Bodie.LinearVelocity.y < 0) Then
            Bodie.applyLinearImpulse2(0,ACCELERATION, Bodie.WorldCenter.x,Bodie.WorldCenter.y, True)
        End If
    Else'within deathzone; stabilize player
    'Log("Deathzone: y velocity=" & Bodie.LinearVelocity.y )
        If Bodie.LinearVelocity.y > DAMPING Then
            Bodie.applyLinearImpulse2(0,-DAMPING, Bodie.WorldCenter.x,Bodie.WorldCenter.y, True)
        Else If Bodie.LinearVelocity.y < -DAMPING Then
            Bodie.applyLinearImpulse2(0,DAMPING, Bodie.WorldCenter.x,Bodie.WorldCenter.y, True)
        End If
    End If
End If

Would below code make sense? Adding gamespeed as global setting and including the deltatime.
B4X:
Bodie.applyLinearImpulse2(0,((ACCELERATION*-1)*gamespeed)*deltatime, Bodie.WorldCenter.x,Bodie.WorldCenter.y, True)
 

notedop

Member
Licensed User
Longtime User
http://www.iforce2d.net/b2dtut/worlds
In this example, each call to Step will advance the simulation by 1/20th of a second, so a body moving at 5m/s like in our first scene would move 5/20=0.25m in that time. The timeStep also affects how gravity gets to act on each body. You might find that things appear to fall at different accelerations depending on the time step. To make a realistic looking simulation, you will generally set the timeStep value to match the number of times per second you will be calling the world's Step() function in your game. For example in the testbed, the default framerate is 60 frames per second, so Step() is called 60 times a second with timeStep set to 1/60th of a second.

Am in correct; I should not adjust the force, but adjust the timestep to handle gamespeed on different devices as the world handles the rest?
Looking at the box2dlight example it seems that you've been doing something similair already.

B4X:
    'Settings
    Dim RAYS_PER_BALL As Int = 128
    Dim BALLSNUM As Int = 3
    Dim LIGHT_DISTANCE As Float = 16
    Dim RADIUS As Float = 1
    Dim MAX_FPS As Int = 60
    Dim MIN_FPS As Int = 30
    Dim TIME_STEP As Float = 1 / MAX_FPS
    Dim MAX_TIME_STEP As Float = 1 / MIN_FPS
    Dim VELOCITY_ITERS As Int = 6
    Dim POSITION_ITERS As Int = 2

Sub Fixed_Step(Delta As Float) As Boolean
    PhysicsTimeLeft = PhysicsTimeLeft + Delta
    If PhysicsTimeLeft > MAX_TIME_STEP Then
        PhysicsTimeLeft = MAX_TIME_STEP
    End If
    Dim Stepped As Boolean = False
    Do While PhysicsTimeLeft >= TIME_STEP
        World.Step(TIME_STEP, VELOCITY_ITERS, POSITION_ITERS)
        PhysicsTimeLeft = PhysicsTimeLeft - TIME_STEP
        Stepped = True
    Loop
    Return Stepped
End Sub

This would imply that my 'solution' does not make sense and I should leave it as is, but set a max/min frame rate instead and call the fixed_step function each render.
 

Informatix

Expert
Licensed User
Longtime User
You found the right function. In this code, TIME_STEP is constant and an accumulator is used to determine how many steps have to be computed before being drawn.
 

notedop

Member
Licensed User
Longtime User
Okay, i've implemented above function.

I have a slow device (HTC One V) so I would expect that the player would move same speed as a fast device and instead of moving smoothly, make bigger 'jumps' each draw.
But it's not... There are still moments where I have a lot of tiles visible, which has affect on the device and the player slows down and starts to 'stagger'. The camera is following the player so the level slows down.

There is improvement but not to the full extend I would expect.
Are my expectations correct? The player should move by a greater x/y value on slow devices even if box2d forces/impulses are applied, right?

At first I thought this was due to the timing of the update functions;
I have a object class with a draw function to draw the player, bullets etc.
Within the sub Draw of the object class I call the classes Update.
I should call the Update sub of the object class in the main update sub and not via the draw sub in the class, right?

I changed this, but it does not have the expected effect...

Any other ideas?
 

Informatix

Expert
Licensed User
Longtime User
In my code in post #286, I set a minimum number of FPS (MIN_FPS). If the real number of FPS is under this value, you will notice the slowing down. You can lower this value and see whether that solves your problem, but this already means that your game is probably too demanding for the device. You should improve the speed of your code above all.
 

notedop

Member
Licensed User
Longtime User
I did some tests after my post yesterday evening and indeed noticed that the framerate goes down to 9fps at a certain point. So basically the behavior i'm seeing is as expected.

I guess this leaves me with the following actions:
  1. optimize code to the full extend
  2. buy a faster phone/tablet for testing purposes
 

wonder

Expert
Licensed User
Longtime User
Hello again,

I'm totally stuck with the following situation... I don't know what to do anymore.

Everything works as expected after implementing this method:
B4X:
actor_x = actor_x + actor_direction_x * lGdx.Graphics.DeltaTime
actor_y = actor_y + actor_direction_y * lGdx.Graphics.DeltaTime


However:

When I try to apply it to the Z axis (my Z axis is later converted to X,Y coordinates)
B4X:
jump_direction(player) = initial_jump_direction(player) * lGdx.Graphics.DeltaTime
stage_gravity(active_stage) = initial_stage_gravity(active_stage) * lGdx.Graphics.DeltaTime
The player jumps higher on slower devices (old Sony Xperia: lgdx @ 44 FPS) and jumps lower on faster devices (HTC M7: lgdx @ 77 FPS).


I also tried to do it this way:
B4X:
'When the jump button is pressed the actor_direction_z(player) becomes 330.
'Something like this:
jump_direction(player) =  330
If jump_btn_pressed = True Then actor_direction_z(player) = jump_direction(player)

(...)

actor_direction_z(player) = actor_direction_z(player) + stage_gravity(player)
actor_z(player) = actor_z(player) + actor_direction_z(player) * lgdx.Graphics.DeltaTime
...and it still doesn't work. The player jumps at different heights in different devices.

Is my understanding of physics wrong??

Note: Without the "z = z + dz * lGdx.graphics.DeltaTime" method, the jump height is the same on all devices.
 

Informatix

Expert
Licensed User
Longtime User
Is direction an angle? If yes, then don't add DeltaTime to it. If not, I don't understand what it is.
 

wonder

Expert
Licensed User
Longtime User
It's not an angle, it's a straight vertical direction... I'll send you the APK.
(Press X to jump)

You may press the CIRLCLE button to decrease the engine speed (simulate a slower device).
At 20 FPS (for example) the player jumps way higher than before.
 

Informatix

Expert
Licensed User
Longtime User
I don't understand how you compute the jump.
You can see in the Perf_Skaters demo an example of jumping sprite (with gravity applied) that uses DeltaTime.
 
Last edited:

wonder

Expert
Licensed User
Longtime User
I basically adapted this JAVA code:

Working example HERE

B4X:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var positionX = 100.0;
var positionY = 175.0;
var velocityX = 4.0;
var velocityY = 0.0;
var gravity = 0.5;
var onGround = false;

window.addEventListener("mousedown", StartJump, false);
window.addEventListener("mouseup", EndJump, false);

Loop();

function StartJump()
{
    if(onGround)
    {
        velocityY = -12.0;
        onGround = false;
    }
}

function EndJump()
{
    if(velocityY < -6.0)
        velocityY = -6.0;
}

function Loop()
{
    Update();
    Render();
    window.setTimeout(Loop, 33);   
}

function Update()
{
    velocityY += gravity;
    positionY += velocityY;
    positionX += velocityX;
   
    if(positionY > 175.0)
    {
        positionY = 175.0;
        velocityY = 0.0;
        onGround = true;
    }
   
    if(positionX < 10 || positionX > 190)
        velocityX *= -1;
}

function Render()
{
    ctx.clearRect(0, 0, 200, 200);
    ctx.beginPath();
    ctx.moveTo(0,175);
    ctx.lineTo(200,175);
    ctx.stroke();
    ctx.beginPath();
    ctx.moveTo(positionX - 10, positionY - 20);
    ctx.lineTo(positionX + 10, positionY - 20);
    ctx.lineTo(positionX + 10, positionY);
    ctx.lineTo(positionX - 10, positionY);
    ctx.closePath();
    ctx.stroke();
}
 

wonder

Expert
Licensed User
Longtime User
Alright, I checked the Skaters sample:

B4X:
'Moves the skaters
Skater.X = Skater.X + (Skater.velocityX * timeDeltaSeconds)
Skater.Y = Skater.Y + (Skater.velocityY * timeDeltaSeconds)

'Applies gravity
Skater.velocityY = Skater.velocityY - (SPEED_OF_GRAVITY * timeDeltaSeconds)
This is pretty much what I have so far... I must have a bug somewhere else.
I will revise my code (by the 1000th time) and rewrite the jump module from scratch if necessary.

Anyway, many thanks for pointing me in this direction.
 

Informatix

Expert
Licensed User
Longtime User
The easier way to compute a vertical jump is to do a non-linear interpolation (lgMathInterpolation) between 0 and 1 (up) then 1 and 0 (down). The parameter of the Apply function is SumOfDeltaTime/(JumpDurationInSec/2). The result is multiplied by the max. height of jumps:
Yup = interpolation.apply(SumOfDeltaTime/(JumpDurationInSec/2)) * MaxHeight
When the max.height is reached, you reset SumOfDeltaTime to 0 and invert the direction:
Ydown = MaxHeight - (interpolation.apply(SumOfDeltaTime/(JumpDurationInSec/2)) * MaxHeight)
 

wonder

Expert
Licensed User
Longtime User
Thanks for the non-linear interpolation method. At this moment I'm still trying to "fix" the code I already have, since it works flawlessly without the timestep. Reading your tutorials again, I came across this paragraph:


Although I believe that my problem is other than the tunnel effect, could you please elaborate on this matter?
Thanks in advance!
 
Last edited:

Informatix

Expert
Licensed User
Longtime User
Although I believe that my problem is other than the tunnel effect, could you please elaborate on this matter?

From wikipedia: "the tunnel effect is the perception as a single object moving beyond an occluding object and then reappearing after a suitable amount of time on the other side of it"

When the step to move an object is too big, it can go through a limit that is not supposed to cross. For example: you fire a bullet to an enemy target. If your bullet moves at 1 pixel/sec, the move is so slow that you can compute a collision with the target with no risk of passing through. On the contrary, if it moves at 2000 pixels/sec and the device takes 150ms to draw the next frame due to a sudden slow down, then your bullet is moved behind the target and never hit it. That's why you should cap the step to use.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…