Friday, November 7, 2014

Level Design

For this current sprint, my task was to create a pipeline and tools to design levels so that the designers could then design their own levels for the game. While the task itself wasn't that hard, there are many design decisions that I had to make with the team to ensure the process of building a level be as efficient as it can be. The very first thing I wanted to get solved was borders. This is an underwater game so borders aren't that simple. The bottom of the sea floor is obvious, but there isn't an upper limit. Where does the player stop, a certain depth below sea level, or can they surface and that's the border. While there isn't a good solution for the game yet, we decided on a soft border in which if the player gets too close to the surface, then some force (pressures of water or too much light is bothering) will force them down. Also with that soft border there are some design decisions. How will it force the player down. Does it just add a vector onto the player's trajectory that is so great they are forced down, or does it take control out of the players hand and play an animation as the player swims down to the correct level. I chose the latter as I feel it has the most aesthetic value to it and can give a more logical reason why the player can't swim too close to the surface. I also chose it because it gave me the opportunity to change the architecture of Entity types (Player, Swarm, and Enemies) to be more closely related in terms of assignment and state control. I feel that I may need to change it to the more dynamic approach of forcing the player down, but not taking control away from them. Fortunately, I've added a way to have multiple ways of being able to move the player down so that it is easy to switch based on designers choice or if there is some other choice of the type of soft boundary.

Hard boundaries (moving into a wall) was a lot easier, but I still had to experiment with ways to create hard boundaries in the most efficient way. The initial way I did it was to use a series of rectangle that would act as the collision wall. It would be a series of them, because they could be used to approximate a curved wall since Unity does not have curved lines and it would be too computationally heavy to do collision detection with a spline. While this method did work and is the standard way of doing it, making the rectangles took way too long, was hell trying to scale, rotate, and move each rectangle, and there was a possibility of a gap in the wall potentially creating future, hard to find bugs. I learned of an alternative way using Unity's edge collider. It allows the designer to create a line that can be subdivided into many lines that can be used to approximate the curve. It is the same principle as the rectangles, but it much faster to create as the designer only has to select a midpoint between the two endpoints and move it to where they need it. The only problem is which certain types of collisions in which the object is moving at a great speed. The edge collider has a much smaller room for errors as opposed to the rectangle. This problem doesn't come up to frequently and if there is the possibility of either capping its speed or using a predictive collision to determine if it will hit the edge using discrete steps. This would be much easier than the added buffer that rectangles give especially since the edge collider will cut down the time it will take to set up the walls and it is much easier to fine-tune and fix later on.

The placement of enemies is a very important. An enemy that lies in wait in a corner of the level that is quite away from the player will not only suck up important CPU, but depending their AI will chase the player from across the level. One of the fixes I have for this is by using an enemy trigger. When the designer places an enemy in the level, they can hook the enemy up with a trigger that when activated will create the enemies offscreen and allows the enemy to attack the player saving CPU. The main problem with this is placement of the trigger, especially in a more open-space world. The trigger can only be so big, and it is a rectangle, and creating more than one for the same group of enemies can open up some potential bugs. While it is great in some cases, it is not a catch-all. The other solution, would be to define their behavior if the player is a certain distance away from them. If the enemy can't see them, then they do some default state such as patrol or try to kill each other, and when the player gets close enough they go into their attack state. While this may solve the enemy not going across the level to kill the player, it does have a bunch of enemies that aren't useful taking up CPU. A fix to this would be if they were a certain distance away, then to become disabled so they aren't taking up CPU. This will probably be the best since when the player is far enough away, then they aren't doing anything, and when the player is close enough, but not too close to attack, they are activated and do their default behavior. While it would be nice for the enemies to do their default behavior no matter where the player is, this just isn't feasible in terms of performance. The best bet would to use the trigger where possible and if that doesn't work, then to use the default behaviour if the player is close enough.

Those were the most basic things that I covered so far. There are still some aspect that I haven't talked to anyone else, such as when a level ends, how it decides the next level to go to and where the designer can specify that. The level design is very iterative and will change as we get a better idea how we want our levels to look and feel.

No comments:

Post a Comment