Full LibGDX Game Tutorial – General Improvements

Sharing is caring!

Full LibGDX Game Tutorial – General Improvements

Welcome to part 15 of our Full LibGDX Game Tutorial. This part will focus on general improvements to the game like adding textures, better level generation etc. If you haven’t seen the earlier parts of this tutorial I advise you to start at Full LibGDX Game Tutorial – Project setup as this tutorial continues from these earlier parts. For those of you who have come from part 14, you can continue on.

In this part, we will be replacing our old simplex noise generation code with the OpenSimplexNoise. We will also be changing the code in the levelFactory to be more readable and reusable. Finally, we will update the end screen to show the user their score with a button to go back to the main menu. Later we will be adding the ability to post the high score on a leaderboard.

General Improvements – Open Simplex Noise

The  OpenSimplexNoise is available from github.com. This is similar to the one we have already, however, the output values are more consistent than the one we are using at the moment and this will make it easier for us to use in our game.

Add the OpenSimplexNoise to your simplexnoise package so we can use it in our game. Once done, update your levelFactory to match this code:

Here we added a new method called genNforL that takes the level(the height of the player) and the height (the layer of noise). This will generate the noise value for the level we provide. This is purely for readability in our generateLevel method. If you look at the generateLevel method you will now see we replaced all the noise generation with a for loop which calls the generateSingleColumn method. This method will generate a single column of platforms based on the noise values passed in. This allows us to reuse this code by changing the offset so another column can be created next to our previous column.

Now when you run the game the world should look similar to this:

General Improvements - Current

 

This should be a lot easier for our player to traverse allowing them to get higher and reduce the possibility of impossible sections.

General Improvements – Springs to Teleporters

All the extra platforms mean that the springs we created are pretty much useless most of the time as a platform is likely to be over it. In order to fix this, we will change the spring from shooting a player up to teleporting a player up higher. This is done in the playerController:

Now when you land on a Spring you are teleported 10 units higher. Now we have a better level generation process let’s update the player and bullets so they have animations.

General Improvements – Bullet Animation

We will need to add 2 new sprite animation sheets to our project. For the purpose of this tutorial, I will use 2 different methods to load the animation. One will be a series of images that we will turn into an animation and the other will be a sprite sheet that we will convert to an animation using an extra function added to the DFUtils class. Let’s start by adding the new function to our DFUtils class:

This function takes a texture region which contains all of our animation frames then splits them into a 2d array. An animation only takes a 1d array so we have to compact the 2d array into a single array which is then returned. In order for an entity to be animated, it requires the AnimationComponent and StateComponent. The StateComponent is used to choose which animation to play This allows us to have a different animation for jumping, moving, falling, shooting etc. We will do the Bullets first which don’t have any states other than the normal state but the state component is still required. Update your LevelFactory’s createBullet method to match this:

In order to use the animation, you will need to add the sprite sheet images to your assets. You can download the sprite sheet from opengameart.org and add it yourself with the texture packer or you can download the already packed game.png(the image below) and game.atlas(the text below)

General Improvements - our atlas

 

In the code, we have added atlas.findRegion(“FlameSpriteAnimation”) to get the animation from the atlas. We then pass it to the DFUtils function we created earlier to split the texture into single frames which are used to create a new animation. The animation is set to loop and added to the AnimationCompnent under state 0. state 0 is the normal state and the only state a bullet has. Now when we fire a bullet the bullet will be an animated flame.

General Improvements  – Player Animation

Now to add an animation for the player. Still, in our LevelFactory we need to update our createPlayer method to this:

The animation frames used here are from powstudios.com and are single images which have been resized to match our player size. The images were added in our texture atlas as single images with a number suffix in the name to identify the order the images should be used. This makes adding animations easier as we can load the images as a single array of texture regions straight from the atlas with atlas.findRegions(“flame_a”). The file names were flame_a_000x.png where x is the frame number. Since out player has different states we have to add an animation for each state. Later we will have a different animation for each state, but for now,  a single animation will suffice.

After testing the player animation you will notice that the animation stops when doing certain actions like jumping. This is due to the way we change the player state. Currently, we are changing the state each frame which resets the animation. In order to fix this, we need to update our PlayerControlSystem to only change the state if it is not already in that state.  Update you PlayerControlSystem to:

In a couple of places we have added && state.get() != StateComponent.[some state] to check if the state is not in the state we want to change to. This fixes the problem of the animation resetting.

In the code above we also changed the jump mechanic. We changed the value used to add upward force to our player with b2body.body.applyLinearImpulse(0, 12f * b2body.body.getMass() , b2body.body.getWorldCenter().x,b2body.body.getWorldCenter().y, true); In order for this to work properly we need to update the BodyFactory and set a new density for our STONE setting. Set the stone density to 1f.

Now our player should jump normally again.

General Improvements – Entity Textures

If you noticed a green flat object in our game.png file earlier you may already know that we are going to add images to our platforms..and you’d be right we are. All it is is a simple change to the LevelFactory and our platforms will have images.

If you haven’t added the platform image in your atlas yet, use the image above to add it. Then you can update your LevelFactory:

So we have added a couple of animations and a texture for our platform but we’re still using the debug renderer. Later, we will want to turn this off completely but for now, we just want to see what the game looks like without it on. Let’s add a flag for the debug renderer that we can adjust in the code to turn the debug renderer on and off. Update your PhysicsDebugSystem:

Now, when you run the game you won’t see the debug renderer and will only see the animations and textures we have added. Which should look something similar to this:

General Improvements - Texture Render only

The enemies are hard to see due to the colour I chose the use, but that doesn’t matter because we’re going to give them a new texture. What texture is that? well it this awesome super texture created by me:

That masterpiece needs to be added to your assets via that texture packer. As we did before for the platform texture we change a single line of code in the LevelFactory:

And voila:General Improvements - Enemy Water Drops

General Improvements – Water Floor

To make this a bit more aesthetically pleasing we need to add some items for the teleporter/springs, however, I want to use a particle system for those so that will be done in the next part of the tutorial. To make the game a bit more fun and playable we will limit the distance the water can be from the player which will increase the urgency of the player moving upwards. To do that we will check the water position and if it is too far move it up. So let’s edit the WaterFloorSystem:

Since the water is now going to follow us we will want to be able to top see it. We will also want to see the floor when we start so we don’t look like we’re floating when we start the game. So let’s add the floor texture and the water texture:

General Improvements - Water Texture
Water Texture
General Improvements - really badly drawn dirt
really badly drawn dirt

Add these 2 images to your texture atlas, or make your own and add them to your atlas. Then update you LevelFactory class and update this code:

General Improvements - Now with water and dirt

You should now have something similar to this video:

[embedyt] https://www.youtube.com/watch?v=lFwPgxEBCAE[/embedyt]

 

General Improvements – End Game Screen

The final step of this tutorial is to add an end game screen that shows the player their score and has a button to go back to the main menu. Currently, we just move to the endgame screen then move back to the menu so we already have the code for these actions. All we need to do now is to add the button and make the button trigger the screen change. The first thing we need to is to add a last Score variable to our Box2DTutorial class so that we can pass it to our endScreen to display. Simply add this code to the Box2DTutorial after the other variables:

Now we need to set this value when the player dies. We already check for the player death in the MainScreen so let’s update it to not only check for death but also update score in the Box2DTutorial class.

Finally, we need to update the EndScreen:

All of the code above has been seen before when we created the MainMenu so no explanation should be necessary. You should now have a game that starts with a loading screen, goes to the main menu where the player can update preferences, quit and play the game. The player can now play the game and when they die are prompted with the end game screen which shows their score and returns to the menu.

We now have a full game, granted it’s missing a few things like music, sounds, pretty effects, challenging play and finesse but these can be added later and people can start playing the game. This is where the fun starts, we can start thinking about what other things we want in our game, do we want to add new enemies or some traps like falling rocks or hidden panels that shoot arrows. Do we add an AI character that we have to race or do we add new bonus items like power-ups that make us shoot faster or give our player different weapons to use against the enemies? Since we used the Ashley framework we can simply add new items with a few components and a new system easily whenever we want.

Over the next few tutorials, we will aim to add some particle effects to cover the pretty effects need and maybe move into AI for the enemies to make the game more challenging.

As usual here is a download of the complete project from stormyvids and a link to the next part Particle Effects – part 16

← Shooting Contents Particle Effects →

 

Sharing is caring!

10 Replies to “Full LibGDX Game Tutorial – General Improvements”

  1. Hi, could you put the source code (until now, part 15)?

    I have a problem with animation, I see a black screen (if I set debug to true).

    Also I do not see the score (I am using Android Studio 2.3.3, I to test the code for both the Desktop and Mobile version.

    I’m using the latest version (libgdx-nightly-latest.zip – 15-Jul-2017 10:03)

    I would compare the code, thanks for the work done so far.

    1. Hey 5ono10,
      I have added a link for downloading the full project.
      I believe there have been some changes in LibGDX that requires you to define a type when creating an animation.
      So new Animation (0.1f,TextureRegImg) becomes new Animation < TextureRegion > (0.1f,TextureRegImg)

      1. Thanks John.

  2. Hey JOHN,
    I’ve made the changes without results, I think the problem varies from the AnimationSystem class …
    @Override
         Protected void processEntity (entity entity, float deltaTime) {

             if (ani.animations.containsKey (state.get ())) {
                 TextureComponent tex = tm.get (entity);
               —> tex.region = ani.animations.get (state.get ()). GetKeyFrame (state.time, state.isLooping);
             }

    I tried to cast it but nothing changes –> tex.region = (TextureRegion) ani.animations.get(state.get()).getKeyFrame(state.time, state.isLooping);

    1. Have you updated your AnimationComponent so that he animation types are set?

      public class AnimationComponent implements Component, Poolable {
      public IntMap<Animation<TextureRegion>> animations = new IntMap<Animation<TextureRegion>>();

      @Override
      public void reset() {
      animations = new IntMap<Animation<TextureRegion>>();
      }
      }

      1. Ok! Now works. 😉

      2. However, the resolution that you have set is good only for the desktop version.
        Anyway thank you for this tutorial.

  3. That’s an incredible work, i am for 4 days following the tutorials and today i have think, if have been four days with copy-paste , how many time has been working this men to create these tutorials?.
    Thank you very much.
    (sorry for my english)

    1. Hi Juanjo,

      I write these tutorials myself in my spare time, which is why they’re still not finished. :p
      I’m glad you like it and I hope you continue on learning and end up creating your own software/game in the future.

  4. solo puedo disparar una sola ves

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.