Posted by & filed under Dissertation.

Projectile implementation took me about two days. I had a projectile firing in about two hours, but tweaking the code and testing different ways of how the user can fire took the extra time. Furthermore it turns out I had forgotten quite a bit of my GCSE maths and therefore had to learn that all over again.

Before implementing firing I had to think about how I wanted the player to fire. Since I am using a mobile screen there is a lack of space for complicated controls. Therefore I only really had two options, do I use the touch input or do I use a simple onscreen control?

Since I already had an onscreen control for movement I thought I’d just add another for firing to see how it worked. Personally I feel that this would be a good approach as it would keep the users hands in one place. However I ran into a bit of issue using the input library in Libgdx. When you use a touchpad/joystick you have two ways to gather the X and Y coords of the touchpad, you can either use a set of methods which return the position of the knob relative to the centre of the widget, or return the position of the knob as a percentage from the centre of the touchpad to the edge of the circular movement area. Using either of these turned out to be massive headaches as I couldn’t get the maths to work correctly. For example if I wanted to fire directly upwards I would hold up on the touchpad, and if I wanted to fire downwards I would hold down, but when firing in between it was like the angle wouldn’t calculate correctly and not be straight. Ideally I should have taken some screenshots but the best way to describe it was that it didn’t feel right when using. The other issue I had with this is when I tested on the desktop version of the game, it would work in a certain way, but when testing on the mobile it was different. This definitely added to the time it took to implement projectiles overall.

This lead me onto the second possible implementation, using the whole screen as the input device. I found this a lot easier to implement, but this could purely be down to the fact that I learned a lot from implementing the previous method. The way I implemented this method was quite simple, during the render/update method of the main game loop I have a conditional statement that asks whether or not the screen has been touched, if it has then take those coordinates and pass them into the player’s fire method. It also turns out that I had to call the ‘unproject’ method from the camera class on these coords, otherwise their values would be affected by the camera and therefore be incorrect when given to the player class.

So let’s get into some maths, how did I manage to get the angle of where the player is and where the user has touched? As mentioned above, we first need to get the touch input.

screenTouchPosition = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
  camera.unproject(screenTouchPosition);
    player.fire(delta, screenTouchPosition);

So as you can see ‘screenTouchPosition‘ is a Vector3, this is a variable that I declared globally in the class. The reason for this is I didn’t want Java creating a new Vector3 every time it went through this loop, this was an optimisation tip I picked up from the Android website. So why I Vector3 you ask, when all we need are the X and Y coords? Well it’s simple, the camera.unproject method can only take a Vector3. Since I am not making a 3D game or using depth in anyway, I don’t really have to worry about what goes into the Z position of the Vector3, so I just added a zero in there. The last step is to call the player.fire method and pass in the delta time and the coords where the player has touched the screen. As a side note, adding this into an if statement that first checks to see whether the screen is touched or not is a good idea, otherwise this method will constantly run all the time!

The next step is to work out the angle of where we need the projectile to traverse.

public double calculateAngle(float x, float y, float a, float b) {
     return (Math.toDegrees(Math.atan2(y - b, x - 1)) - 90);
}

In the above example the X and Y variables that are parsed in are the players position while A and B are the coordinates of where the player touched the screen. Java then does a lot of work for us by providing the Math.atan2 method. This method neatly gives us the direction between two vectors and therefore the angle.  After working this out I then create a new projectile object and add it to my game world. This projectile object then has its own update method that calculates how to update its position in the game based on the angle that we just worked out.

public Vector2 calculateVector(double angle, float speed) {
  vector = new Vector2();
    vector.x = Math.sin(Math.toRadians(angle));
       vector.x *= speed;
    vector.y = -Math.cos(Math.toRadians(angle));
       vector.y *= speed;
   return vector;
}

So what is happening above? First we create a new Vector2 (I’ve called it ‘vector’ in this example to keep it simple), this is going to hold the distance as to how far the projectile will move during the next game loop. Again Java does a lot of work for us here by providing us with relevant methods that we need. Hopefully you’ll remember sin and cos (we don’t like tan) from your maths classes at school so I won’t go over what they are doing. The Math.toRadians method is pretty cool as it converts the angle we worked out earlier from degrees into radians. A radian can be worked out by the following: Start at the centre of the circle, move along the radius until you hit the edge. Then move along the circumference of the circle the same distance that the radius was. Then move in a straight line back towards this centre point. This creates you a segment of the circle and a radian is the angle of that segment.

The method returns a Vector2 and we simply add this to our projectiles current X and Y position during each update of the game. I should also point out that we parse in a float variable called speed. This is quite simply how far you want the projectile to move per update. Setting it to a 100 will result in you not being able to see the projectile at all as by the time the game has updated it, its moved off the screen. I have mine set around 10, but I do like the patterns that you can make when you set it lower and spin your character around!

So that’s it for this blog post. I’ve learnt quite a lot from implementing projectiles in Libgdx, the camera.unproject was a particularly tricky moment as at the time I had no idea the camera was changing the input variables. Ideally I would have liked the player to fire the first way I tried to implement, but time is not on my side and I felt it was better to have an implementation of firing than not at all. Should I have time towards the end of my project I will revisit this and see if I can get the touchpad method to work.

 

One Response to “Dissertation: Projectile Implementation”

  1. Guest

    Don’t know if you’ve already profiled your application, but this line will create garbage:
    screenTouchPosition = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);

    Reason for this is you are using “new” keyword, which means “drop old reference for screenTouchPosition and assign new Vector3 to it”. If you really want to make it not produce garbage, you should do something like this:

    screenTouchPosition.x = Gdx.input.getX();
    screenTouchPosition.y = Gdx.input.getY();
    screenTouchPosition.z = 0;

    For future readers. 😉