In this project, we will put into practice everything we learned in part 1 and part 2 of the tutorial series on trigonometric functions. We will draw a simple triangle-shaped spaceship to the screen by drawing lines between three points/vertices. We will then see how we can do the math to smoothly rotate it and calculate its heading in order to fly around the screen.

patreon

 

 

About this project

Skill level 1
Time to complete 1 hour

New Concepts:

  1. Movement-based on a heading in degrees
  2. Rotating a 2d game object

Projects that demonstrate these concepts

To get started create a new project in Android Studio, call it Heading And Rotation and name the Activity HeadingAndRotationActivity then read on.

Making the game a full-screen landscape

We want to use every pixel that the device has to offer so we will make changes to the app’s AndroidManifest.xml configuration file.

    1. In the project explorer pane in Android Studio double click on the manifests folder, this will open up the AndroidManifest.xml file in the code editor.
    2. In the AndroidManifest.xml file find the following line of code,  android:name=".HeadingAndRotation"
    3. Immediately below type or copy and paste these two lines to make the game run full screen and lock it in the landscape orientation.

This is an important step because otherwise, the controls won’t work.

The class structure

We want to create classes to represent the view and the spaceship. We will call them  HeadingAndRotationViewand Ship. By creating empty implementations of these classes we can then declare objects of them right away and make faster progress through the code.

With this in mind let’s create those empty classes. Right-click the java folder in the Android Studio project explorer as shown in the next image.

Creating a new Java class called Paddle

Creating a new Java class called Paddle

Now select New|Java class then select …\app\source\main\java and click OK. Now enter HeadingAndRotationView as the name for our new class and click OK. We have now created a new Java class in a separate file called HeadingAndRotationView.java. Now do the same thing and create a class called Ship.
[widgets_on_pages id=”udemy_advert_java_2″]

Coding the Activity class

This Activity class is no different  from the Activity classes from other projects like the Breakout game so I will just throw the code at you below. If the comments are not enough to remind you of what the code does then check out more detailed explanations in the Breakout project. Delete the contents of the HeadingAndRotationActivity class and add this code instead.

Coding the view class

The view class holds nothing new either. It sets up the main game loop and calls update and draw as per usual. The only slightly new thing compared to the Breakout or Space Invaders projects is that in the draw method we use the drawLine method of the Canvas class to draw three lines that we get the coordinates for by calling getA, getB and getC of the Ship class that we are yet to implement. For more on drawLine have a look at the Drawing Graphics project.

Also, if anything is unclear about the way we handle the player’s input check out the Space Invaders project. The controls simply allow the player to hold the very bottom left or right of the screen to rotate left and right or hold anywhere above the bottom eighth to thrust. The setMovementState method of the Ship class is called with the appropriate value in each case.

I have liberally sprinkled comments throughout as a reminder of what the code does. Enter the following code in the HeadingAndRotationView class and then we can look at the Ship class which is where all the action takes place.

[widgets_on_pages id=”udemy_advert_java_3″][widgets_on_pages id=”udemy_code_details”]

Coding the Ship class

Now for the fun part. As this class contains some new ideas we will break it into a few parts and explain the code as we go along. Just enter each section of code after the previous section and at the end, you should end up with a fully working project.

The  class declaration and member variables

After the import directives and class declaration, we declare four PointF objects to hold the x and y values for the vertices of the ship ( a, b, c and the center point of the ship ( centre)). Next, we declare and initialize facingAngle to 270. This will be the variable that keeps track of which way the ship is pointing.

Next, we have length and width which do as you probably suspect. We then have a speed variable which will be the speed of the ship in pixels per second. Next, we have horizontalVelocity and verticalVelocity which will hold values relative to each other and will enable us to move at a specific heading. We will multiply both of these variables by speed each frame so they are still relative to each other but quicker than the base values returned by our trigonometric functions.

We also declare and initialize rotationSpeed. We will see how we use this variable to lock the rate at which the spaceship rotates in a frame rate-independent manner. Finally, we have our ship’s movement states and the shipMoving variable to hold the current state. Enter the code below into the Ship class.

Coding the Ship constructor

In the constructor, we make the length and width variables equal to one-fifth of the screen resolution, it will be quite a large ship but this is good for seeing what is going on. Then we initialize all four of our PointF objects as blank points.

Next, we initialize the members of the four PointF objects with the relevant coordinates. We make centre the exact center of the screen. Now it is important to draw the ship in its initial position at the same angle that we set facingAngle otherwise it will be out of sync from the start. We used 270 which is pointing straight up. Remember 0 degrees is facing east/3 O’clock and the angle grows bigger anti-clockwise).

We initialize the members of a, b and c by using centre, length and width. If you were to plot the points and join them up you would end up with a ship much like the image in the 2d graphics rotation tutorial. Obviously, the exact sizes will vary dependent on the screen resolution of the specific device you use. Add the constructor code to the Ship class.

Ship class getters and setters

Now we have a bunch of getters and setters so the view can access and set the necessary members of the Ship class. These include a getter for each point and the facingAngle as well as setMoveMentState so that the onTouchEvent method from the view can change the movement state. Add these methods to the Ship class.

The update method

As this method holds all the magic that we learned about in the trigonometric functions part 1 and part 2 tutorials we will break it into a few pieces to be clear about what is going on. If anything is unclear be sure to read those tutorials.

The first part of the update method is the simplest. You can see that if shipMoving equals LEFT or RIGHT we simply reduce or increase facingAngle by rotaionSpeed divided by fps. We also check to see if the facing angle has reached the full extent of a rotation (less than 1 or greater than 360) if it has we set it to the appropriate reset angle. However, note the very first line of code where we initialize a local variable previousFA to whatever the current value of facingAngle is. We will need this value when we do the rotation math because we use the angle of change when rotating not the actual current angle. Remember how we rotated a point by 180 degrees? This time we will be rotating by tiny fractions of 1 degree for each frame so we need the value for change (facingValue – previousFA). We will see this in action soon. Enter the first part of the update method.

Now we handle what happens when the player is thrusting.

Here we use our heading algorithms to calculate the horizontal and vertical velocities. Remember the important thing about the values returned is the ratio of the two values to each other.

Next, we update the coordinates of each and every point using the newly calculated horizontalVelocity and verticalVelocity. We also multiply by speed to maintain our desired pixels per second and divide by fps for smooth frame rate independent motion.

Now we have moved our points we can rotate them. We declare some local variables tempX and tempY to temporarily hold the values of the rotations. Starting with the point a we subtract the centre coordinates, both x and y from it.

We then rotate these newly acquired object space coordinates and assign the result to our temporary variables. Notice that the angle we pass in is facingAngle - previousFA and is wrapped in the Math.toRadians method.

Then we reassign to the actual point a along with adding back the x and y values held in centre.

So we converted the coordinates to object space, rotated them, then moved them back to world space. We do the same for points b and c then we are done. Add the last part of the update method and you can run the game.

What next?

Soon I will publish another full-game tutorial that uses these techniques. If we have dozens of rotating game objects then we will need a smarter way of handling them, probably an array. Also, it is worth noting that Math.sin and Math.cos are computationally expensive. So, if we kept adding more objects then eventually the game would begin to lag. One simple solution to this is to create look-up tables for the values of sine and cosine. This could be just an array with the returned values of sine and cosine perhaps for all the whole numbers 1 through 360. We could then stop calling Math.toRadian, Math.cos and Math.sin just do something like this,  arrayCOS[facingAngle- previousFA] instead.

I hope you enjoyed the tutorial please comment if you liked it or if you didn’t and if you have any thoughts about it. Also, I am trying to get followers/friends on Facebook and would really appreciate it if you can like or follow Game Code School.

patreon