👨🏼‍💻LibGDX Demo Game Application With ML Kit Hand Gesture Detection and Ashley System Library Part 2

Erdal Kaymak
Huawei Developers
Published in
10 min readMay 18, 2022

--

Introduction

Hi, If you did not read the first part of this article check this link. In this article, we will understand LibGDX Ashley Entity System Library and create a Libgdx Game Screen. Also, we will create our player object with entity factory class, we will learn and use components, systems, and engines in this Game Demo Application.

Bounds Component

I create this component to keep the bounds data of players and other game objects.

First I implement this class from the Component interface. That is a simple Component class. I create two variables for the use of this component in Game Objects. One is a circle for using in circle shape game objects and another one is a rectangle for using rectangle shape game objects.

Position Component

I create this component to keep the position initial values ​​of the x and y coordinate of game objects in the game world.

Player Component

That component is only used to sign the game object as a player. This class does not have any data.

Enemy Component

I create two variables for understanding to hit an enemy with the player and hit an enemy with the laser. I reset the values in the reset function. This function is called when the enemy is cleaned from the game world.

Laser Component

This component is used only to sign that the game object is a laser. This class does not have any data.

Explosion Component

I create one variable for understanding to the explosion animation is finished or not. I reset this value in the reset function.

Texture Component

That class is used to keep the texture region data of the game objects. I create one variable to keep the texture region data of game objects. Texture Region is the region of Texture Atlas. Texture Atlas keeps all game object textures in one file with their regions.

Dimension Component

I create this component to keep dimension values ​​of the width and height of game objects in the game world. I set the width and height initial values ​​to 0f.

World Wrap Component

That component is only used to wrap the game object and prevent the game object from the out of the game world.

Clean Up Component

I create this component to clean up game objects from the game world

GameManager Class

I create this class for controlling level, high score, and health with the help of Preferences. I call this class from the systems.

GameConfig Class

I create this object for storing constant values. Such as world height, world width, lives, core, enemy and player size, hud width and height, etc.

EntityFactory Class

I create this class for creating entities and game objects dynamically.

Firstly, I pass engine and assetManager as parameters of the constructor. I use assetManager for game texture and the engine for adding components and entities.

(In lines 10–14) I create init for initializing gameplayAtlas and explosion texture. I use gamePlayAtlas for all game object textures and I use explosion texture for just explosion of the game object it should split from the gamePlayAtlas for creating explosion animations.

(In lines 16–47) I create my player with the help of the game engine and components. I create components with the engine.createComponent() method. I create an entity with the engine.createEntity() method. After this, we can add these components to our entity (player). I add components respectively. Order is important when we add our components to the entity. For this reason, I add components in this order; bound, player, texture, position worldWrap, and dimension. Finally, we can add an entity to our game with the engine.addEntity() method.

(In lines 49–79) I create my laser with the help of the game engine and components. I add components to an entity (laser). I add components in this order; bound, laser, movement, texture, position, and dimension. Finally, we can add this entity (laser) to our game with the engine.addEntity() method.

(In lines 81–112) I create my enemies with the help of the game engine and components. I add components to an entity (enemy). (In lines 99–101) I get the game difficulty with the help of preferences after that I set the difficulty to the game using setDifficulty() method. I add components in this order; bound, movement, texture, position, dimension, cleanUp, and enemy. Finally, we can add this entity (enemy) to our game with the engine.addEntity() method.

(In lines 116–169) I create a setDifficulty() method for changing enemy speed and size with the level of the game. When the score increased I change the level and after the level changes, enemies are faster and smaller randomly.

(In lines 171–191) I create my background with the help of the game engine and components. I add components to an entity (background). I add components in this order; texture, dimension, and position. Finally, we can add this entity (background) to our game with the engine.addEntity() method.

(In lines 195–232) I create my explosions with the help of the game engine and components. This entity is a little different than others. I change the textures in time to prepare the explosion animation when the enemies died. I add components to an entity (explosion). I add components in this order; texture, dimension position, and explosion. Finally, we can add this entity (explosion) to our game with the engine.addEntity() method.

Mappers

We can use the Mappers object to map the Components with the help of the Components Mapper class.

Bounds System

I create this system to determine the entity's bounds with position and dimension components.

I use this system with Iterating System. Iterating System gets Family as a parameter. The family should contain the used components for system work. This system’s processEntity() method will be called when the entity contains the bound, position, and dimension components. Also, we should call this system with engine.addSystem() method in the GameScreen.

Movement System

I use this system to move the entity such as the enemy and laser. I use this system with Iterating System.

When the entity contains the Position Component and Movement Component together it can be moved with this system. Also, we should add all systems to our engine on the Game Screen.

Render System

I create this system for rendering entities. I use this system with Entity System. This system update method will be called every frame.

I pass Sprite Batch and Viewport to the constructor for using this system. (in line 3) I create an entity array to use rendering entities. (In lines 6–16) First I create my entity list with the engine.getEntitesFor(FAMILY) method that way I get the all entities that contain the Family components(Texture, Position, Dimension). After that, I add these entities to my entity array which is called renderQueue. Later I called viewPort.apply() to activate my ViewPort. (in line 11) I set the SpriteBatch with my ViewPort with a camera. Combined that means that it represents the combined view and projection matrix. In other words; it describes where things in your game world should be rendered onto the screen. (In lines 13–15) I call draw method between batch.begin() and batch.end(). (In lines 21–31) I create a draw method to draw my rendering entities with batch. draw() function.

HUD Render System

HUD (heads-up display) or status bar is the method by which information is visually relayed to the player as part of a game’s user interface. I create this system for showing scores and lives on the game screen. I pass ViewPort, DarkSpaceGame, and BitmapFont objects as a parameter of the constructor. I use this system with Entity System.

(In line 14) I create GlyphLayout for getting the text dimension and showing the score on the Game Screen. In the update function, I call draw methods between batch.begin() and batch.end() methods. (In lines 33–38) I create the score text and set the text to GlyphLayout for getting the height and width of the text with the layout.setText() method. Then I draw this text with the font.draw() function.

(In lines 43–70) I set lives HUD for showing lives on the Game Screen. First I create Game Play Atlas for getting the lives region with help of the Asset Manager. After that, I get how many lives are left with help of Preferences. Then I change the color of the health object if the health decreases in the game. I draw the lives with batch.draw() method. (In line 69) Finally, I set the color to the old color.

Enemy Spawn System

I use this system to create enemies for every interval of time.

I use this system with Interval System. Interval System gets the Float value as a parameter. This value means that this system will be called every interval time. For example; I choose 1f for this value so my enemies will spawn every second. This system calls updateInterval() method every second that way I can change enemies x position with a random function and I call addEnemies() method to create enemies.

Player System

I create this system for moving the player with hand gesture detection.

I store the hand gesture situation in the TOUCH_LEFT_RIGHT variable. When the player moves with hand gesture detection I change the player position with that value.

Laser Spawn System

I use this system to create lasers for half of every second. I use this system with Interval System.

I create two lasers half of every second. Also, I change the laser position with the player dynamic position.

World Wrap System

I create this system for wrapping the game world. I use this system with Iterating System.

I clamp the position x and y with MathUtils.clamp() function. I use this system with Iterating System. When the entity contains World Wrap Component, Position Component, and Dimension Component together it can be wrapped.

Clean-Up System

I use this system for cleaning enemies if it is passed the screen.

In processEntity() method I control the enemy position with enemy size. Then, I update health, score, and level with the GameManager object.

Collision System

I create this system for the collision operation of entities using the Entity System. I have four families. These are player, enemy, laser, and explosion family.

Firstly, I pass the EntityFactory object as a parameter of the constructor. I use the GameManager object to update scores and health.

(In lines 6–15)Firstly, I get player, enemies, lasers, and explosions entities with the engine.getEntitiesFor(FAMILY) method. Then I control the size of the explosions and remove the first explosion with the engine.removeEntity() method.

(In lines 16–33) Firstly, I get the player dimension and position then I get all enemy entities and I control the collision with the player. I use the chekCollisionShip() method for this operation. If the player and enemy have a collision then I remove the enemy and create an explosion with the factory.addNewExplosion() and update the health and score with the GameManager object.

(In lines 35–55)Firstly, I get enemy components, dimensions, and positions. Then, I control the collision of lasers with enemies. I use checkCollisionLaser() method for this operation. After that, I remove the entity and create a new explosion and update the score.

(In lines 57–62) I use this method for controlling the collision between the player and enemies. Firstly, I get the bounds of player and enemy with the helper of the Mapper class. Then I control their collision with Intersector.overlaps() method.

(In lines 64–69) I use this method for controlling the collision between lasers and enemies. Firstly, I get the bounds of laser and enemy with the helper of the Mapper class. Then I control their collision with Intersector.overlaps() method.

Game Screen

I use this screen with ScreenBaseAdapter. I pass the DarkSpaceGame object as a constructor parameter. I use this screen as a Game Screen. All game operations run on this screen. Also, you can play the game on this screen with Hand Gesture detection from the camera.

Firstly, I create the object of AssetManager, Viewport, ShapeRenderer, PooledEngine, EntityFactory, OrthographicCamera, RenderSystem, BitmapFont, Preferences, and GameManager in the show() method.

(In lines 33–47) I add systems respectively with the engine.addSystem() method. Order is important when we add our systems to the entity. For this reason, I add systems in this order; Player System, Movement System, World Wrap System, Bounds System, Enemy Spawn System, Laser Spawn System, Clean-Up System, CollisionSystem, Render System, and HudRenderSystem. Then I add background and player with EntityFactory object. Show() method will run once when the GameScreen opens.

(In lines 49–61) I use this method for rendering every game frame. Firstly, I call the engine.update(delta) method to trigger systems update() and processEntity() methods. Then I get lives from the Preferences object. After that, I control the player's health with the checkPlayerHealth() method. When the player’s lives are equal to zero then I call the system.update(0f) to stop the engine rendering.

(In lines 66–86) I create this method for controlling player health when the player has no life then I create a new explosion on the player by getting player dimension and position.

(In lines 88–91) We should call viewport.update() and hudViewport.update() methods for managing the camera and determining how world coordinates are mapped to and from the screen.

Tips & Tricks

I use Ashley Entity System Library for this demo application. If we don’t use this system library it will be hard to build modern games. By using this system library we separate the game logic from the rendering logic. Also, we use EntityFactory to create dynamic entities instead of static class entities.

Conclusion

Now we learned how to create a LibGDX demo game application and create the Game Screen and understood LibGDX Ashley Entity System Library. Also, we created our player object with entity factory class, we learned and used components, systems, and engines in this demo game application. If you want to learn more about LibGDX and its services, you can check this link. I tried to teach advanced topics of the Libgdx Ashley Entity System Library with this demo application. I hope you understand all.

Take Care until next time …

--

--