Blogger Templates

Tuesday, December 12, 2017


Graphics (∞ of ∞) The Game

Posted in ,
EAE 6320-001
It was an awesome learning experience building individual graphics systems like meshes, textures, sprites, effects, asset build pipeline and architecturing them. In this write up, I will carry forward all those learning to make a cool video game. That way, based on my game requirement, I can reuse the existing system to build the whole game loop.

The game idea
It’s always a good practise to solidify the game idea before getting into implementation as that would save a lot of time from rework. So I started by thinking about a planet defender game where a space shuttle will protect earth from incoming projectiles. Having done some of the concept, the top down graphics did not appeal me much. Since I was still ideating, it's easy for me to jump between ideas and I won’t lose anything. Like the usual software development saying goes “If you are failing, fail faster” The next idea I came up with was a car game that can work like an infinite runner by clashing through some obstacles. Since I had already made some assets for the previous project using the car and planets, it was easy for me to visualize how the game can come and I was confident that the game experience can be made really better. Seeing a 3D model closely in the game window fascinated me and doing an infinite runner style game would allow me to render multiple 3D objects close to the screen at a high pace.

Architectural Changes
After thinking a while, I realized I would end up with many game objects to complete this game. With that setup, my existing system which relied on vector and vector index to access each game object was fragile and error prone. To get rid of this index, I need to come up with a key value pair setup like a map. So I replaced my vector logic with a map based logic and each gameObject will have its own name and that name will be used as a key to access the gameobject in a map.

The Infinite Loop
In most games, the platform will be procedurally generated to give an infinite running experience. I thought about this approach first and realized that this could complicate my implementation of maintaining all the game object offsets relative to the new position. To solve this, the approach I took was to give an artificial moving experience by having the player car to be at one position and moving the other game objects relative to the player car. This motion of objects will be reset after a certain threshold and will start from the same place where it originated and keep doing its motion in a loop. Once I got the loop working for the tree, I kept adding other objects like house, mountains, road strips and all possible bear types. My game system was capable of handling large game objects with ease. If you are using Unity or Unreal, I would highly recommend the first approach for infinite running experience.

More environment objects
Nowadays I am getting used to creating quick assets using Maya. The trees and mountains you are seeing in this game were vertex painted in maya and then imported into the game. I also reused some of the old assets I was using and took some additional models from turbosquid. For instance, I kept the planets to be seen from this planet as you drive through a highway. These planets also have a subtle rotation which makes the game world look good. Most of the existing game architecture design came handy when I had to create all these environment objects through a single wrapper representation called the gameObject which support mesh and texture rendering.

Enemies and it’s Collision
The enemies in this game are basically the bears. The white polar bears are allies and will reduce our score index if we kill it. Our score index will climb up when I hit an enemy bear. I achieved the detection of hit through a very simple collision logic. I wrote a anonymous namespace method PerformCollision and CheckCollision. CheckCollision will basically tell me if the two objects are in an accepted proximity. PerformCollision is built on top of the CheckCollision and it can work only when CheckCollision evaluates to true. For our game, PerformCollision will do the role of resetting the game object to the start of its loop on successful collision. Since this class is more related to graphics and code architecture, I spent little time on building a complete collision system. An ideal way to solve this is to implement the separating axis theorem to determine if two objects collide with each other.

The NOS Mode
The nos mode experience is similar to using nitrous oxide in fast and furious movies. Whenever the up arrow is hit, I simply add an extra offset to all of the moving environment objects. That extra offset will give an experience as if you are moving fast. To make it more intuitive, I also move the camera backwards to make it look as if the car is plummeting in. This camera movement will be reset whenever the player do not press the up arrow key. I thought this was interesting as I could pace the car’s speed according to the will of the player.

Game UI
I added couple of UI widgets to give a consistent experience for the player to jump start with the game. This includes the intro title game which gives a base idea to the player about the game followed by the narrative screen which describes the mission from the commander to the sergeant. This will help the player understand that he is in a different planet than that of earth; and the white polar bear are allies and not to be harmed. I also added an end game screen which gives a positive indication on completion of level. For our game, we are relying on 20 bear hits as the win state.

Game Score
The game score is calculated by each successful mutated bear hit. For every new successful hit, we will add 1 to the existing value. At the time of this writing, I did not have an elegant system to show numbers, So I literally created image png’s representing 0 to 9. Since these images are added to the start of the textureVector, it's easy for me to access the individual digits and show its equivalent texture from texture vector.

Final Thoughts on Good coding
I am a person who believes in design driven engineering. There are two kinds of programmers to my understanding, one who wants to get the task done in the least amount of time and get it working and the other one who spends some time in thinking about how the system would interface in future and with other system. I have always found good code with the second style of programming as I have found their code to be more readable and scalable. If the code is not scalable, every new change feature request would eventually make the code look like a spaghetti and be not useful to anyone. This class has definitely taught me how to jump start in an existing code base and figure out why a code is written like that. In most cases, whenever we join a new company, its very rare that we will get to work on a project from scratch rather we will have to understand an existing code base. I think I learnt how to decipher existing code and architecture good code from this class and applied those learning on my thesis project and other areas as well. For example, whenever I am tasked with a feature, I always think about how the feature is used in game and what is the expected experience and what is the future scope. Once I have that clarity, I use some judgement to build systems that are scalable and can support that feature and enable designers to plug and play values(Data driven systems). There could be cases where I decide to get an hackish implementation in if the time is really really less but it’s good to leave notes there as to why that was done and what refactoring is required. This could help future engineers understand the intent of the usage and arrive at a better refactoring.

Final Thoughts on Good Design Vs Bad Design
Good designed systems/software are the ones that are less error prone, highly readable, and easily modifiable. Everything is opposite when it comes to bad design and from my personal experience, I would highly recommend to think of a good design before jumping into code. For example, when I was learning AI in unreal, to implement an AI mechanic, me and another AI programmer kept working on the same behaviour tree and it became difficult for both of us to work simultaneously. The behaviour tree kept growing such that it became difficult to trace its flow. This happened because of poor design systems and to solve this, I built an emotion system that uses data driven system and has a design pattern that all systems can adhere to. Now the behaviour tree was broken into individual pieces and it's easy for me and the other AI programmer to work parallely. We saved a lot of time and we made meaningful design decisions with a good design and with bad design, it just hindered our progress.

Car Movement
Right Arrow - Move the 3D game object to the right.
Left Arrow - Move the 3D game object to the left.
Up Arrow - Move forward with NOS mode.

Enter to skip the title screen. Space to skip the narrative screen.
Camera Movement
A - Rotate towards the left side
D - Rotate towards the right side
Q - Rotate Upwards
E - Rotate Downwards

Check out the game via this