Mobile Tutorial Series (LibGDX & MTX)——第一部分
本系列教程来自MTX(MoribitoTechX)的Tutorial Blog: http://moribitotechx.blogspot.co.uk/
因需科学上网才能访问,且该博客5年多没有更新了(最后更新时间2013.7.27),故这里手打上来留一备份。因为比较长,分成两部分:第二部分
项目地址:https://github.com/moribitotech/MTX
# Series 1 (Introduction to MTX with LibGDX Scene2D) In this series I will talk about Mini-MTX framework which built on LibGDX Scene2D. This is a mandatory series, if you want to continue other series. I will talk about the structure of MTX, screen systems, advanced actors, game specific buttons, animations and cool effects and so on.
1.1 Introduction
Welcome all!!!
If you want to develop games, you are on the right place. If you started to work on LibGDX Game Framework and want to continue with it, Compact-MTX framework may help. It is %100 built on LibGDX Scene2D and it makes many things easier for you. More about MTX is here. If you like LibGDX Scene2D and do not need to rely on MVC patterns so much, MTX could be right choise for you.
Note:
I am also fairly new to LibGDX, some of the things may exist in LibGDX already, however it is always good to practice and improve yourself. It may be bugs, errors or stupid duplicated annoying codes please let me know, I try to fix :). In tutorial series first I will explain MTX, then I will dive into little game development.
Example:
I have completed this game in three weeks on my spare times by the help of LibGDX and MTX. It was pretty easy and straight forward.
Puzzle Slide

Game tested on:
Google Nexus 7
Samsung Galaxy SII
Samsung Galaxy Ace
HTC Desire S
HTC Evo 3D
Minipad Tabtech
Great performance and no crash report since its release on many markets not just Google Play.
1.2 Tutorial Structures & Project
1.3 Test1_AbstractScreen
Hello there!
I assume you downloaded the project files (MtxFramework2, MtxFramework2-android, MtxFramework2-desktop) and imported to eclipse.
We create our screen and extend to MTX framework's "AbstractScreen". It will handle the rest.
All mtx framework codes are documented, so you can read for more features
- It creates stage for you - getStage()
- You should set SCREEN_W & SCREEN_H for screen resolution in "AbstractScreen" class, once set and use it everywhere
- It has state time for animations - getStateTime()
- It sets input processor for you - Gdx.input.setInputProcessor(stage);
- You can get seconds counting since its creation - getSecondsTime()
- You can get formatted time since its creation - getScreenTime()
- You can set back button active, and override the keyBackPressed() for back button

So less code, so much done:
- Created the scene
- Added background texture
- Added Screen timer and Fps
- Set the back key and override it
package com.mtx.tests;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.GDX;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.moribitotech.mtx.AbstractScreen;
import com.mtx.testasserts.Assets;
public class Test1_AbstractScreen extends AbstractScreen {
private Label lblFps;
private Label lblScreenTime;
public Test1_AbstractScreen(Game game, String screenName) {
super(game, screenName);
}
@Override
public void setUpScreenElements() {
super.setUpScreenElements();
// #1.1 TEST
// Set background texture
// ##############################################
setBackgroundTexture(Assets.imgMtxBg);
// #1.2 TEST
// Set back button
// (Override keyBackPressed to do some action see very below)
// ##############################################
setBackButtonActive(true);
// #1.3 TEST
// Screen time / Fps
// Update by overriding render
lblScreenTime = new Label("", Assets.getSkin());
lblFps = new Label("", Assets.getSkin());
lblScreenTime.setPosition(getStage().getWidth() - 80, getStage().getHeight() - 40);
lblFps.setPosition(getStage().getWidth() - 80, getStage().getHeight() - 60);
getStage().addActor(lblScreenTime);
getStage().addActor(lblFps):
}
@Override
public void keyBackPressed() {
super.keyBackPressed();
getGame().setScreen(new Test0_AllTestsScreen(getGame(), ""));
}
@Override
public void render(float delta) {
super.render(delta);
lblScreenTime.setText(getScreenTime());
lblFps.setText("Fps: " + Gdx.graphics.getFramesPerSecond());
}
}
1.4 Test2_AbstractActor
"AbstractActor" is extending Actor, so it can do anything an Actor can do. I just gave couple of game specific functions to Actor.
What it can do:
- Set a texture
- Ready to use animation state timer
- Set a animation
- Set a animation momentary (We will see in animations tutorial)
- Translate in constant speed
- All other actions that normal actors do
BAT TEST MODEL
I created a test model a bat, and I extended it to "AbstractActor" and nothing else. Just added the constructors which I may need from "AbstractActor"
package com.mtx.testsmodels;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.moribitotech.mtx.AbstractActor;
public class Bat extends AbstractActor {
public Bat(TextureRegion textureRegion, boolean isTextureRegionActive, float posX, float posY, float width, float height) {
super(textureRegion, isTextureRegionActive, posX, posY, width, height);
}
public Bat(float posX, float posY, float width, float height) {
super(posX, posY, width, height);
}
}
TEST SCREEN
I just used previous tutorials screen, and added two bats (one only has texture on has animation). Simple as it is. Animation created in "Assets" class, I will talk about animations in later tutorials. You can set texture in constructor or use another constructor which has no view information, also there are other constructor options you many use.
- Very quick implementation
- No need to worry about animations or state timer
- Cool momentary animation feature to use (Coming on one of the next tutorials)
- No need to worry about texture

package com.mtx.tests;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.GDX;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.moribitotech.mtx.AbstractScreen;
import com.mtx.testasserts.Assets;
import com.mtx.testmodels.Bat;
public class Test1_AbstractScreen extends AbstractScreen {
private Label lblFps;
private Label lblScreenTime;
private Bat bat;
private Bat bat2;
public Test1_AbstractScreen(Game game, String screenName) {
super(game, screenName);
setUpGameElements();
}
@Override
public void setUpScreenElements() {
super.setUpScreenElements();
// #1.1 TEST
// Set background texture
// ##############################################
setBackgroundTexture(Assets.imgMtxBg);
// #1.2 TEST
// Set back button
// (Override keyBackPressed to do some action see very below)
// ##############################################
setBackButtonActive(true);
// #1.3 TEST
// Screen time / Fps
// Update by overriding render
lblScreenTime = new Label("", Assets.getSkin());
lblFps = new Label("", Assets.getSkin());
lblScreenTime.setPosition(getStage().getWidth() - 80, getStage().getHeight() - 40);
lblFps.setPosition(getStage().getWidth() - 80, getStage().getHeight() - 60);
getStage().addActor(lblScreenTime);
getStage().addActor(lblFps):
}
private void setUpGameElements() {
// #2.1 TEST
// Create an abstract actor
// ##############################################
bat = new Bat(Assets.imgBat, true, 50, 20, 96, 96);
getStage().addActor(bat);
// #2.2 TEST
// Create an abstract actor with animation
// ##############################################
bat2 = new Bat(50, 100, 96, 96);
bat2.setAnimation(Assets.animBatFlyRight, true, true);
getStage().addActor(bat2);
}
@Override
public void keyBackPressed() {
super.keyBackPressed();
getGame().setScreen(new Test0_AllTestsScreen(getGame(), ""));
}
@Override
public void render(float delta) {
super.render(delta);
lblScreenTime.setText(getScreenTime());
lblFps.setText("Fps: " + Gdx.graphics.getFramesPerSecond());
}
}
Q:
Hii Morbito. I want to start up with your nice Framework for my games. I am trying to make my tile game. Previously I was using Sprite as a base class for Player, Enemy, Coin etc. But they use vectors position and velocity. In your AbstractActor..there is nothing like that. For a platform game, I will need these vector calculations for sure. Please comment on this.
A:
You can extend my AbstractActor create your own actor With vector and velocity, at the same time you can get benefits from AbstractActor.
1.5 Test3_Buttons
Buttons can be troublesome, so when I was developing my games, I asked myself "what is necessary?". Then I have created game-specific buttons which has rich features. (ButtonGame, ButtonToggle, ButtonLevel)
General features fo all buttons:
- Set down and up textures
- Set lock condition and texture
- Set text with any font
- Set external texture for different purposes
- Each button type also has special features
TESTSCREEN
I again used previous tutorials screen, I removed one of the bats, and centered the other bat. I created new method setUpButtons() to show the buttons and their abilities. I have also created a table to add all the buttons in it.

MENU CREATOR
This is very simple buttons and table creator for faster and less code writing.
BUTTONGAME
First two buttons are the general game buttons. These can be used, skills, shoot, grap or any other game specific purposes. First button was set to lock so it cannot detect his, the other button is active and has a text on it with a font I have chosen, text was set to desired position. Each time of click this buttons, sets a momentary animation (Coming on next tutorial) to bat, so each time you click the bat cycles. I also made a counter to decrease to number, when it is 0 it locks the button and makes it unusable.
// #3.1 TEST
// Button locked
// ####################################################
ButtonGame btnTest1 = MenuCreator.createCustomGameButton(Assets.btnBatCircle, Assets.btnBatCirclePressed);
btnTest1.setTextureLocked(Assets.btnBatLocked, true);
tableButtons.add(btnTest1).pad(5);
// #3.2 TEST
// General Game Button (Button + Text)
// ####################################################
final ButtonGame btnTest2 = MenuCreator.createCustomGameButton(Assets.btnBatCircle, Assets.btnBatCirclePressed);
btnTest2.setText(Assets.font2, "" + batCircleCounter, true);
btnTest2.setTextPosXY(50, 35);
btnTest2.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
// Set the momentary animation of abstractactor
// It is like a blink eye animation then goes back to regular animation
bat2.setAnimationMomentary(Assets.animBatCircleRight, true, null, true, false);
// Decrease counter
if(batCircleCounter > 1){
btnTest2.setTextChange("" + --batCircleCounter);
} else{
btnTest2.setTextureLocked(Assets.btnBatLocked, true);
}
}});
tableButtons.add(btnTest2).pad(5);
BUTTONTOGGLE
Third button is a type of button toggle (This is not fully finished, but it works). As the name sounds, its duty is toggling. So if you press this button it bat will constantly cycle, if you press again bat will fly normal.
// #3.3 TEST
// Toggle Button
// ####################################################
final ButtonToggle btnTest3 = MenuCreator.createCustomToggleButton(Assets.btnBatCirclePressed, Assets.btnBatCircle, false);
btnTest3.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
// Toggle the button, and change animation of abstract actor
btnTest3.setToggleSwitch();
if(btnTest3.isToggleActive()){
bat2.setAnimation(Assets.animBatCircleRight, true, true);
} else{
bat2.setAnimation(Assets.animBatFlyRight, true, true);
}
}});
tableButtons.add(btnTest3).pad(5);
BUTTONLEVEL
The forth button is the type of level button. This is probably the most game specific button I have created :). Pretty easy to use and implement. You can set level number or text, also you can set achivement objects (I named as star) on it. For example, you can set 2 stars, it means on that level 2 stars achieved.
For achiements, you should set holders and stars textures (or other things). For example, In levels 5 stars is the maximum achievement, then user achieved 3 stars. Button will show 5 star holders but it will set 3 stars. Still with me ? :))). Its best to see in action in the code.
- I created the button
- I set the level star holder ( dull star holders - Assets.imgStarHolder) and star ( yellow shiny -Assets.imgStar) textures, the maximum number of stars can be achived (3), the number of stars that earned (1). The number of stars earned normally comes from database of the game in actual games.
- Then the MTX auto centers all the stars, but you can set the ratio (size of it)
- You can also move the stars upper or lower with setLevelStarPosYStart()
- Then I set the level number with a font.
FOR TEST PURPOSES, I made button to increase the stars numbers on each click and it also resets the bat cycle button and activates again just for fun.
// #3.4 TEST
// Level Button
// ####################################################
final ButtonLevel btnTest4 = MenuCreator.createCustomLevelButton(Assets.btnLevel, Assets.btnLevelPressed);
btnTest4.setLevelStars(Assets.imgStarHolder, Assets.imgStar, 3, 1);
btnTest4.setLevelStarSizeRatio(3);
btnTest4.setLevelStarPosYStart(2);
btnTest4.setLevelNumber(1, Assets.font2);
btnTest4.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
// Reset circle counter, update button 2
batCircleCounter = 9;
btnTest2.setTextChange("" + batCircleCounter);
btnTest2.setLockActive(false);
// if full reset (JUST FOR TEST)
if(btnTest4.getNumberOfEarnedStars() == btnTest4.getNumberOfTotalStars()){
btnTest4.setNumberOfEarnedStars(0);
}
// Increase the earned stars
btnTest4.setNumberOfEarnedStars(btnTest4.getNumberOfEarnedStars() + 1);
}
});
tableButtons.add(btnTest4).pad(5);
BUTTON WITH A EXTERNAL TEXTURE
The last and the long button is a button game. Why would you need a external texture, you wouldn't, but sometimes it may be handy to use. For example, like in my example.
I created the button, I gave text "Top apps", but it was do dull and boring, so I put a external texture on it with burning app icons, and it became sexy.
// #3.5 TEST
// General Game Button (Button + Text + ExternalImage)
// ####################################################
final ButtonGame btnTest5 = MenuCreator.createCustomGameButton(Assets.btnAllMenu, Assets.btnAllMenuPressed);
btnTest5.setText(Assets.font2, "Top Apps", true);
btnTest5.setTextPosXY(20, 50);
btnTest5.setTextureExternal(Assets.imgTopApps, true);
btnTest5.setTextureExternalSize(120, 120);
btnTest5.setTextureExternalPosXY(144, -16);
btnTest5.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
// Set the momentary animation of abstractactor
// It is like a blink eye animation then goes back to regular animation
}
});
tableButtons.add(btnTest5).pad(5);
1.6 Test4_Animations
Important: Please downlaod the latest test project
TEST SCREEN
I removed all the buttons from previous screen and created a clean screen, added a bat and hulk test model (Hulk test model has do nothing but extending abstract actor) and I added two buttons. DO NOT WORRY ABOUT BUTTON TEXTURES. I forgot the create new textures for the buttons. Left button turns bruce to hulk and right button turns hulk to bruce.

ANIMATION CREATOR
I have always needed to quickly implement my animations, with less code writing and fast like a lighting, then I created animation creator, this is extremely helpful.
There are 3 type of animation sheets:
- Each frame saved as individual .png files
- Single .png file has one row animation.
- Single .png file has multi row animations

Animation creator has 3 methods at the moment, one for to get multi frames from individual textures, one for getting single row animation texture and other one for getting multi row animation texture. those may have many parameters it is all documented and easy to understand. Anyway, we got all our animations from 3 type of animation sheets (all embedded in texture atlas) very quickly and saved tons of time.
private void setUpAnimations() {
// Bruce - Hulk Animations (Single Sheet multiple rows)
animBruceWalk = AnimationCreator.getAnimationFromSingleTextureMultiRows(Assets.getAtlas(), "animhulkbruce", 8, 22, 4, 0, 0.08f);
animHulkWalk = AnimationCreator.getAnimationFromSingleTextureMultiRows(Assets.getAtlas(), "animhulkbruce", 8, 22, 4, 1, 0.08f);
animBruceToHulk = AnimationCreator.getAnimationFromSingleTextureMultiRows(Assets.getAtlas(), "animhulkbruce", 21, 22, 4, 2, 0.08f);
animHulkToBruce = AnimationCreator.getAnimationFromSingleTextureMultiRows(Assets.getAtlas(), "animhulkbruce", 18, 22, 4, 3, 0.08f);
// Sinlge row animation
animBatFlyRight = AnimationCreator.getAnimationFromSingleTexture(Assets.getAtlas(), "animbatflyright", 6, 0.065f);
// Multi frame .png animation
animBatSantaFlyRight = AnimationCreator.getAnimationFromMultiTextures(Assets.getAtlas(), "batsanta", 6, 0.065f);
}
ABSTRACTACTOR ANIMATION MANAGEMENT
Our actor is very clever and can manage animations easily and quickly by using setAnimation() & setAnimationMomentary() methods
Setting Animation:
If you wanna set to your actor animation it is very simple. I set all the animation we created previously to our bat, batsanta and hulk.
private void setUpGameElements() {
//
hulk = new Hulk(getStage().getWidth() / 2 - 48, 120, 96, 96);
hulk.setSize(hulk.HULK_SIZE ,hulk.HULK_SIZE * 2);
hulk.setAnimation(animBruceWalk, true, true);
getStage().addActor(hulk);
//
batsanta = new Bat(10, 100, 80, 80);
batsanta.setAnimation(animBatSantaFlyRight, true, true);
getStage().addActor(batsanta);
//
bat = new Bat(20, 20, 80, 80);
bat.setAnimation(animBatFlyRight, true, true);
getStage().addActor(bat);
}
Setting Animation Momentary:
This is a cool feature that I created for myself, it can be very handy in time. So what is it then? Think about like these scenarios;
- Character walks and get shot and it dies
- Character transforming to another being
- Character vanishing
- Character blinking eye
- So many other things...
All those happens one time, then chracters goes back to its regular animation or goes to another animations or animation stops at all. If you want one these you will love this method.
I created two buttons to transform hulk and bruce, I used setAnimationMomentary() method.
- Default animaton is bruce walking
- Then I set the momentary animation as "animBruceToHulk", so it changes to hulk, also I set the next animation "animHulkWalk" in the same method parameter, so bruce can turn into hulk, then hulk can walk as default animation, If I set the next animation as null, then after momentary animation completed, it will go back its default animation. Confused ha ? Just play with paramaters and tested, you will see.
- Last parameter is about killing all animations, if it set true, after momentary animation completed, all animations will not be drawn anymore.
// Listeners
// ####################################################
btnBruceToHulk.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
hulk.setSize(hulk.HULK_SIZE ,hulk.HULK_SIZE * 2);
hulk.setAnimationMomentary(animBruceToHulk, true, animHulkWalk, true, false);
//
btnBruceToHulk.setTextureLocked(Assets.btnBatLocked, true);
btnHulkToBruce.setLockActive(false);
//
}
});
tableButtons.add(btnBruceToHulk).pad(5);
NOTE:
Things can be confusing, but do not worry, project has very less code, it is very easy to understand after practice, our aim to write effective code with the minimum amaount.
1.7 SettingsManager
TEST SCREEN
There is no test screen or test code that I have done for SettingManager of MTX, because it is straightforward enough, however I will talk about what can you do with it, it will make your life easier and faster by writing less and less code.
SETTING MANAGER
Setting manager will give you bunch of static methods and varialbes that you can use in every game lets see, what are these. All methods are documented, so you can read if you do not understand.
Set as a first launch and check if it is first launch
You may need to create initial files or settings in the first launch of the game and check if it is the first launch or not in every game launch, methods below works with android preferences, and sets the game as first launch, and checks it if you need. You can use theses methods in create() method of the game to set some stuff
if(SettingsManager.isFirstLaunch()){
SettingsManager.setFirstLaunchDone(true);
// DO SOMETHING FOR FIRST LAUNCH
// Create database
// Create textfiles
// Set initial settings
// etc..
} else {
// IT IS NOT FIRST LAUNCH
// Load previous settings
// Set some stuff
// etc..
}
Create text files in local storage
If I dont do big games (multiplayer rpgs or similar), I llike to use text files for storing basic game data, best place to create these data is the LOCAL STORAGE
SettingManager.createTextFileInLocalStorage(String fileName)
Read/Write/Changes existing line in text files
You may need to read, write new line or change existing line in text files. In Android text files could be in INTERNAL STORAGE (cant write or change anything here, only read), LOCAL STORAGE and EXTERNAL STORAGE. (These are the FileTypes)
SettingsManager.readLine(String strFile, int lineNumber, FileType fileType)
SettingsManager.writeLine(String strFile, String newValue, FileType fileType)
SettingsManager.writeExistingLine(String strFile, int lineNumber, String newValue, FileType fileType)
Number of lines and Comma Seperated Values in text files
You may need the number of lines in a text file or your text file lines can be comma separated values such as (Jack,24,Engineer) in a single line, my method returns a ArrayList for each value between commas.
SettingsManager.getNumberOflInesInTextFile(String strFile, FileType fileType)
SettingsManager.getValuesSeperatedByCommaInLine(String strFile, int lineNumber, FileType fileType)
Music, SoundFX, Vibration and Previous settings retrieving for each game launch
You can set music, soundFX and vibration settings and quickly access in every class of the game with static variables also with a single method you can retrieve all the settings from android preferences in every game launch.
Here is a example for sound effects, setSound(), use this in your settings screen or anywhere in the game, it is static method.
// Set sound condition (Android Pref), also sets the static variable isSoundOn;
SettingsManager.setSound(boolean isSoundActive);
// Get sound condition, static variables (We do not retrieve from android pref ea// ch time we need, performance costs)
SettingsManager.isSoundOn;
// Use this in game launchs, it sets music, soundFX and vibration settings from preferences
SettingsManager.setGeneralSettings();
Series 2 (Useful Things)
This is a series for showing power of LibGDX and MTX, I will show you that things can be done extremely fast with high efficiency. This series is not mandatory but it is highly suggested. You learn about splash/loading screens, creating main menu, level menu, game menu without any effort and more will be coming in time.
2.1 Test5_SplashScreen
Everything is same with previous test screens. I added a loading animation which will fade in 6 seconds and auto go back to all tests screen.

SPLASH/LOADING
If you work with lightweight assets/resources and making not a very large game you can fake splash and loading screen easily, but if you have large amount of assets and need a real loading performer with percentage you will need AssetManager, pretty cool thing, but I wont be talking about that.
I created a "Loading" object which only extends "AbstractActor", nothing else, I added my loading animation
private void setUpSplash() {
// #5.1 Test
// Create a loading anim (NOT REAL), center it
// "Loading" is a model, it just extends abstractactor
// #########################################################
loading = new Loading(getStage().getWidth() / 2 - 50, getStage().getHeight() / 2 - 50, 100, 100);
loading.setAnimation(Assets.animLoadingSkull, true, true);
getStage().addActor(loading);
}
Then in my render method I get the seconds from "AbstractScreen" and 6 seconds later, I make my loading animation fade out, and then auto go to back all tests screen.
@Override
public void render(float delta) {
super.render(delta);
lblScreenTime.setText(getScreenTime());
lblFps.setText("Fps: " + Gdx.graphics.getFramesPerSecond());
//
if(getSecondsTime() > 6){
loading.addAction(Actions.sequence(
Actions.fadeOut(0.8f),
new Action() {
@Override
public boolean act(float delta) {
getGame().setScreen(new Test0_AllTestsScreen(getGame(), "All tests"));
return false;
}
}
));
}
DONE IN A FLASH
- Super fast implementation
- far less code writing
- Effective and cool looking
- Plenty of action types you can use, plus you can create cool animations or particles
2.2 Test6_CoolMainMenu
TEST SCREEN
Everything is same with previous test screens. I added a table and buttons in also, set a sliding animation to table

SETTING UP ANIMATED MENU
Extremely fast implementation
- Created a table
- Gave a sliding animation action
- Added 3 ButtonGames and Texts
- Done!
private void setUpMainMenu() {
// #6.1 TEST
// Create table button
// Animate from outside in
// ########################################################################
Table table = MenuCreator.createTable(true, Assets().getSkin());
table.setPosition(getStage().getWidth() + 50, table.getY());
table.addAction(Actions.moveTo(getStage().getWidth() - 550, table.getY(), 0.9f));
table.row();
getStage().addActor(table);
// #6.2 TEST
// Random buttons
// ###############################################################################
ButtonGame btnLevels = MenuCreator.createCustomGameButton(Assets.font2, Assets.btnAllMenu, Assets.btnAllMenuPressed);
btnLevels.setText("Levels", true);
btnLevels.setTextPosXY(25, 45);
table.add(btnLevels).size(230, 62).uniform().pad(2);
table.row();
ButtonGame btnSettings = MenuCreator.createCustomGameButton(Assets.font2, Assets.btnAllMenu, Assets.btnAllMenuPressed);
btnSettings.setText("Settings", true);
btnSettings.setTextPosXY(25, 45);
table.add(btnSettings).size(230, 62).uniform().pad(2);
table.row();
ButtonGame btnAbout = MenuCreator.createCustomGameButton(Assets.font2, Assets.btnAllMenu, Assets.btnAllMenuPressed);
btnAbout.setText("About", true);
btnAbout.setTextPosXY(25, 45);
table.add(btnAbout).size(230, 62).uniform().pad(2);
}
2.3 Test7_LevelScreen
TEST SCREEN
Did I say fast before, but nothing like this. I will show you to meaning of fast. In 25 line of codes (without comments), you are going to implement these:
- Level button table
- Sliding animation action for the table
- Fully customizable ButtonLevels with %100 functionality
- Set button textures, star holders, stars or any other achievement objects you want (coins, bottles, points ...)
- Set the earned stars from database or text files
- Lock the levels which you desire (from database or text file) with a texture you want
- MORE MORE MORE...

Not much to say run the code from project, read comments and documentations
private void setUpLevelsScreen() {
// Create levels table
// ######################################################################
levelsTable1 = MenuCreator.createTable(true, Assets.getSkin());
levelsTable1.setPosition(-999, 0);
levelsTable1.addAction(Actions.moveTo(0, 0, 0.7f));
levelsTable1.top().left().pad(30, 30, 30, 30);
// Add to stage
// ######################################################################
getStage().addActor(levelsTable1);
// Add levels buttons
// Normally get this number from textfiles or database
// ######################################################################
int numberOfLevels = 20;
// Create buttons with a loop
for (int i = 0; i < numberOfLevels; i++){
//1. Create level button
final ButtonLevel levelButton = MenuCreator.createCustomLevelButton(Assets.btnLevel,Assets.btnLevelPressed);
//2. Set level number
levelButton.setLevelNumber(i + 1, Assets.font2);
//3. Set lock condition (get from database if it is locked or not and lock it)
// use if/else here to lock or not
// levelButton.setTextureLocked(Assets.btnBatLocked, true);
//4. Set stars or any other achievements (get from database or text files here)
// I just made a random number of earned stars
Random rnd = new Random();
levelButton.setLevelStars(Assets.imgStarHolder, Assets.imgStar, 3, rnd.nextInt(3) + 1);
//5. Add listener
//Add button listener to go to a level (gamascreen)
levelButton.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
}
});
//6. Add row after each 5 level button to go down or how many do you need
if(i % 5 == 0){
levelsTable1.row();
}
// Add to table
levelsTable1.add(levelButton).size(100, 100).pad(5, 5, 5, 5).expand();
}
2.4 Test8_GameMenu
TEST SCREEN
Everything is same with previous test screens. Did you play Amazing Alex, did you see the sliding menus from both side, do you know how easy is to implement that with LibGDX and with abit help of MTX. I also used these in my game Puzzle Slide.

TABLEOVERLAYER from MTX
Table overlayer is only extending Table of LibGDX with a texture background. Of course normally Table has a texture if you need, but I like these abstraction, I have cool ideas for next version of MTX, very rich features for tableoverlayers. You can check this class in mtx package.
MENUSIDEBOXOvERLAYER as Test Model
This is only extending TableOverLayer I mentioned before. So basic, so fast and very effective.
public class MenuSideBoxOverLayer extends TableOverLayer {
public MenuSideBoxOverLayer(TextureRegion textureBackground, float x, float y, float width, float height) {
super(textureBackground, x, y, width, height);
}
}
SETTING SIDE SLIDING MENU
I created two menusideboxlayers for left and right with different widths and with a transparent black texture, I set their initial positions out side of the screen. I put a ButtonToggle from MTX to slide in and out with actions. I also put dummy buttons for test, and its done.
private void setUpGameMenu() {
// #8.1 TEST
// Create two side boxes in different sizes
// Make them out of the screen
// Left box 120px - Right box 80px
// ###################################################################
sideBoxLeft = new MenuSideBoxOverLayer(Assets.imgTransparentBlack, -120, 0, 120, getStage().getHeight());
sideBoxRight = new MenuSideBoxOverLayer(Assets.imgTransparentBlack, getStage().getWidth(), 0, 80, getStage().getHeight());
getStage().addActor(sideBoxLeft);
getStage().addActor(sideBoxRight);
//8.2 TEST
// Create a menu button anyhere you want, I use a toggle button here
// Toggle Button
// ####################################################
final ButtonToggle btnTest = MenuCreator.createCustomToggleButton(Assets.btnAllMenuPressed, Assets.btnAllMenu, false);
btnTest.setPosition(getStage().getWidth() / 2 - 100, 20);
btnTest.setText(Assets.font2, "Menu", true);
btnTest.setTextPosXY(20, 50);
btnTest.addListener(new ActorGestureListener() {
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
// Toggle the button, and change animation of abstract actor
btnTest.setToggleSwitch();
if(btnTest.isToggleActive()){
// Send boxes into screen
sideBoxLeft.addAction(Actions.moveTo(0, 0, 0.4f));
sideBoxRight.addAction(Actions.moveTo(getStage().getWidth() - 80, 0, 0.4f));
} else{
// Send boxes out of screen
sideBoxLeft.addAction(Actions.moveTo(- 120, 0, 0.4f));
sideBoxRight.addAction(Actions.moveTo(getStage().getWidth(), 0, 0.4f));
}
}});
getStage().addActor(btnTest);
//#8.3 TEST
// Dummy buttons to put on boxes, just for fun
// #########################################################
ButtonGame btnTest1 = MenuCreator.createCustomGameButton(Assets.btnBatCircle, Assets.btnBatCirclePressed);
sideBoxLeft.add(btnTest1);
sideBoxLeft.row();
ButtonGame btnTest2 = MenuCreator.createCustomGameButton(Assets.btnBatCircle, Assets.btnBatCirclePressed);
sideBoxLeft.add(btnTest2);
sideBoxLeft.row();
ButtonGame btnTest3 = MenuCreator.createCustomGameButton(Assets.btnBatCircle, Assets.btnBatCirclePressed);
sideBoxLeft.add(btnTest3);
sideBoxLeft.row();
ButtonGame btnTest4 = MenuCreator.createCustomGameButton(Assets.btnBatCircle, Assets.btnBatCirclePressed);
sideBoxLeft.add(btnTest4);
sideBoxLeft.row();
ButtonGame btnTest5 = MenuCreator.createCustomGameButton(Assets.btnLevel, Assets.btnLevelPressed);
sideBoxRight.add(btnTest5);
sideBoxRight.row();
ButtonGame btnTest6 = MenuCreator.createCustomGameButton(Assets.btnLevel, Assets.btnLevelPressed);
sideBoxRight.add(btnTest6);
sideBoxRight.row();
}
Series 3 (Introduction to MTX v2.0 with LibGDX Scene2D)
Mtx v2.0 is now here with lots of new features, it is strongly recommended for you to finish Series 1&2 understand the basics. In this series we will talk about new project, overcoming strecthing/black bar problems, abstractactors, auto positioning, input intents (drags, drag direction, swipe dectectsion), simple collision detectsions for actors.
3.1 (v2.0) Tutorial Structures & Project
Since Mtx v1.0, couple of new changes made over mtx, it is now structured. Project and tutorial style will be similar with minor changes. If you like LibGDX Scene 2D, this will make your life easier for games, games menu, live wallpapers and so on...

Howcan it be used:
- First of all it is pure libGDX, so you can develop your game in your way (2D / 3D) with LibGDX and add MTX over it without any problems
- Main menu and game menus with animations, easy to use buttons, no stretching problems (only Mtx v2.0)
- Game background environments, bubbles, snows, parallax effects, clouds, animated object anything about game environment can be done in seconds
- Live wallpapers (I made a small forthune with them), Top-notch, very detailed and high quality live wallpapers can be done in days
- Simple touch, touch drag and collision detections for your needs
- Games, you can develop a full game without any problems, if you like abilities of LibGDX Scene2D
Project

Tutorials
Each test is a Screen with a number, each class may have codes from other tests, to check the which code is related to current test, just focus on green comments with number. ("Test 06.2" means that this part of code is related to test 06)

3.2 Anti-Strecth/Black Bars Formula
STRETCHING / BLACK BARS
What is the problem of all develops, definitely device resolutions. Is there a perfect fix for the problem, unfortunately NO, but we can %90-95 adopt a solution to fix this problem. Of course, there is already another solution with black bars, but we do not want that.
What are the regular resolutions, 320x240, 480x800, 960x540, 1280x720, 1920x1080 and other similar resolutions with minor changes.
If you already use the Mtx v1.0, you will see the stretch problem for the devices with different resolutions beside 800x480. But with Mtx v2.0, I created a basic idea to fix the problem.

As you can notice Mtx v2.0 works just fine with almost perfect sizing for all devices, but Mtx v1.0 and many developers who develop games feels this stretching, it is especially noticeable with ovals, they become ellipses
APP SETTINGS 1
I will try to explain my method, do not confuse yourself, it will be more clear with next tutorials, I will explain the basic idea. I am more of live wallpaper developer than games (also developing games). This method suits me perfectly most of times for all type of devices.
Here is the idea:
You should have Target World Size to prepare your textures, I like 960x540 dimension, it is kind of bridge among all device dimensions, and you should prepare all your textures for this world dimensions.
How to do:
Simply in your graphic editor, open new file with dimensions (I chose 960x540 below), then prepare your textures, it is like creating a web page.

APP SETTING 2
In my app settings class, I set the my target world (The dimension matches with my graphic editor)
WORLD_TARGET_WIDTH = 960;
WORLD_TARGET_HEIGHT = 540;
I set my real world size (I genereally use the size as device resolution, but if you want to a bigger world which is draggable around like Angry birds, you should give bigger values than SCREEN_W and SCREEN_H)
WORLD_WIDTH = Gdx.graphics.getWidth();
WORLD_HEIGHT = Gdx.graphics.getHeight();
*Device screen resolutions (For example Samsung GSII SCREEN_W is 800, and Samsung G Ace SCREEN_W is 480), this is used for Scene2D stage creation in AbstractScene
SCREEN_W = Gdx.graphics.getWidth();
SCREEN_H = Gdx.graphics.getHeight();

Basic formula
I will calculate ratio of the current device resolution with my target world size, and I will use this ratio to re-size my AbstractActors which has "DIPActive" parameter true in their constructor. (Only using width to get ratio, this is only solution at the moment)
EAMPLE:
Htc DROID has 960x540, so my home button size will be 150x150 on that device (NO CHANGE)
Samsung Galaxy SII has 800x480, my home button will be 125x125
HOW TO IMPROVE & DRAWBACKS
Of course this is a style of resizing single textures for all devices. Some people can mention about performance problems or quality issues with device resolutions+1920x1080. So these are couple of drawbacks of using single texture for all devices.
The best idea to solve this, creating 2 textures (medium quality and high quality) for each object and rewrite app settings and assets loadings for different devices. You can even create 3 textures (meduim, high, extra high quality for tablets) for each in your graphic editor.
So it could like
WORLD_TARGET_WIDTH_LOW = 480;
WORLD_TARGET_HEIGHT_LOW = 480;
WORLD_TARGET_WIDTH_MED = 480;
WORLD_TARGET_HEIGHT_MED = 480;
WORLD_TARGET_WIDTH_HIGH = 480;
WORLD_TARGET_HEIGHT_HIGH = 480;
Then detect device resolution (low, high, medium), then overwrite the world size calculator which scales all AbstractActors which has "DIPActive" parameter true in their constructor. Also load right assets due to low, med and high resolutions.
AppSettings.getWorldSizeRation();
I hope you get some understanding.
3.3 Test_02_AppSettings
Test_01 is for all tests menu screen, so there is not much talk about main menu at the moment. Here lets look at Test_02:

BEFORE WE START TO TEST 02
Now, previously we talked about App Settings, before we set any screen in the main game/live wallpaper start we have to setup app settings (AppSettings.setUP())
Here in out MainStarter (extends LibGDX game)

AppSettings.setUp();
Set up WORLD_TARGET_WIDTH/HEIGHT, SCREEN_W/H, WORLD_WIDTH/HEIGHT for our games or live wallpaper
Assets.loadAll();
Load all assets (Textures, fonts, animations, sounds, etc...)
setScreen(new Test_01_AllTestsScreen(this, "All Tests Screen"));
Set all test screen as our first screen
MORE UNDERSTANDING OF STRETCH FREE ACTORS/TEXTURES
You saw the heart shape in this test (top picture), this heart perfectly sized for all resolutions, normally, it should have been stretched abit for some devices such as devices with 4:3 ratio. Thanks the our anti-stretcher formula, it will look same in every device on this planet!

Lets talk about this
I designed the heart 250x250 in my graphic editor for 960x540 (Virtual World Dimensions). In my constructor of Light Abstract Actor last parameter (DIPActive) is "true".
In background code if DIPActive is true, heart will be scaled:
heart.getWidth()*AppSettings.getWorldSizeRatio();
heart.getHeight()*AppSettings.getWorldSizeRatio();
POSITIONING
Positioning is not easy like auto-sizing, so DIPActive does not calculate the positions. Position will be different for different devices. However, I created a position-ratio calculator for different device resolution. It will be calculating estimated position for each device). But this have to be done manually if you want auto positioning
See the text example (Bottom descriptive text in our test screen, see the top picture "ORIGINAL HEART SIZE...")

I wanted to set position (15, 95) for first text in a world 960x540
text.setX(15);
text.setY(95*AppSettings.getWorldPositionYRatio());
X position is 15 without any auto positioning, and the X position wont change for each device (For example, if a device width 960 it will be at 15, if a device width 480, it will be still at 15). Text will appear on very left on first device, for second device it will also appear on left but it will be close to center. (In both devices you will feel a difference, NOT GOOD!)
Y-axis, By using AppSettings.getWorldPositionYRatio() we will auto position for Y-axis, so if my device height 514 if will appear on 95, if my device height 270 it will appear on around 47.5...
I hope again you understand the challenges of auto sizing and positioning for 10s of different device resolutions.
NOTE:
Auto sizing (DIPActive) and manual positioning techniques are optional, you do not have to use these, but they work great, for example for my live wallpapers, I got many great comments for Samsung Galaxy NOTE II, GS II, GSIII, G ACE... it means people use them and they work great. I use these techniques on my many projects.
3.4 Test_03_AbstractActors
AbstractActors are 100% same with Mtx v1.0 with additional features.
- New constructor with DIPActive (we talked about this previously...)
- Particle Ready

POSITIONING AGAIN
Before moving on, I want to talk about positioning one more time to get things more clear

In top picture, you see heart, fire and particle effects, it is all same actor (testActor).
As you know my target world dimensions in app settings is 960x540, for this world I wanted to set testActor to position 600x250. But I want my actor to be same/similar positioni in every device on this planet. So, I multiplied my position with;
600*AppSettings.getWorldPositionXRatio()
250*AppSettings.getWorldPositionYRatio()
So if my device resolution is 960x540 the position will be 600x250, if my device resolution is 800x480, actors position will be 600*(800/960) for X-axis, and 250*(480/540) for Y-axis. These will get me estimated positions for each device (But not perfect position because of many ratio differences in devices)
DIPActive constructor
Here example of extra new constructor for DIPActive calculations to auto-resize. Threre is no auto-positioning, it should be done manually like about example, if you need it.
testActor = new EmptyAbsttractActor(150, 150, true);
ABSTRACTACTOR
As I said earlier it is same with Mtx v1.0. You can set everything for actors now
- Texture
- Animation
- Animation Momentary
- Particles
Here example of adding particle:

Particles created by particle editor, You can export the particle data (example: particle.p), and add them to Android projects Assets/Data folder (If you use image in your paritcle add image as well)

3.5 Test_04_InputIntent 1
Sometimes we need to detect drag direction of user (without removing finger off the screen or vice-sersa), Also we may need to detect which area of the screen being touched at the moment. The solution is InputIntent Class, extremely easy to use.

HOW TO SET UP INPUTINTENT
So simple, There are two way of detecting touches, registering ActorGestureListener or by implementing Input Processor.
(Below a screen shot) for set up fo ActorGestureListener of stage. First I constructed the InputIntent, then I set necessary methods to make calculations
touchDown
inputIntent.etTouchInitials(x, y); // Set initial position of finger, mouse, etc...
pan (Pan is dragging, I closed method in screenshot, because it was too long)
inputIntent.setTouchCurrents(x, y); // Set current position of finger, mouse, etc...
touchUp
inputIntent.reset(); // Reset when finger, mouse is off the screen

If you implementing InputProcessor everything is similar. (I have used ActorGestureListener in my test codes), this is just to show who uses InputProcessor
WARNING 1!
AbstractScreen already registers input processor Gdx.input.setInputProcessor(stage);, if you want to use multiple processors for stage and current screen which implements input processor, you have to override your inputprocessor settings by using input multiplexer. Then construct your inputintent in the constructor.
InputMultiplexer plex = new InputMultiplexer();
plex.addProcessor(this);
plex.addProcessor(getStage());
Gdx.input.setInputProcessor(plex);
inputIntent = new InputIntent();
The rest is similar to actorgesturelistener.

HOW TO USE INPUT INTENT
It is so simple.
WARNING 2!
If you use implement inputProcessor instead of using ActorGestureListener, defaultly libgdx world Y-axis opposite as you know if you dont do something about it, so DOWN means will be UP, UP means will be DOWN.
In my example I use ActorGestureListener to detect touches so everything is normal for my example.
As you can see the eample (Up Screenshot). It is very simple, inputIntent.getDirectionIntent() will return current direction (DirectionIntent), just check for direction and do whatever you want. In my case, I turn the arrow on left and rewrite the text at the bottom due to current drag direction.
DirectionIntent could be TOUCH_IDLE, TOUCH_D_UP, TOUCH_D_DOWN, TOUCH_D_LEFT, TOUCH_D_RIGHT
You can also check the current touch area see the rest of class, observe the codes and read the documentation by hovering on methods. Everything is easy to use and understand.
3.6 Test_05_InputIntent 2
What if I just need to detect swipe intentions not minor drags on the screen. The very simple solution is again InputIntent class.
FOR EXAMPLE: When you get notification center in android, you need to drag abit longer, not just minor drags like 4-5 pixels.

SET DRAG INTERVAL
First I need to determine how much drag needed for a specific task, in my example below
dragAmount = AppSettings.SCREEN_W / 5.0f;
inputIntent.setTouchDragIntervalRange(dragAmount);
Drag amount is 1/5 of the Screen Width (So if you use Samsung Galaxy II, you need to drag 160 pixels, if you use the GSIII, you will need to drag 256 pixels)

CHECK DRAG INTERVAL
It is again very simple, just use:
inputIntent.isTouchDragInterval(); // This simple will return true if needed drag amount achieved which you set in above example (dragAmount) inputIntent.setTouchDragIntervalRange(dragAmount);
In my example I only want to detect drags to LEFT and RIGHT, I do not care for UP and DOWN drags, So if user drags to LEFT or RIGHT and if it is DRAG INTERVAL return true and do something.

EXAMPLE
The best example you can see in one my live wallpaper projects "Christmas Live Wallpaper". You need to drag a specific amount to UP and DOWN to switch between Christmas Tree and Christmas Objects.
NOTE: The InputIntent I used in this live wallpaper abit old version, back then it was only detecting by removing finger off the screen each time. The current InputIntent much more improved and better.

3.7 Test_06_CollisionDetection
Some developers may need collision detection for actors.
Collision detection is very simple, nothing complicated or impressive about it. I created a class CollisionDetector which has only one method at the moment (it will be improved more in the future) to detect collision of two actors from their rectangles, and returns ture or false.
CollisionDetector.getActorsCollisionFromRectangles(Actor a1, Actor a2);
In my example I created two actors(a1 and a2), I created checkCollision() method which constantly check collision in render().
