Android Tutorial Introduction to the libGDX library

Introduction to the libGDX library

What is libGDX ?

libGDX is a game engine. As we saw in the first tutorial, a game engine provides a framework to create games and covers all aspects (rendering, animation, input, music, networking, physics, ...) of various kinds of games.

libGDX is considered as one of the best and fastest engine for the Android world. It is free, rich-featured, reliable, and proved its efficiency in a lot of well-known games (Ingress, Zombie Smasher, Apparatus, Monsterama Park, Clash of the Olympians, Bumbledore, etc.)

It’s a layered framework: it goes from low-level classes for OpenGL experts to high-level classes, easy to use by beginners. It includes a scene graph (Scene2D classes), a physics engine (Box2D classes), a particle system, a map renderer, a sprite batcher, an extensive set of mathematics classes… more than 200 classes in total.

For technical reasons, the version for Basic4Android cannot be multi-platform, and by choice, the current release doesn't include the 3D classes (except the ones for the perspective camera and for the decals) and the Daydream class.

libGDX was created in 2010 by Mario Zechner (badlogicgames.com) and is maintained by M. Zechner, Nathan Sweet (esotericsoftware.com) and a community of developers.

Minimum requirements

OpenGL ES 2.0
Android Froyo (API 8)

Hardware acceleration

libGDX does not require that you enable hardware acceleration on your device because it is based on OpenGL, which interacts directly with the GPU.

Debugging

You cannot use the debugger of B4A with libGDX because most of the code of the library runs in a different thread. You have to use the Log() function to debug your game.

The library provides a debug renderer for Box2D (lgBox2DDebugRenderer), a debug renderer for Scene2D (lgScn2DDebugRenderer) and a profiler for OpenGL (lgGLProfiler).

A word about the classes

The main class is LibGDX. All other classes are prefixed by lg.
All Box2D classes are prefixed by lgBox2D. All Scene2D classes are prefixed by lgScn2D. All Map classes are prefixed by lgMap. All Math classes are prefixed by lgMath.

The LibGDX class gives access to five interfaces: Audio (lgAudio), Files (lgFiles), Graphics (lgGraphics), Input (lgInput), and Net (lgNet). You will use the Input interface, for example, to get the input from the accelerometer.

With some classes (e.g. the five interfaces), you cannot create a new instance with Dim. You have to use an instance returned by the library. For example, you cannot write:
B4X:
Dim Graphics As lgGraphics
Graphics = lGdx.Graphics
but you can write:
B4X:
Dim Graphics As lgGraphics = lGdx.Graphics

Some classes cannot be instantiated at all because they are generic classes (e.g. com.badlogic.gdx.scenes.scene2d.utils.Drawable or com.badlogic.gdx.maps.tiled.TiledMapTile). In this case, either you store their instance as an Object or you use a subclass, e.g.:
B4X:
Dim objTile As Object = CurrentLayer.GetCell(X, Y).Tile
Dim staticTile As lgMapStaticTiledMapTile = CurrentLayer.GetCell(X, Y).Tile

OpenGL ES

I explained what OpenGL is in the previous tutorial and I won't discuss it further here because the main advantage to use a game engine like libGDX is to benefit from the abstraction layer above OpenGL. However, if you need (or want) to call directly OpenGL, here's how to get access to the classes and functions:
B4X:
Dim lGdx_GL20 As lgGL20 = lGdx.Graphics.GL20
or better (includes also the constants):
B4X:
Dim GL As lgGL

Note: libGDX uses the 2D coordinate system and the color encoding of OpenGL ES, so the Y-axis is pointing upwards and each color value ranges from 0 to 1.

The libGDX life-cycle

An important thing to keep in mind about libGDX is that it runs in its own thread. Your Basic4Android application runs most of the time in a different thread called the UI thread, or main thread. That means you cannot access the other views of your activity and change their properties from the libGDX thread. Fortunately, there's a function in the LibGDX class that passes the runnable (the piece of code to execute) from a thread to the other: CallSubUI. So if you want to change the activity title, set a label text or show a MsgBox from the libGDX thread, don't forget to use this function to avoid a crash!

Since libGDX runs in a different thread, you have to inform its library of the events of your activity : Create, Pause and Resume. First, create an instance of libGDX in Globals :
B4X:
Dim lGdx As libGDX
In Activity_Create (and nowhere else), add the Initialize function :
B4X:
lGdx.Initialize(False, "LG") 'fills the activity with the libGDX surface, uses OpenGL 1 for compatibility and prefixes the events with LG
In Activity_Resume, add the following line :
B4X:
If lGdx.IsInitialized Then lGdx.Resume
In Activity_Pause, add the following line :
B4X:
If lGdx.IsInitialized Then lGdx.Pause

You could initialize libGDX differently. For example, it could be limited to a view with InitializeView. You could also define a configuration (lgConfiguration class) and pass it to libGDX. Example:
B4X:
Dim Config As lgConfiguration

'Disables the accelerometer and the compass
Config.useAccelerometer = False
Config.useCompass = False

'Uses a WakeLock (the device will stay on)
Config.useWakelock = True

'Creates the libGDX surface
lGdx.Initialize2(Config, "LG")

Once done, your library is ready to raise the events of its life-cycle : Create, Resize, Render, Pause, Resume, Dispose. These events are the place to put all the code of your game. Don't put anything in the usual activity events. They are reserved for your other views and are raised by the UI thread.

Create :

Create is the first raised event. It is raised soon after the initialization of the library and the creation of the OpenGL surface.
In this event, initialize your renderer and your input processors, load your resources (we'll see that in detail later) and initialize your game data.

Resize :

Resize is raised when the size of the libGDX surface changes. Under Android, that should only happen when you start the application and when it is restarted after a rotation or resumed.
It is raised at least once, after Create, and, when the application is resumed, just before Resume.
In this event, initialize the camera viewport. It's probably the only use you will find for it.
This event returns the new width and height in pixels.

Render :

Render is raised as soon as possible after Create and Resize.
It's where things are drawn. It's also where you have to put the logic of your game, but I would not recommend putting hundreds of lines of code here. Instead, create new subs and new modules and call them from this event.
The first lines in Render should be to clear the screen. Example:
B4X:
lGdx_GL.glClearColor(0, 0, 1, 1) 'Blue background
lGdx_GL.glClear(lGdx_GL.GL10_COLOR_BUFFER_BIT)

Pause :

Pause is raised when the activity is sent in the background, rotated or exited.
It's the right place to save your game data.
Note that the OpenGL context is destroyed when the app goes in the background, so all your unmanaged textures and pixmaps have to be reloaded or recreated in the Resume event when the app returns to the foreground.

Resume :

Contrary to the Resume event of your activity, this one is not raised after Create, only when the application returns from a pause.
As the OpenGL context is destroyed when the app goes in the background, all your unmanaged* textures and pixmaps have to be reloaded or recreated when this event is raised. More info here. *Not loaded by an asset manager.

Dispose :

Dispose is called when the activity is exited, after Pause, or when the device is rotated.
In this event, release all the used resources by calling the Dispose function of objects (if they have one).

The life-cycle :
application_lifecycle_diagram.png


Multiple screens

A game is made of many screens. You could create an activity for each one, but that would not be very convenient because you'd have to reinitialize the library in each activity and reload some resources. Moreover, that would not ease any graphical transition between screens. In fact, most games are made with a very small number of activities and make use of a screen manager instead. The screen manager stores the reference of the different screens and allows switching between them. Each screen has its own life-cycle.
To create a screen manager with two screens, for example, declare them in Globals:
B4X:
Dim lGdx_ScrMgr As lgScreenManager
Dim lGdx_Screen(2) As lgScreen
Then add these lines in the Create event handler:
B4X:
'Creates two screens
lGdx_ScrMgr.Initialize(lGdx)
lGdx_Screen(0) = lGdx_ScrMgr.AddScreen("LGS1")
lGdx_Screen(1) = lGdx_ScrMgr.AddScreen("LGS2")
Show the first screen:
B4X:
lGdx_ScrMgr.CurrentScreen = lGdx_Screen(0)

When you want to change the current screen, just change the value of the CurrentScreen property. That will raise the Hide event of the previous screen and the Show event of the new one.

The screens have the same life-cycle as the library, and thus the same events except that Create is named Show and Dispose is named Hide.

Input processor and gesture detector

To get the input events raised by your players, you have to declare input processors. libGDX has an input processor for keyboard and touch events (lgInputProcessor) and a specialized input processor for gestures (lgGestureDetector).
Start by declaring them in Globals:
B4X:
Dim lGdx_IP As lgInputProcessor
Dim lGdx_GD As lgGestureDetector
Initialize them in the Create event (or the Show event of a screen if you want different processors for different screens):
B4X:
lGdx_IP.Initialize("IP")
lGdx_GD.Initialize("GD")
And add the event handlers that you need:
B4X:
Sub IP_KeyDown(KeyCode As Int) As Boolean
   Return False
End Sub

Sub IP_KeyUp(KeyCode As Int) As Boolean
   Return False
End Sub

Sub IP_KeyTyped(Character As Char) As Boolean
   Return False
End Sub

Sub IP_TouchDown(ScreenX As Int, ScreenY As Int, Pointer As Int) As Boolean
   Return False
End Sub

Sub IP_TouchDragged(ScreenX As Int, ScreenY As Int, Pointer As Int) As Boolean
   Return False
End Sub

Sub IP_TouchUp(ScreenX As Int, ScreenY As Int, Pointer As Int) As Boolean
   Return False
End Sub

Sub GD_TouchDown(X As Float, Y As Float, Pointer As Int) As Boolean
   Return False
End Sub

Sub GD_Fling(VelocityX As Float, VelocityY As Float) As Boolean
   Return False
End Sub

Sub GD_LongPress(X As Float, Y As Float) As Boolean
   Return False
End Sub

Sub GD_Pan(X As Float, Y As Float, DeltaX As Float, DeltaY As Float) As Boolean
   Return False
End Sub

Sub GD_Pinch(InitialPointer1 As lgMathVector2, InitialPointer2 As lgMathVector2, Pointer1 As lgMathVector2, Pointer2 As lgMathVector2) As Boolean
   Return False
End Sub

Sub GD_Tap(X As Float, Y As Float, Count As Int) As Boolean
   Return False
End Sub

Sub GD_Zoom(InitialDistance As Float, Distance As Float) As Boolean
    Return False
End Sub

Description of events :

Fling: The user quickly dragged a finger across the screen, then lifted it. Useful to implement swipe gestures.
Pan: The user is dragging a finger across the screen. The detector reports the current touch coordinates as well as the delta between the current and previous touch positions. Useful to implement camera panning in 2D.
Pinch: Similar to zoom. The detector reports the initial and current finger positions instead of the distance. Useful to implement camera zooming and more sophisticated gestures such as rotation.
Tap: The user touched the screen and lifted the finger. The finger must not move outside a specified square area around the initial touch position for a tap to be registered. Multiple consecutive taps will be detected if the user performs taps within a specified time interval.
Zoom: The user has placed two fingers on the screen and is moving them together/apart. The detector reports both the initial and current distance between fingers in pixels. Useful to implement camera zooming.

The other events are self-explanatory.

.....
 
Last edited:

Informatix

Expert
Licensed User
Longtime User
Camera

The lgOrthographicCamera class operates as a very simple real world camera. You can move and rotate the camera around, zoom in and out without having to manually operate on the projection and view matrices.

The first thing to do with a camera is to set its viewport (usually in the Resize event sub). The viewport is the rectangular area visible at any given time from the whole world. Once set, it is not recommended to change its values. Use instead the Zoom property or the Translate function, for example, to change the view.
The viewport is always scaled up to the actual resolution, so you can choose any unit for its size. This unit will be used for the size and position of all objects to display if you set the renderer to use the coordinate system of the camera, which is recommended. For example, you can choose an unit based on the screen ratio to set sizes and positions as percentages of the screen size:
B4X:
Camera.Initialize2(1, Height / Width)
Camera.SetToOrtho(False)
or you may stay with the default pixel unit:
B4X:
Camera.Initialize
Camera.SetToOrtho(False)

To translate the viewport coordinates of the camera to/from the screen coordinates, use the Project and Unproject functions.

Note: If you don't call one of the SetToOrtho functions after the initialization, (0, 0) will be in the middle of the screen. SetToOrtho allows also to reverse the Y-axis to have the 0 at the top, as you are used to with Basic4Android, but the rendering will be flipped too on this axis and you'll have to use the Flip function of each object (if it has one) to fix that.

Call the Update function whenever you make a change to recalculate the projection and view matrices of the camera.

Pixmap, Texture, TextureRegion, Sprite, NinePatch and Decal

libGDX has six basic classes to store and handle your images: lgPixmap, lgTexture, lgTextureRegion, lgSprite, lgNinePatch and lgDecal. Their Drawable variants will be seen later, in the chapter dedicated to Scene2D.

Pixmap :

A Pixmap is the same thing as a Bitmap in Basic4Android. You can create it from a file, from a byte array or from scratch. You can draw lines, circles, rectangles, points, or another Pixmap on it.
The Pixmap is stored in native heap memory and its operations are performed by the CPU. You have to call its Dispose function when it is no longer needed to prevent memory leaks.
OpenGL cannot use directly a Pixmap so a Pixmap has to be loaded to a Texture before being displayed.
Example:
B4X:
Dim myPix As lgPixmap
myPix.InitializeWithFile(lGdx.Files.Internal("background.jpg"))
myPix.SetColorRGBA(1, 0, 0.5, 1)
myPix.DrawCircle(10dip, 27dip, 32dip)
Dim myTex As lgTexture
myTex.InitializeWithPixmap(myPix)
myPix.dispose 'no longer needed

Texture :

A Texture is an image that has been decoded from its original format (e.g. JPG or PNG) and uploaded to the GPU. Contrary to the Pixmap, you cannot alter its contents.
Changing the current Texture used by OpenGL (“binding” a Texture) is a somewhat expensive operation, so you should limit the number of Textures used in a rendering.
The best practice is to load a large texture containing all images for the current screen. By using TextureRegions, you will be able to reference and draw these images individually.
Finally, call the Dispose function when the Texture is no longer needed to prevent memory leaks.

TextureRegion :

A TextureRegion describes a rectangle inside a Texture and is useful for drawing only a portion of the Texture.
Most graphical functions of the library accept (or expect) a TextureRegion.

The Split function of lgTextureRegion is commonly used with a tileset or a sprite sheet to create frames or tiles out of the region. Example:
B4X:
Dim HexRegion As lgTextureRegion
HexRegion.InitializeWithTexture(HexTexture)
Dim HexRegions(,) As lgTextureRegion = HexRegion.Split(112, 97)

Sprite :

A Sprite describes both a texture region, the geometry where it will be drawn, and the color it will be drawn. It has an origin around which rotations and scaling are performed. This origin is given relative to the bottom left corner of the Sprite and is not modified by rotation and scaling.
Because a Sprite stores the geometry and only recomputes it when necessary, it is slightly more efficient than a TextureRegion if the scale, rotation, or other properties are unchanged between frames.

NinePatch :

A NinePatch is an image with defined "stretchable" areas. With this property one can create images that scale nicely. Since the areas are pre-defined, the image won't look stretched (given that it has been created with scaling in mind).
Each area of a NinePatch is a TextureRegion.
NinePatches are mainly used by the Scene2D widgets.

Decal :

A Decal is similar to a Sprite and is created from a TextureRegion but is intended to be displayed in a 3D space. It has only two dimensions, so it is a flat 3D object. Its front and back sides are identical.

Texture atlas

As explained above for textures, it is more efficient to pack all your images in a large texture and use regions for drawing. A texture atlas is a collection of such textures (called pages).
By putting all graphical resources of your game in an atlas, you load only one file and, in the end, you can dispose all these resources by disposing the atlas. You don’t need to dispose the textures one by one.
The atlas is made of a text file and several page images. The text file holds information about the pages (file name, format, filter, etc.) and the packed images (name, original size, packed size, position, index, split, padding, etc.).

Example of use:
B4X:
Atlas.InitializeWithFile("sprites.pack")
Dim sprLogoB4A As lgSprite = Atlas.CreateSprite("b4a_logo")
Dim tarAnimatedLogo(2) As lgTextureAtlasRegion = Atlas.FindRegions2("anim_logo")

To create an atlas, I recommend using the Aurélien Ribon's tool:
TexturePacker GUI

This tool stores the images in the atlas with their file name without extension. If the file name ends with _ then a number, the underscore and the number are removed and the number is considered as the “index”. This makes it easy to pack animations without losing the order of the frames.
If the file name ends with “.9” just before the file extension, the image is processed as a nine-patch. The 1px border is removed and the split and padding information are stored in the text file.

You can also pack an atlas at runtime with the lgPixmapPacker class but this is of limited interest.

Fonts

To render a text with libGDX, you must first load a bitmap font with the lgBitmapFont class. A bitmap font is, as its name suggests, an image containing different characters (called glyphs) drawn in a specific font. Each glyph on the image is described in a file in the AngleCode BMFont text format.

You can use the Hiero tool to create these two files from a TrueType or OpenType file. To run it:
  • download the nightly build of libGDX;
  • uncompress the file in a folder of your choice;
  • run the following command in the installation folder:
    java -cp gdx.jar;gdx-natives.jar;gdx-backend-lwjgl.jar;gdx-backend-lwjgl-natives.jar;extensions\gdx-tools\gdx-tools.jar com.badlogic.gdx.tools.hiero.Hiero
You can create a bitmap font at runtime from a TrueType or OpenType file with the lgFontGenerator class but it is an expensive operation that should be avoided as much as possible.

The library embeds a default font (Arial 15). To load it, simply do:
B4X:
myFont.Initialize

Bitmap fonts usually do not scale well, so it's recommended to use an already scaled font. If you need the scaling anyway (e.g. to adjust the font size to the density of the device), you should apply a linear filter on the font texture for anti-aliasing:
B4X:
Font.SetTextureFilter(Font.FILTER_Linear, Font.FILTER_Linear)
Font.Scale(Density)
Beware: if your font is taken from a texture atlas then its texture is shared and the filter will be applied to all regions.

For static texts, you should cache the glyph geometry by using the lgBitmapFontCache class. This saves needing to compute the location of each glyph each frame. Example:
B4X:
'In the Create event:
FontCache.Initialize(Font)
FontCache.SetText("Score", 0, lGdx.Graphics.Height)
FontCache.Color = FontCache.Color.WHITE

'In the Render event:
FontCache.Draw(Batch)

MipMaps

The more a texture is rescaled to be smaller, the more the visual result and the performance may be affected. To regain a few FPS and/or to improve the visual quality, you can use mipmaps. Wikipedia definition: "[...] mipmaps are pre-calculated, optimized collections of images that accompany a main texture, intended to increase rendering speed and reduce aliasing artifacts." These images replace the original texture when a certain size is displayed (the hardware is able to interpolate between two levels) and, of course, they need extra memory (33% more).

As mipmaps are smaller versions of an original image, the latter has to be large enough for all screen resolutions. And it is also strongly recommended that it has a square size so to be compatible with the OpenGL ES driver of all devices.

The mipmaps can be generated either by the hardware or by code. To change the generation method, call the SetGenerationMethod function of the lgMipMapGenerator class. By default, it is METHOD_HARDWARE. If you want to provide your own pixmaps for the mipmap chain, set the method to METHOD_CUSTOM and add a handler for the LoadMipMap event. In this sub, return a pixmap with the width and height requested by the event. The width and height of each level are half the size of the previous level. Depending on your rescaling of the initial texture, all levels are not necessary (especially the smaller ones). In this case, return Null and the library will produce a blank pixmap for you.

To trigger the mipmap generation for a texture, call InitializeWithFile2 or InitializeWithPixmap2 with UseMipMaps = True. Then, to use the generated mipmaps, set the minification filter of your texture to one of the Filter_MipMap constants.

To trigger the mipmap generation for a texture atlas and use the generated mipmaps, set the minification filter in TexturePacker to one of the MipMap values and call any Initialize function.

The best result, but the slowest one, is achieved with FILTER_MipMap (or FILTER_MipMapLinearLinear, which is the same) and the worst but the fastest one with FILTER_MipMapNearestNearest (no interpolation between levels and no linear filtering).

Rendering

By default, the rendering thread of libGDX raises a Render event continuously, with a frequency that depends on your hardware (ideally 60 times per second). You can stop this rendering at any moment with:
B4X:
lGdx.Graphics.ContinuousRendering = False
and re-enables it with:
B4X:
lGdx.Graphics.ContinuousRendering = True

When the rendering is non-continuous, the following events will trigger a redraw:
  • a call to Graphics.RequestRendering;
  • input events from the touch screen or keyboard;
  • a call to CallSubUI.
To draw in the Render event, you have to use a renderer. This renderer will batch the drawing commands and optimize them for processing by the GPU.
There are eight renderers:
  • lgSpriteBatch to draw your fonts, textures, sprites and regions;
  • lgPolygonSpriteBatch to draw 2D polygons;
  • lgDecalBatch to draw decals;
  • lgShapeRenderer to render points, lines, circles, rectangles, cones, etc.
  • lgBox2DDebugRenderer (see the Box2D chapter);
  • lgMapHexagonalTiledMapRenderer (see the Maps chapter);
  • lgMapIsometricTiledMapRenderer (see the Maps chapter);
  • lgMapOrthogonalTiledMapRenderer (see the Maps chapter).
Note : before rendering, you have to clear the screen. The following lines should always be first in your Render event:
B4X:
lGdx_GL.glClearColor(0, 0, 0, 1) 'Black background
lGdx_GL.glClear(lGdx_GL.GL10_COLOR_BUFFER_BIT)

All renderers need to be disposed of when no longer needed.

SpriteBatch

The lgSpriteBatch class is used to draw 2D rectangles that reference a texture or a texture region. As it batches the drawing commands, you have to first call the Begin function which will setup appropriate render states and, when you are done with drawing, call End which will actually draw the things you specified.

By default, a SpriteBatch is limited to 1000 rectangles and operates in screen coordinates. You can modify its size limit with Initialize2 and use the coordinate system of the camera by setting the projection matrix of the SpriteBatch to the combined matrices of the camera. Example:
B4X:
Camera.Update
Batch.ProjectionMatrix = Camera.Combined
'Position and size are now in the coordinate system of the camera
Batch.Begin
Batch.DrawTex2(texBottle, 2, 2, 0.2, 0.5)
Batch.End

Some classes require a SpriteBatch to draw their texture region (lgSprite or lgBitmapFont for example) so their drawing commands must be inserted between the Begin and End of the SpriteBatch. Example:
B4X:
Batch.Begin
mySprite.Draw(Batch)
myFont.Draw(Batch, "FPS:" & lGdx.Graphics.FramesPerSecond, 8dip, 10dip)
Batch.End

A SpriteBatch is a pretty heavy object so you should only ever have one in your program.
Call its Dispose function when you no longer need it.

PolygonSpriteBatch

The lgPolygonSpriteBatch class is used to draw 2D polygons. The polygon shapes are defined by the lgPolygonRegion class on top of a texture region. As they minimize the number of pixels to render and the number of transparent pixels to blend, they make the PolygonSpriteBatch a better choice than the SpriteBatch for images with a lot of whitespace.
On a Nexus 7 with JellyBean, the Perf_PolyTree demo runs at 60 fps with 345 trees when a PolygonSpriteBatch is used, while it can’t go faster than 30 fps with a SpriteBatch.

To construct your polygon regions, don’t bother with an array of vertices; use the Aurélien Ribon’s graphical tool:
Polygon Editor

Example of a .psh file applied to a texture:
B4X:
Dim texTree As lgTexture
texTree.Initialize("tree.png")
Dim regionTree As lgTextureRegion
regionTree.InitializeWithTexture(texTree)
Dim polyTree As lgPolygonRegion
polyTree.Initialize(regionTree, lGdx.Files.Internal("tree.psh"))

As the PolygonSpriteBatch batches the drawing commands, you have to first call the Begin function which will setup appropriate render states and, when you are done with drawing, call End which will actually draw the things you specified.
Example:
B4X:
PolyBatch.Begin
PolyBatch.DrawRegion(polyTree, 15dip, 10dip)
polySprite.Draw(Batch)
PolyBatch.End

A PolygonSpriteBatch is a pretty heavy object so you should only ever have one in your program.
Call its Dispose function when you no longer need it.

ShapeRenderer

The lgShapeRenderer class is used to draw points, lines, rectangles, filled rectangles, circles, ellipses, etc. As it batches the drawing commands, you have to first call the Begin function which will setup appropriate render states and, when you are done with drawing, call End which will actually draw the things you specified.
The parameter of the Begin function defines the type of rendering (line, filled, point). It expects one of the SHAPETYPE constants. If you want to draw an empty rectangle then a filled rectangle, for example, you will have to render them in different batches:
B4X:
ShapeRdr.Begin(ShapeRdr.SHAPETYPE_Line)
ShapeRdr.Rect(0, 0, 50dip, 50dip)
ShapeRdr.End
ShapeRdr.Begin(ShapeRdr.SHAPETYPE_Filled)
ShapeRdr.Rect(0, 100dip, 50dip, 30dip)
ShapeRdr.End

By default, a ShapeRenderer operates in screen coordinates. You can use the coordinate system of the camera by setting the projection matrix of the ShapeRenderer to the combined matrices of the camera. Example:
B4X:
Camera.Update
ShapeRdr.ProjectionMatrix = Camera.Combined
'Position and size are now in the coordinate system of the camera
ShapeRdr.Begin(ShapeRdr.SHAPETYPE_Line)
ShapeRdr.Rect(0.3, 0.3, 0.5, 0.6)
ShapeRdr.End

Don't look for a stroke width parameter; there's none. Use a For loop to repeat the drawing with different parameters and make the lines thicker.

Call the Dispose function of the ShapeRenderer when you no longer need it.

.....
 
Last edited:

Informatix

Expert
Licensed User
Longtime User
Maps

libGDX can manage and draw different kinds of tiled maps: orthogonal (with square or rectangle tiles), isometric (fake 3D, with diamond tiles) and hexagonal.

Maps can be imported in the TMX or tIDE format, or constructed from a collection of texture regions (see the provided Map_Hexagonal demo).

I suggest using Tiled or tIDE to create and edit your maps.

It is also possible to create a texture atlas from an existing map with the TiledMapPacker tool. I recommend using it when you have visual issues while zooming or rescaling the map as it duplicates the edges of your tiles. To create the atlas:
  • download the nightly build of libGDX;
  • uncompress the file in a folder of your choice;
  • run the following command in the installation folder:
    java -cp gdx.jar;gdx-natives.jar;gdx-backend-lwjgl.jar;gdx-backend-lwjgl-natives.jar;extensions\gdx-tools\gdx-tools.jar;extensions\gdx-tiled-preprocessor\gdx-tiled-preprocessor.jar com.badlogic.gdx.tiledmappacker.TiledMapPacker %1 %2 %3
    %1 = input folder
    %2 = output folder (optional)
    %3 = --stripe-unused (optional)
How to load a map (TMX format):
B4X:
Dim TMXLoader As lgMapTmxMapLoader
Dim Maps As lgMapTiledMap
Maps = TMXLoader.Initialize2("maps/MyMap.tmx")
Replace lgMapTmxMapLoader by lgMapAtlasTmxMapLoader or lgMaptIDEMapLoader for the other formats.

The lgMapTiledMap class gives access to the layers, properties and tilesets of the map.

The layers and the tilesets are ordered and indexed, starting by index 0. Example of access to the last layer:
B4X:
Dim LastLayer As lgMapTiledMapLayer
LastLayer = Maps.Layers.Get(Maps.Layers.Count - 1)

The properties are stored and retrieved by name. Example:
B4X:
Dim TileDoorX As Int = LastLayer.Properties.Get("doorX")

Maps use special renderers that rely upon SpriteBatch: lgMapHexagonalTiledMapRenderer, lgMapIsometricTiledMapRenderer and lgMapOrthogonalTiledMapRenderer. They are initialized with the map (lgMapTiledMap) as the main parameter and are very simple to use:
B4X:
MapRenderer.SetCameraView(Camera)
MapRenderer.Render
They can render a selected set of layers (Render2) or a specific layer (RenderTileLayer).

Call the Dispose function of the map and of its renderer when you no longer need them.

Particles

Particles are small graphics objects used in large number to simulate certain kinds of "fuzzy" phenomena, which are otherwise very hard to reproduce with conventional rendering techniques, e.g. fire, explosions, smoke, moving water, clouds, fog, snow, glowing trails, magic spells, etc.

Particles are created with the lgParticleEmitter class. The emitter has many properties that control how each particle behaves: life, velocity, rotation, scale, etc. You can save all these settings to a file with the Save function and reload them with the Load or Load2 function.

Creating a particle emitter from scratch is rather difficult, so I recommend using the Particle Editor, especially since it allows combining multiple emitters to create a complex effect. To run it:
  • download the nightly build of libGDX;
  • uncompress the file in a folder of your choice;
  • run the following command in the installation folder:
    java -cp gdx.jar;gdx-natives.jar;gdx-backend-lwjgl.jar;gdx-backend-lwjgl-natives.jar;extensions\gdx-tools\gdx-tools.jar com.badlogic.gdx.tools.particleeditor.ParticleEditor
particle-editor.png

Online documentation for this tool.

If the file produced by the editor contains more than one emitter, the Load function of the lgParticleEmitter class will load only the first. To load the particle effect, i.e. the complete set of particles emitters, use one of the Load functions of the lgParticleEffect class.

Once loaded, the particle effect has to be stated as ready with the Start function. Although this does not seem necessary in some cases, it is a good habit to take.

The lgParticleEmitter and lgParticleEffect classes render their particles with the Draw function. This function must be inserted between the Begin and End of a SpriteBatch. Since, basically, particle emissions are animations, an emitter needs to know the elapsed time between each frame. Thus, before calling Draw, call the Update function. Or use Draw2 that does the Update and the Draw at the same time.

If you draw repeatedly the same particle effect, the lgParticleEffectPool class provides you an efficient and convenient way of reusing the created instances. With a pool, you can minimize the number of memory allocations/deallocations and avoid triggering the garbage collector too often. You can also limit the number of effects at the same time (the capacity of the pool will not exceed the maximum that you specified).
To learn how to use a pool, see the ParticlesPool demo. The Free function indicates that an instance can be reused, and the Obtain function gets the first unused instance.

The particle effect and the particle effect pool have to be disposed of when they are no longer needed.

Scene2D

Scene2D is a scene graph using a hierarchy of actors. It has a two-way event system and a set of widgets for menus, HUD overlays, dialogs, touchpads, and other Uis.
It makes the creation of games easier and is recommended for beginners. It may seem complex at start because of all the possibilities and classes, but don't be put off by that and try to understand the major principles.

Scene2D has three classes at its core:
The lgScn2DStage class is used to create the stage, i.e. the place where the actors are drawn and can receive input events. It's the root of the hierarchy. It has a camera (lgOrthographicCamera) to define a viewport, a renderer (lgSpriteBatch) to draw the actors and an input processor. It is recommended to have only one stage per application.
The lgScn2DActor class is used to create the actors, i.e. the graphic objects that will take place on the stage. An actor has a position, a rectangular size, an origin, a scale, a rotation angle, and a color.
The lgScn2DGroup class is used to create groups of actors. It allows to do group actions (group movement for example) or group transformations. The stage contains already a group named Root which is the main group.

Stage:

The stage is initialized in the Create event:
B4X:
Stage.Initialize("ST")
In this example, ST is the prefix of the Act and Draw events and the default settings are used: the stage has a viewport equal to the device screen resolution and uses its own SpriteBatch, which will be disposed when the stage is disposed.
It is possible to define another viewport or reuse an existing SpriteBatch with the other Initialize functions.

To add an actor or a group to the stage, use the AddActor function. To remove an actor or a group, call RemoveActor.

To perform the actions attached to actors, call Act in the Render event.

To draw actors, call Draw in the Render event.

Typically, your Render event will look like this:
B4X:
'Clears the screen
GL.glClear(GL.GL10_COLOR_BUFFER_BIT)

'Runs AI, computes moves and resolves collisions
MyUpdateFunction

'Applies the actions to actors (if you use actions)
Stage.Act

'Draws the actors
Stage.Draw

The stage has to be disposed of when it is no longer needed (all resources used internally by actors will be disposed too).

Actors:

An actor can be created and initialized at any time. It will not be drawn until it is added to the stage. Example:
B4X:
Dim Elf As lgScn2DActor
Elf.Initialize("Elf")
Elf.Name = "Elf"
Elf.X = 15dip
Elf.Y = 10dip
Elf.Height = 65dip
Elf.Width = 50dip
Stage.AddActor(Elf)

Each actor has an Act and a Draw event, raised by a call to the Act and Draw functions. These functions should be called by their parent, and usually they are called at the stage level (the root group being the parent of all actors). Draw does nothing by default (you have to draw yourself the actor in the event); Act updates and applies the actions attached to the actor (see the Actions section below).

If your actor is an image, you should use the lgScn2DImage class instead of the generic lgScn2DActor class. This way, you won’t have to draw the image in the Draw event. That will be done automatically.

When you want to delete permanently an actor (and not just remove it from the stage), set it to Null.

To see the bounds of an actor, you can use the lgScn2DDebugRenderer class. Once the class is initialized, call the Render function of the renderer in the Render event. You can toggle this rendering for each actor with the DebuggingEnabled property.

Event system:

All groups and actors can receive input events via listeners. These listeners can be added as capture listeners (AddCaptureListener) or as regular listeners (AddListener). In the capture phase, events are propagated from the root down to the deepest actor in the hierarchy, which allows parents to block events before they reach their child actors. After the capture phase, events are sent directly to their target, and if not stopped or cancelled, are propagated in the reverse order of the capture phase: from the targeted actor up to the root. It’s the regular phase.

With the Event parameter, the event handler can limit the propagation of the event:

In the capture phase:

If, in the event handler of a group…
  • You do nothing…
    The target and all intermediate groups will get the event.
    The application will get the event.​
  • You call Event.Cancel…
    The target and all intermediate groups will not see the event.
    The application will not see the event.​
  • You call Event.Stop…
    The target and all intermediate groups will not see the event.
    The application will get the event.​
  • You call Event.Handle…
    The target and all intermediate groups will get the event.
    The application will not see the event.​
In the regular phase:

If, in the event handler of the targeted actor…
  • You do nothing…
    Its parent groups will get the event.
    The application will get the event.​
  • You set Event.Bubbles to false…
    Its parent groups will not see the event.
    The application will get the event.​
  • You call Event.Cancel…
    Its parent groups will not see the event.
    The application will not see the event.​
  • You call Event.Stop…
    Its parent groups will not see the event.
    The application will get the event.​
  • You call Event.Handle…
    Its parent groups will get the event.
    The application will not see the event.​
These two tables suppose that the input processor of the application was declared after the initialization of the stage. If it is declared before, it will intercept all events.

The value of Bubbles is ignored in the capture phase.

In a TouchDown event handler, you must call Event.Handle if you want to fire the TouchDragged and TouchUp events that follow.

Example of event handler:
B4X:
Sub Elf_Click(Event As lgScn2DInputEvent, X As Float, Y As Float)
    Event.Target.Remove
    Event.Stop
End Sub
In this example, the Click event is fired when the user touches the screen and lifts up his finger in the same area. The Event parameter is used to remove the actor targeted by the click (the topmost actor under the finger). Then the propagation is stopped, so no other actor or group (including the root group of the stage) will see this event.

List of available listeners:
  • lgScn2DInputListener: for keyboard and touch events
  • lgScn2DClickListener: for clicks detection
  • lgScn2DGestureListener: for gestures detection (pan, zoom, pinch, fling, etc.)
If you want to delegate an event to another actor, look at the Fire and Hit functions.

An actor not visible, not touchable or not on stage cannot receive input events.

Actions:

Each actor may have a list of actions. These actions are added with AddAction and are removed automatically when they are complete. They cover most needs (move, rotate, resize, rescale, show/hide, change alpha, change color...) and can be run at the same time or in sequence. The lgScn2DActions class provides the complete list of actions.

Examples:
B4X:
Dim Actions As lgScn2DActions

'Will move instantly the actor 10dips to the right
Ogre(0).AddAction(Actions.MoveBy(10dip, 0))

'Will take 5 seconds to move the actor to the bottom left corner
Ogre(1).AddAction(Actions.MoveTo2(0, 0, 5))

'Will hide immediately the actor, then will wait for one second before showing it again
Ogre(2).AddAction(Actions.Sequence2(Actions.Hide, Actions.Delay2(1, Actions.Show)))

Actions are performed when the Act function is called.

Widgets:

A widget is an actor used to build UIs which draws itself and provides a minimum, preferred, and maximum size for dynamic layout. It is similar to the standard views of Basic4Android (Label, EditText, Button, Spinner, etc.).

Most widgets have their appearance defined by a Style (lgScn2DButtonStyle, lgScn2DLabelStyle, lgScn2DWindowStyle, etc.). This style may require images called Drawables, which are variants of the basic image types: lgScn2DNinePatchDrawable for nine-patches, lgScn2DSpriteDrawable for sprites, and lgScn2DTextureRegionDrawable for texture regions. There is a fourth type, based on lgScn2DTextureRegionDrawable: lgScn2DTiledDrawable, which is convenient to repeatedly fill an area instead of stretching the image.

List of widgets (WG indicates a widget group, i.e. a widget that can contain other widgets):
  • lgScn2DButton (WG) is an empty Table with a checked state that is toggled each time the Button is clicked. Typically, Images or Labels are added to this widget.
  • lgScn2DImage simply displays a Drawable.
  • lgScn2DLabel displays a text using a bitmap font and a color. The text may contain newlines (CRLF).
  • lgScn2DList is a list box that displays textual items and highlights the selected item. A List does not scroll on its own and is often put in a ScrollPane.
  • lgScn2DProgressBar is a horizontal or vertical bar intended to show a progression.
  • lgScn2DScrollPane (WG) scrolls a child widget using scrollbars and/or touch dragging. Scrolling is automatically enabled when the widget is larger than the ScrollPane.
  • lgScn2DSelectBox is a drop-down list that displays only the selected value when inactive, and shows the list of values that may be selected when activated.
  • lgScn2DSlider is a horizontal or vertical indicator that allows a user to set a value.
  • lgScn2DSplitPane (WG) contains two widgets and is divided in two either horizontally or vertically. The user may resize the widgets with a draggable splitter.
  • lgScn2DTable (WG) is a widget group that sizes and positions its children using a logical table, similar to HTML tables.
  • lgScn2DTextButton (WG) is a Button containing a Label.
  • lgScn2DTextField is a single line text entry field, with an optional password mode.
  • lgScn2DTouchpad is an onscreen joystick that moves in a circular area.
  • lgScn2DWindow (WG) is a Table with an area above the contents that displays a title and allows to move the whole. The window can optionally act as a modal dialog, preventing touch events to widgets below.
You can build new widgets by adding widgets to a widget group. Here's an example of “checkbox”:
B4X:
Sub Globals
    …

    Dim trdCheckBox(2) As lgScn2DTextureRegionDrawable
    Dim imgCheckBox As lgScn2DImage
End Sub

Sub LG_Create
    …

    'Gets the checked and unchecked drawables from a texture atlas
    trdCheckBox(0) = Atlas.CreateRegionDrawable("unchecked")
    trdCheckBox(1) = Atlas.CreateRegionDrawable("checked")

    'Sets the minimum size of the state drawables
    For i = 0 To 1
        trdCheckBox(i).MinHeight = 40dip
        trdCheckBox(i).MinWidth = 40dip
    Next

    'Creates an image widget to display one of the state drawables
    imgCheckBox.Initialize("")
    imgCheckBox.Drawable = trdCheckBox(0) 'Unchecked by default

    'Gets the font for the button label
    Dim AtlasRegion As lgTextureAtlasRegion = Atlas.FindRegion("arial22")
    Font.Initialize4(lGdx.Files.internal("font/arial22.fnt"), AtlasRegion)
    Font.Scale(Density)

    'Creates a transparent style for the button (no background)
    Dim stylButton As lgScn2DButtonStyle
    stylButton.Initialize(Null, Null)

    'Builds the "checkbox" button (image+label) and adds it to the stage
    Dim btnCheckBox As lgScn2DButton
    btnCheckBox.Initialize(stylButton, "btnCheckBox")
    btnCheckBox.AddActor(imgCheckBox)
    btnCheckBox.AddLabel2("Check me", Font, Font.Color.WHITE).SpaceLeft = 10dip
    btnCheckBox.Pack 'Adjusts the size of the button to its contents
    Stage.AddActor(btnCheckBox)
End Sub

Sub btnCheckBox_Click(CheckedState As Boolean)
    'Selects the appropriate drawable for the checked state
    If CheckedState Then
        imgCheckBox.Drawable = trdCheckBox(1) 'Checked
    Else
        imgCheckBox.Drawable = trdCheckBox(0) 'Unchecked
    End If
End Sub

Tables are intended to be used extensively to layout widgets, as they are easy to use and much more powerful than manually sizing and positioning widgets.
They are made of cells (lgScn2DTableCell) which have their own properties. To create cells in the same row, one after the other, use the AddActor function (with a specified actor/widget) or the AddCell function (to let the cell empty). To start a new row, call NewRow. Once added, the cells cannot be reordered.

I recommend to add a Table as the main child of the root group, and to create everything else inside this Table. This will facilitate the layout of your game screen and will make it more dynamic.
Example (in the Create event):
B4X:
Stage.Initialize("Stage")
Table.Initialize("RootTable")
Table.FillParent = True
Stage.AddActor(Table)

More information on Tables.

There are two classes intended to be used by widgets: lgScn2DButtonGroup to make “radio” buttons and lgScn2DStack to stack widgets on top of each other.

To rotate (rotateBy, Rotation) or scale (ScaleX, ScaleX, setScale) a widget group and apply this transformation to the children, you have to set the Transform property of the group to True.

Drag & Drop:

The lgScn2DDragAndDrop class can manage drag and drop operations through registered drag sources and drop targets.
Example:
B4X:
DragAndDrop.Initialize
DragAndDrop.AddSource(mySource, "Src")
DragAndDrop.AddTarget(myTarget, "Tgt")

The source will receive two events:
SrcDragStart: the user started dragging the source. You have to return a “payload” (lgScn2DDragAndDropPayload), i.e. a drag actor that will show where the source is going to be dropped. That can be the source or another actor. You can display two different payloads according to the drop position (valid/invalid). At the end of the drag, the payload will be removed from the stage.
SrcDragStop: the user dropped the source. DropTarget contains the drop target or Null if the drop position is invalid. If you used the source as payload, you can replace it on stage, at its original position.

The target will receive three events:
TgtDrag: the source is dragged over the target. You have to return True or False to indicate whether the source is allowed to be dropped here.
TgtReset: the source is no longer over the target. You can reset any changes you made in the TgtDrag event.
TgtDrop: the source has been dropped on this target.

Box2D

There are many excellent tutorials about Box2D on Internet (those of iforce2d for example), so I don’t think it’s useful to cover again this topic. The differences with the original version in C++ are not fundamentals.

If you want a version of Box2D with more features (but a lot slower), you may give a try to another library for B4A: JBox2D.

In libGDX, the main class is lgBox2DWorld.

The lgBox2DBodyEditorLoader class allows to load shapes created with the Aurélien Ribon’s Physics Body Editor.

The lgBox2DDebugRenderer class is useful to make visible the bodies, joints, bounding boxes, inactive bodies, velocity vectors and/or contact points. Its Render function takes two parameters: the unwrapped object of your lgBox2DWorld instance and the combined matrices of your camera. Example:
B4X:
Renderer.Render(World.InternalObject, Camera.Combined)

The lgBox2DParticleEmitter class uses ray casting to achieve continuous collision detection against fixtures. If a particle detects collision, it changes its direction before the actual collision would occur. Velocity is 100% reflected. These particles cannot collide to other particles. This is useful to contain an effect between the boundaries of a container. E.g. the flames of a fire in a hallway are not supposed to cross the walls.

Note: The general rule of thumb for Box2D is to use a fixed time step and meters as unit.

The world, the shapes and the debug renderer have to be disposed of when no longer needed.

.....
 
Last edited:

Informatix

Expert
Licensed User
Longtime User
Audio

libGDX provides classes to playback small sound effects (lgSound) as well as stream larger music pieces (lgMusic) directly from disk. It also provides convenient read and write access to the audio hardware to record (lgAudioRecorder) and play (lgAudioDevice) PCM data.

Access to the audio facilities is done through the audio interface. Examples:
B4X:
Dim myMusic As lgMusic = lGdx.Audio.NewMusic("Bullet the blue sky.mp3")
Dim mySound As lgSound = lGdx.Audio.NewSound("Gunshot.ogg")
Dim myRecording As lgAudioRecorder = lGdx.Audio.NewAudioRecorder(44100, True)
Dim myPlayback As lgAudioDevice = lGdx.Audio.NewAudioDevice(44100, True)

The sound effects played by lgSound cannot be longer than a few seconds. Their audio data is retrieved from MP3, OGG or WAV files and is loaded entirely into RAM (max. 1 MB).
You can change the panning, the pitch and the volume of sounds.

For any sound that's longer than a few seconds it is preferable to stream it from disk with the lgMusic class. The accepted file formats are MP3, OGG and WAV.
You can change the panning and the volume of music.

To record audio data, use the Read function of the lgAudioRecorder class, and to listen your recordings, use the WriteSamples function of the lgAudioDevice class. The function names may seem erroneous; they’re not. E.g. WriteSamples write PCM samples to the audio hardware, so the hardware can play them.
The samples are written and read as 16-bit signed (short) PCM.
Example of recording:
B4X:
Dim Samples(1024 * 100) As Short
Rec = lGdx.Audio.NewAudioRecorder(44100, True) '44.1 khz, mono
Rec.Read(Samples, 0, Samples.Length)

libGDX will automatically pause and resume all audio playback for you if your application is paused and resumed.

All audio resources have to be disposed of when they are no longer used.

File handling

Many functions require a file handle (lgFileHandle) to load a file. To obtain it, use the Files interface. Example:
B4X:
Effect.Load(lGdx.Files.Internal("particles/particles.p"), lGdx.Files.Internal("particles"))

A file handle has a type which defines where the file is located:
  • Absolute: the specified path is the fully qualified path to the file. You should use it only when absolutely necessary.
  • External: the specified path is relative to the SD card root.
  • Internal: the specified path is relative to the assets directory. Internal files are packaged with your application and are read-only.
  • Local: the specified path is relative to the internal (private) storage of the application. If you need to write small files, e.g. the game state, or want to be sure that a file cannot be deleted by users, use local files. For big files, e.g. screenshots, prefer the external storage.
The lgFileHandle class can perform all operations on files: move, copy, read, write, delete, etc.

Asset Manager

If your game is very simple, and loading resources doesn't take a lot of time, you don't want to use the Asset Manager. In all other cases I'd recommend using it due to the following nice behaviours:
  • Loading of resources is done asynchronously, so you can display a reactive loading screen while things load;
  • Assets are automatically managed (they are reloaded in case of a context loss);
  • You have a single place to store all your assets. Calling the Dispose function of the manager will dispose all your assets.
You can load and manage the following resource types:
  • Bitmap font
  • Music
  • Particle effect
  • Pixmap
  • Polygon region
  • Sound
  • Texture
  • Texture atlas
  • Tiled map
The first thing to do is to add the resources locations and types to the loading queue with the Load function, preferably in the Create event. Example:
B4X:
AssetMgr.Initialize("AM")
AssetMgr.Load("font/arial22.fnt", AssetMgr.TYPE_BitmapFont)
AssetMgr.Load("audio/main_theme.mp3", AssetMgr.TYPE_Music)
AssetMgr.TiledMapLoader = AssetMgr.MAPLOADER_tIDE
AssetMgr.Load("maps/tide/map_lvl1.tide", AssetMgr.TYPE_TiledMap)
As done in this example, you have to declare the type of TiledMap loader before queuing the asset. You cannot mix different map loaders in the same Asset Manager.

The loading is done asynchronously in the Render event with the Update function. This function returns False when the loading is finished. Example:
B4X:
If AssetMgr.Update Then
    Show_Progression(AssetMgr.Progress * 100)
    Return
End If

To access the loaded resources, call the Get function with the internal file path of the asset. Example:
B4X:
Dim myFont As lgBitmapFont = AssetMgr.Get("font/arial22.fnt")
Dim myMusic As lgMusic = AssetMgr.Get("audio/main_theme.mp3")
Dim myAtlas As lgTextureAtlas = AssetMgr.Get("atlas/atlas.pack")

To get the list of loaded resources, use the LoadedAssetNames function. If the manager fails to load a resource, you can get details about the error in the Error event.

When you no longer use one of the assets, dispose it with Unload. Or dispose all managed resources at the end by calling Dispose.

Networking

The networking functions of this version of libGDX have been limited to direct connections via sockets because you will find better alternatives among the B4A classes and libraries. Note that lgSocket and lgServerSocket offer the same socket service as the Network library, but with more settings.

Look at the Sockets demo to see a concrete example of exchange between a client and a server.

Math utilities

The lgMath classes are useful for dealing with problems in geometry, linear algebra, collision detection, interpolation, and common unit conversions.

Among all these classes, you will probably use lgMathVector2 to create a pair of coordinates and lgMathUtils for its many useful functions (random, clamp, cos and sin from lookup tables, fast atan2, etc.). To convert radians to degrees, or the contrary, with lgMathUtils, you have to multiply your result by the appropriate constant. Example:
B4X:
MySprite.Rotation = MyBody.Angle * MU.RadiansToDegrees

Another very useful class is lgMathInterpolation. You use it by selecting an interpolator and calling Apply to return the interpolated value for the specified linear value (between 0 and 1). Example:
B4X:
Dim Interpolation As lgMathInterpolation
Interpolation = Interpolation.Elastic
Dim myFirstInterpolatedValue As Float = Interpolation.Apply(0)
Dim myLastInterpolatedValue As Float = Interpolation.Apply(1)
Interpolators are commonly used to change the rate of an animation. You can set one to accelerate or decelerate a movement, for example, or simulate a rebound. Many actions of Scene2D can be parameterized with an interpolator.

If you don't plan to use Box2D for your collision detection, you will find all what you need in the lgMath classes: lgMathBoundingBox, lgMathCircle, lgMathPlane, lgMathPolygon, lgMathRay, etc. to define the type, position and size of objects, and lgMathIntersector to compute the distance between them and the intersection point, if any.

The lgMathCatmullRomSpline class is very interesting to build a curved shape or path that passes through all the given points.

Live wallpapers

To create a Live Wallpaper, I recommend modifying the provided template. If you want to create it from scratch, add this to the manifest:
B4X:
AddApplicationText(
<!-- ******** Add the internal service declaration - you can change android:label  ******* -->
<service
        android:label="My Live Wallpaper"
        android:name="anywheresoftware.b4a.libgdx.lgLiveWallpaper"
        android:permission="android.permission.BIND_WALLPAPER">
        <intent-filter>
            <action android:name="android.service.wallpaper.WallpaperService" />
        </intent-filter>
        <meta-data android:name="android.service.wallpaper" android:resource="@xml/wallpaper" />
</service>
<!-- End of internal service declaration -->
)
Add also the file “wallpaper.xml” in Objects\res\xml:
B4X:
<?xml version="1.0" encoding="utf-8"?>
<wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
  android:thumbnail="@drawable/icon"
/>

The service of the wallpaper must be named WallpaperService.

The wallpaper needs to be initialized with lgLiveWallpaper.Initialize when the service is created or started. The lgLiveWallpaper class is the class that replaces the LibGDX class for wallpapers. You can use it in a similar way.

The life-cycle of a wallpaper is very close to the application life-cycle. However, the service is not restarted after a rotation (the Resume event is raised instead) and it is not unlikely to see many Resize events in a row.

Note: Service_Destroy is never called by libGDX.

The lgInputProcessor class, the lgGestureDetector class and the input listeners of Scene2D cannot be used in a wallpaper service. To detect and handle a touch event, use the lgInput functions. Example:
B4X:
If LW.Input.JustTouched Then
    touchX = LW.Input.X
    touchY = LW.Input.Y
End If

Classes to dispose

The following classes need to be disposed of:
  • lgAssetManager
  • lgAsyncExecutor
  • lgAudio
  • lgAudioDevice
  • lgAudioRecorder
  • lgBitmapFont
  • lgBox2DDebugRenderer
  • lgBox2DShape
  • lgBox2DWorld
  • lgCameraGroupStrategy
  • lgDecalBatch
  • lgFrameBuffer
  • lgMapHexagonalTiledMapRenderer
  • lgMapIsometricStaggeredTiledMapRenderer
  • lgMapIsometricTiledMapRenderer
  • lgMapOrthogonalTiledMapRenderer
  • lgMapTiledMap
  • lgMesh
  • lgMusic
  • lgParticleEffect
  • lgParticleEffectPool
  • lgPixmap
  • lgPixmapPacker
  • lgPolygonSpriteBatch
  • lgScn2DStage
  • lgServerSocket
  • lgShaderProgram
  • lgShapeRenderer
  • lgSocket
  • lgSound
  • lgSpriteBatch
  • lgTexture
  • lgTextureAtlas
Ready-to-use templates

libGDX is provided with six templates: _Template, _TemplateInput, _TemplateInputGD, _TemplateScene2D, _TemplateScene2DTable and _TemplateLiveWallpaperTouch. These templates implement the minimal code required to run your game with libGDX.

Further reading

You will find many tutorials for libGDX on Internet. They are made for Java developers, and sometimes for another OS as the original library is cross-platform, but they are still useful to understand how to use the library at its best. Converting the Java code to Basic4Android should not be complicated because I did not change the name of 99% of functions. The main difference is for most Get and Set functions that you will find without the Get/Set prefix in the B4A version.
The first place to go and the first thing to read is the official developer's guide.
The forum is also a valuable source of information, but keep in mind that people there are not Basic4Android users.

-END-
 
Last edited:

Tom Christman

Active Member
Licensed User
Longtime User
Infomatrix, I'm working with ShaderProgram_Light example you provided in the Code Examples Section, and have a question concerning the section Titled "Compile the Shader Program". in the B4A code listing.
B4X:
Shader.Pedantic = False
    Shader.InitializeWithFiles(lGdx.Files.Internal("shaderprog/vertex.txt"), _
                              lGdx.Files.Internal("shaderprog/fragment.txt"))
Where is a description for generating these lines of code. I've looked at the Shader lesson description and the LibDX Port of the Shader Lesson6 and can't seem to find anything regarding these txt files.
Tom
 

Informatix

Expert
Licensed User
Longtime User
Shader programs are reserved to experts and are programmed in GLSL. If you don't know what the vertex shader and the fragment shader are, then stay away from that until you fully understand what you do. My first intent was to not include the lgShaderProgram class because it's only for experts (and that could be done with the lgGL20 class). So I won't provide any tutorial or advice about it.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi Fred,

I want to load the background with an image in Live wallpaper Template. I was using Engine.Canvas.DrawBitmap before. How to achieve the same thing here. Also there will be user text on the image.

Kindly let me know.

Regards,
SK
 

Informatix

Expert
Licensed User
Longtime User
Hi Fred,

I want to load the background with an image in Live wallpaper Template. I was using Engine.Canvas.DrawBitmap before. How to achieve the same thing here. Also there will be user text on the image.
There are plenty of demos provided with the library (including a wallpaper example). Please look at them. There's no background in LibGDX. What you put in the background is an image (texture, sprite, region...) as any other image.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi Fred,

I tried with Texture,Region and sprite but i am not able to set the background to an image. Getting Force Close.

B4X:
Sub LG_Create
Batch.Initialize
Texture.Initialize("candle1.jpg")
End Sub

Sub LG_Render
Batch.Begin
Batch.DrawTex2(Texture,0,0,LW.Graphics.Width, LW.Graphics.Height)
Batch.End
End Sub

What is the mistake i am making here.

Regards,
SK
 

Informatix

Expert
Licensed User
Longtime User
Hi Fred,

I tried with Texture,Region and sprite but i am not able to set the background to an image. Getting Force Close.

B4X:
Sub LG_Create
Batch.Initialize
Texture.Initialize("candle1.jpg")
End Sub

Sub LG_Render
Batch.Begin
Batch.DrawTex2(Texture,0,0,LW.Graphics.Width, LW.Graphics.Height)
Batch.End
End Sub

What is the mistake i am making here.

Regards,
SK
If you're not using OpenGL 2 or a device compatible with OpenGL 2, your size of texture has to be a power of two. Please read the chapter about Textures above.
 

shashkiranr

Active Member
Licensed User
Longtime User
Fred I am using Note 2 v4.3 and it supports OpenGL 2 . I referred the lGdx_Perf_Skaters ,the way the background is set. But not able to use it in Livewallpaper.
 

shashkiranr

Active Member
Licensed User
Longtime User
Hi Fred,

Thank you..!!

Added this line
B4X:
Config.useGL20 = True
and it worked :)

One Question - What about devices which does not support OpenGL 2 ? For all those devices cant i set the background image?

Regards,
SK
 
Top