Plane and Simple
Andri Soone, Jorgen Juurik, Erik Martin Vetemaa
Plane and Simple is a simple plane flying game made with Three.js and Cannon.js that you can play in your browser.
GitHub repo: https://github.com/ndri/plane-and-simple
Play it at: https://andri.io/plane-and-simple
Initial progress
For our project we decided to make a simple base game that we could upgrade over the course of the semester. The base consisted of a simple plane model, environment, basic self-implemented physics.
The Plane Model
Initially, the plane model was made out of 3 boxes, so we could focus on the physics and gameplay.
Later, more boxes were added to the plane to represent the moving parts: the propeller, ailerons, elevators and rudder.
Finally, a proper 3D plane model was made in Blender and imported to the game. It is based on a P-51 Mustang. It also has moving parts that demonstrate the plane's movement.
Procedural environment
At first we planned to make an infinitely generated world, but it proved to be quite difficult to generate new chunks of land without lag, so we decided to make an island instead. An island is great, because it can be all generated at once, without adding edges to the world.
The procedural terrain is generated using perlin noise (https://github.com/josephg/noisejs). To create interesting mountain ridges and to give roughness to the terrain, we stacked 5 layers of perlin noise, with varying levels of detail. (see image below)
Using fancy trigonometry, the terrain was made gradually lower from the center point of the world, so it looks like an island. To make it resemble a volcano, the center of the island was lifted higher.
Some very simple clouds and trees were also added to help navigating. Tree density is set by terrain height and user input. Perlin noise is used to make patches of trees. Threejs lightning and shadow camera was implemented to create shadows.
Controls
The controls of the plane are based on the default keyboard plane controls in GTA San Andreas.
acceleration/deceleration | w/s |
---|---|
roll | left/right |
pitch | up/down |
yaw | q/e |
reset position | space |
For more precise input, a gamepad can be used to control the plane.
throttle | left stick up/down |
---|---|
roll | right stick left/right |
pitch | right stick up/down |
yaw | left stick left/right |
All of these controls can be changed in the settings.
Physics
To make flying the plane feel like actually flying a plane, we needed to implement some sort of physics.
Initially, we made the plane move forward based on a speed variable. Holding the W-key increased the speed and releasing it slowed it down in order to simulate drag. Pressing the arrows or Q and E rotated the plane on all 3 axes. If the plane was moving too slow and "was not generating enough lift", it would be pulled towards the ground. The plane would also speed up and slow down based on how much it was facing down or up respectively. This actually ended up to be a smooth flying experience as long as there was no interaction with the environment.
The plane needed to react to the environment as well. We used a ray tracing algorithm for detecting collisions and it worked quite well. However, the problem was not collision detection, but it was reacting once collision was detected. The way the physics were set up, the best solution we had was to simply stop the plane when it hit something. This did not work well. Imagine clipping a branch with the edge of a plane and it comes to a dead stop and starts falling down. We needed something better.
We decided to switch to an actual physics engine and went with Cannon.js, as it seemed to be the most popular one. This made collisions work a lot better and even moved the plane when it hit something. However, moving the plane based on user input was an even bigger challenge. If we give the plane any linear damping or inertia, it keeps moving in that direction even after it rotates away from it. This is not how a plane flies. We experimented with a bunch of ways to fix this, but never really accomplished anything.
We ended up just basically removing the inertia. As long as the plane is moving, it feels like proper flying and collisions work quite well. However, letting go of the throttle brings it to an almost dead stop. This is not ideal and the plane does not behave like a real plane would, but it is the best we could come up with.
Objective
To make it less than just a flying simulator more like an actual game, we needed an objective. For that, we added yellow rings in the sky that the plane can fly through. Each time a ring is flown through, a new one spawns nearby and the player is given a point for which there is a counter at the top left. There is also a semitransparent preview ring to show where the next one will spawn.
Settings
There are many factors and constants that change how the game operates. For example, how fast the plane flies, how fast it turns, how many trees should be generated, what keys interact with the plane and so on. All of these can be changed in the settings menu, which can be accessed either upon inital launch or by pressing escape while playing and clicking on the settings button.
Since the environment is created using noise, the user can input a seed based on which it is generated. The user can also change the world size and opt to use shadows, based on how much their computer can withstand.
Summary
Making a 3D browser game turned out to be quite challenging, but also fun. Three.js and Cannon.js are excellent frameworks with extensive documentations that made the whole process user-friendly and enjoyable.
Deciding to use Three.js and making it a browser game instead of using a game engine was a great choice. Normally bothersome features like menus and text input were made easier, since we could simply use HTML for them. Also, gamepad input is already built into every browser and required almost no work to get running.
Most importantly, we can share the project simply by sending the link to our friends. There is no installation process and it works on every platform. You could even run it on a phone, but as of right now there is no touch or accelerometer input implemented.