First, I want to say that my blog posts for Days 1 through 3 will be a more technical and in-depth description of what I accomplished each day. To read about what the game is or what we wanted to do on the whole then you should read the blog posts on the current build page here.

We started on Day 1 at about 4pm and went to sleep at about 3am, giving us about 11 hours to get started and get as far as we could. I managed to accomplish three main milestones on Day 1:

  • A (faked) buoyancy model
  • Dynamic water generation
  • Basic 2D sprite displaying

 

The Buoyancy Model

I needed to create a buoyancy model for Cargo Chaos that was going to look semi-realistic, wasn’t going to take long to program (to not take up too much of the 48 hours) and would hopefully not require much processing power as we were aiming for a mobile game. The solution I came up with looks realistic enough when moving over most kinds of waves (it kind of freaks out when it tries to go over waves with high frequencies), only took a couple of hours to complete and so far it hasn’t brought my test Android phone (a Google Nexus One) to its knees.

Before we started this challenge I had been playing around with the SpringJoints in Unity for The Establishment and had the idea that if I attached the boat to the current location on the wave with a number of SpringJoints and play with some properties, I might be able to get the boat to stay above the waves and bob around semi-realistically.

So, I threw together a prototype using cubes within Unity to test my theory which you can see in Image 1 below. This prototype required three main objects:

  1. A blue cube to represent the water.
  2. A black cube to represent the boat. This boat is set to not physically collide with the water using Unity’s layers.
  3. One or more red cubes used for SpringJoint connection points. These cubes are set to not physically collide with the water or the boat using Unity’s layers. In my initial prototype, I used two connection points, one at the front and one at the back of the ship. However, during the testing of the system, I added a third point to the middle to help the ship to be more buoyant at the apex of a wave, instead of just having the centre of the ship under water.

Image 1

Image 1: The prototype of a ship floating on flat water.

The basic idea behind how this system works is that the red cubes have locked movement in the X and Z axes and locked in all axes for rotation, i.e. they can only move up and down, and they always sit at the top of the wave. Then you simply attach the back red cube to the back of the ship with a SpringJoint and do the same for the front. And now you have the basis for a ship that follows the waves in a springy fashion, simulating bobbing around in the water. The thing you have to remember is to lock the movement and rotation axes of the water and the ship like you would for all other 2D sprites, by locking movement in the Z axis and rotation for the X and Y axes.

As I said, the red cubes effectively float on the surface of the wave so the final technical detail you need to finish this system is how you get those red cubes to be at the right Y value. There are a number of different ways you could do this but I chose to simply Raycast from above the water, downwards at the X position of the red cube. This Raycast should be set to only be able to hit the water using a LayerMask which only includes the water layer. This Raycast hit will find the required Y value to which I then set the red cube’s position. With all that set up, you can move and rotate your water any way you want and your boat should stick to it properly, like in the following image where I have rotated the water cube by 30 degrees.

Image 2

Image 2: The prototype of a ship floating on water at a 30 degree incline.

 

Dynamic Water Generation

Creating a single wave mesh that the user sees was quite the easy process. In my solution, a single wave is based on a sine wave with a given amplitude and frequency. So, if you take a number of different sine waves, place them next to each other and blend between them at the joins you get a nice, easy, varied, and if you want it to be, random ocean.

To create the 2D ocean plane that the user sees like in Image 3, I simply created a list of 2D points along a sine wave, at configurable intervals and for a configurable length. To that list I also added two points below this wave, one at the start X position and one at the end X position, which determined the height of the mesh. I then passed these points into a Triangulator script (I used the example one found on the Unify Community website which you can download here) which returns a set of triangles I then used to create the mesh. This gave me both the vertices and the triangles that I needed to create a Mesh in Unity. Then all I needed to do to put it all together was create a new GameObject and give it a MeshFilter and a MeshRenderer. I then assigned this new Mesh to it and gave it a blue material and giving me some nice wavy water.

Image 3

Image 3: An example wave with the wireframe showing its 203 vertices and 201 triangles.

But remembering that Unity is inherently a 3D engine with 3D physics, having the top, curved edge of a 2D plane for objects to collide with won’t work well so we also have to create a 3D collider for this new wave. To do this, I extruded the existing vertices of the original 2D mesh by duplicating them, increasing their Z value and adding them to the end of a new list of vertices that already includes the original vertices. I created the triangles that make up the top of the curve with the following code (which I found here and modified):

                                List<int> triangles = new List<int>();

                                int N = originalVertices.Length;

                                int i1, i2, i3, i4;

                                for (i1 = 0; i1 < N; i1++) {

                                                i2 = (i1 + 1) % N;

                                                i3 = i1 + N;

                                                i4 = i2 + N;

 

                                                triangles.Add(i1);

                                                triangles.Add(i3);

                                                triangles.Add(i4);

 

                                                triangles.Add(i1);

                                                triangles.Add(i4);

                                                triangles.Add(i2);

                                }

This code creates two triangles for every two adjacent vertices and their corresponding extruded vertices. I then used these vertices and triangles to create a new Mesh. I created a new GameObject for this Collider that I made a child of the GameObject with the Renderer on it because it seemed easier and quicker to deal with than having to have two MeshFilters on one GameObject. After I added a MeshFilter, a MeshCollider and added the new Mesh to the MeshCollider, you get a MeshCollider you can use in your game like the example in the following image.

Image 4

Image 4: The generated collider for the wave shown in Image 3.

The next challenge I had to tackle was the one of creating multiple wave meshes with different amplitudes and frequencies and having them blend together seamlessly. My solution isn’t perfect and could use some more work but it works rather well if you are careful in choosing your amplitude and frequency values. Obviously this won’t fly for when we choose to do endless, random levels so I plan to give it a revisit.

The solution I came up with was to start blending between the current waves values and the next wave’s values after a certain distance to the changeover point (only if the next wave has different attributes of course). To take an example, let’s say I set the blending start distance to 10 units. At 10 units from the end of the current wave mesh, I take 100% of the current wave’s value and 0% of the next wave’s value. At 9 units, I take 90% of the current wave’s value and 10% of the next wave’s value. It continues in this way until the end of the current wave and if the blending start distance is great enough and the difference in values between the two waves isn’t too great, the blending transition should be pretty smooth.

The final challenge with the water was to make the boat move along it. This turned out to be rather simple as all I ended up doing was making all the water meshes scroll to the left, giving the illusion to the player that the boat is moving along the water to the right.

 

2D Sprites

To display all the 2D sprites that Ed created, we chose to use a Unity add-on created by exDev called ex2D which can be found here. ex2D allowed me to quickly and easily convert Ed’s individual sprite textures to a few texture atlases and to then easily display those sprites on screen. I have found it very easy to use ex2D and because we are using texture atlases, our draw calls are very low.

One important problem to note, which I found out the hard way, is that if your 2D solution supports pixel perfect graphics (like ex2D), then you can’t use that option for in-game objects. The pixel perfect option in ex2D resizes the sprite to match its pixels with Unity units which usually makes the object huge compared to normal game objects. If you then try and do any sort of physics movements with these huge objects (like simply attaching a Rigidbody to it and having it be affected by gravity), they will just move ridiculously slowly. As our game uses physics heavily, this wasn’t an option for game objects (I will probably use them for GUI objects though).

To get around this, I created a size modifying script (which I would have needed to create anyway to support multiple screen resolutions and aspect ratios). Ed designed all of the images to fit into an iPhone 4 screen which has a resolution of 960x640 while in landscape mode. My basic idea was to resize every element to fill up the same percentage of the screen width and position them relative to the top and bottom edges to give them their Y position. If you know the original screen width, the current device’s screen width and the game object’s pixel width then the math is rather simple to resize the objects.

 

Conclusion

Overall, Day 1 was very successful for both Ed and I and by the time we were getting ready to sleep, we could already see the game coming together. We didn’t really run into many problems that stopped our work for very long which was amazing considering how many times we have gotten stuck while working on The Establishment. The only really annoying problem was that the software we had chosen to record our screens would freeze and corrupt our video files if we tried to record for longer than about 1 1/2 hours consecutively. We ended up recording a lot of what we did and will be uploading them to YouTube in the not too distant future. When I have done that, I shall link them here.

Scott