In this project, we work on a non-euclidean object. We will help the user to better understand the complex geometry behind the Klein bottle, by enabling him to explore it by themself. In the beginning, we will test our implementation on a donut to work out the flaws and get the basics, like moving and gravity right. The gaming idea behind all of this is, that the player has to find keys that are located all over the world. As a bit more motivation to explore the world the player is constantly followed by an enemy that can kill him.
To understand how the worlds look like and where you can go, and especially where not, it helped us to fold them step by step. The first world, a simple torus, is achieved the easiest way. You simply take a rectangle and glue the left and right sides together. So you get a ring. Then you take the ring, and again just glue the left and right border together and there you have a donut. The second world, the Klein bottle, is achieved almost the same way, but instead of gluing both sides simply together, you invert one gluing ledge. This way you get one side as a normal ring, and one side inverted as a Moebius strip. The object you get is not fitting in the three-dimensional euclidean space, so you have to cheat a little to make it work. The trick is to make the object go through itself, so one outside and inside can be connected. Now you could take this even further by making both sides of your rectangle a Moebius strip. This way you would get Boys surface, which goes through itself in more than one spot, but for this project, we will stay with the first two worlds.
The first step towards a working game was to create a player and make him listen to basic commands like moving around and turning the camera. It was kind of easy to figure out because there are tons of tutorials on Youtube about it. The next a little bigger hurdle was to adjust the players' alignment to the game world. On a flat world, it would be no problem, even on a not all even surface, it can be solved by adding gravity towards the player's feed till he hits the ground. But as our gameworlds had a little more curves, the player needs orientation all the time, so his gravity would not pull him out of the world. Our idea was to manage it similar to a sphere, using a central point and align the player on the ray from the center through the point he is standing on. As we tried to adapt this to the torus world, it came out pretty quick, that it will not work propper on this world, and not even a little on the others. This was kind of a big problem, but luckily unity offers a method to give back the normal of a point on any surface, which was exactly what we needed. So we could make the player always stand straight to the ground, no matter what form the world has. It got a little complicated to combine the rotation of the camera initialized by the mouse and the rotation of the player initialized by the ground, but using quaternions for directions handled the problem with their easier way to combine them.
Once we got the basic movement figured out we began working on the game world.
It took some time and in the end a good thread on StackExchange until
we came up with a feasible solution for the Klein bottle creation in Blender.
We used the Bezier curve, adjusted the radius, and converted it to a mesh.
In the final step, we closed the gap with the bridge loop function.
The only problem with this solution was, that the mesh,
once imported into Unity left a hole in the middle of our bottle [Fig.1].
This was unacceptable and halted the process for quite some time.
We tried to circumvent this issue with the idea to cut the bottle in half and
teleport the player from one side to the other every time he would cross the edge.
But this solution would have come with some other challenges that seemed even harder to overcome.
In the end, we somehow solved the problem.
Our solution was that we recalculated the normals on the mesh, merged all vertices by distance,
cut the small tube to match the height of the large one [Fig.2], and closed the gap relatively flat.
All this lead to a Klein bottle that looked nice [Fig.3],
and would work with our "gravity" system.
The Problem this Klein bottle has was, that the spot where the surface permeates itself, has a real contact spot, where the player could touch it like a wall. But this spot exists just to fit the object in our three-dimensional space, so we had to find a way to forbid the player to make any contact with this special intersection. Our approach uses portals, that simply move the player to the other side of the wall, so it seems that there is nothing in his way. After thinking about different shapes of the portal, it seemed best to build a room with eight planes on each side and central management, that listens where the player enters, searches the right exit, and moves him there. There were some complications, for example, the execution order of the different listeners for the portals, which caused errors, because if the management script came too late, they could not find it. But some hours in the unity documentation later we found the submenu where you can adjust even that. So we finally had a world, where you can move almost flawlessly.