top of page

TRAIN BOB

ROLE

Group Mamber / Development

DESCRIPTION

"Train Bob" is the coursework of CSC8508: Engineering Gaming Solutions within a Team. I developed this game in an 8-member group. I mainly take part in designing the rendering pipeline, some of the gameplay functions, network design and PS5 development.

TIME

2024.1-2024.3

GENRE

Level-Based, Multi-Player Cooperation

PLATFORM

PC, PS5

Grade

Group: 61%, Individual: 76%

Development Notes

​Introduction

This game is the coursework of CSC8508: Engineering Gaming Solution within a Team which require us to develop a completed game based on the knowlegde we learnt on last two courses. The game of our group is called "Train Bob". In the game, there is a train running along the unfinished rail. If the train reaches the end of the rail, the game will be over. So player needs produce rails and connect them to the rails on the ground. Player needs to cut trees and fig rocks to collect the material to produce rails. When player manages to connect the rail with the rails in the destination, the player will win. The game allows multi-player cooperation and is available to play in 

​

It took us 8 weeks to finish this game. During the development, I gained the experience of teamwork. In my group, I also took part in task assigning and managing project progress.

1
3

In this project, I took part in designing the rendering pipeline, some of the gameplay functions, network design and PS5 development. Here's the features I developed in this project.

Features

1. Render Engine

We chose the code base of CSC8503 as the code base of this project. Since the render engine in this code base is quite simple, I decided to use the render engine of my CSC8502 coursework as this project's render engine. I also improved this render engine based on our current code base. Here's the rendering pipeline of this project.

In this rendering pipeline, many things is same as it in CSC8502 like building, sorting object lists, rendering shadow and skybox. The biggest difference is that both forward rendering and deferred rendering are used in this pipeline. Day night cycle is implemented to this game. During the daytime, only a direct light - sunlight will be rendered by forward rendering, while in the night, many point lights will be rendered by deferred rendering. Since then, all the objects need a pair of shader to render. One for forward rendering and one for deferred rendering. So in the "RenderObject", there is a variable called "ShaderGroup". Besides, the contents will be rendered to different FBO in forward rendering and deferred rendering.

Like CSC8502, different obejcts will be rendered in different methods. In rendering, the objects in this project can be divided into four kinds: .obj mesh objects, objects with environment mapping, objects with animation and other common objects.

​

OBJ Loading is also implemented in this project. This process is based on the same library in CSC8502 to load obj meshes. To use this library, I also wrote functions to load in and render the meshes in this project.

Besides, the library used to load in textures in this code base is stbi library, which didn't work well with some of the textures. So we decided to use SOIL library which was used in CSC8502. My group mate loaded the library into this project and I wrote other codes to use this library. The texture loaded in by stbi library is "OGLTexture" class, while the texture loaded in by SOIL is "GLuint" class. So there are two functions to bind the texture to the shader in this project. In this project, diffuse, normal and specular texture are used.

I also wrote the shader to render the objects and lights in this project. One major difference with CSC8502 is that "layout" keyword is used to bind the variables.

​

For animation, I created a new class called "AnimationObject" which has eight variables to save eight different animations can be played by this object, and an "activeAnim" variable that saves the animation that's being played. Different animations will be played when the player holds different keys.

More Code

2. Gameplay

2.1 Loading Models

I took part in models finding and loading. As it is mentioned before that the mesh format availabe in this project is .obj and .msh. But most models found is in .fbx format. So I used a uinty pulg-in called "Mesh Exporter" to convert them into .msh format and load in. I also used one .obj model which is generated by AI.

2.2 Picking up Objects

Like CSC8503, there are many objects can be picked up and dropped in this project. These objects can be axe, pickaxe, plank, stone and so on. Similarly, when it's on the ground, it will be rotating, and it will be above the player when it's picked up. One difference is that a player can carry three of some objects at a time. There is avariable of player called "slot" and "slotNum" which saves which kind of object the player is carrying and how many are them.

More Code

2.3 Drawing Pad

The map of this project is consist of navigation grids like the maze area in CSC8508. The map is based on .txt files. My group mate designed the program to create the map. 

Each grid has a type of what is on in, 0 is empty ground, 2 is for tree, 3 is for rock...

When player tries to drop an object like axe or plank, the object will be dropped behind the player. In case the object is dropped inside the trees or objects, the game will check if the grid behind the player is empty ground or rails. If so, the player is able to drop object. To make it more clear, a pad will be drawn behind the player to show if the player is able to drop an object when player is carrying a certain object. Yellow is for able to drop while red is for not. Besides, if the player is not carrying anything, the pad will be drawn on the centre of the grid the player is in.

​

Similarly, when the player is carrying the rail, he can place the rail in the grid he is in. The pad will be drawn on the centre of the grid the player is in. If the grid the player is in is availabe to place the rail, the pad is yellow, or it is red.

More Code

2.4 Produce Rail

There are three carriages in the train: material carriage, produce carriage and water carriage. The process of producing rail is mainly about the first two carriages. Players need to cut down the tree to collect planks, dig the rock to collect stones and put them into the material carriage. If there are at least one plank and one stone in the material carriage, the produce carriage will start to produce the rail.

More Code

In the Update function of the produce carriage, the program will check if last rail has been produced and if there're enough material in the material carriage. If so, a new rail will start to be produced.

When starting to produce a new rail, a counter will be set. The colour of this carriage will be changing from white to yellow during producing.

​

When the counter reaches 0, the rail is finished producing. The rail will be added to the game as a new game object. Besides, it will also be added to a vector of the rails. The rails will be piling on the produce material. The y position of the new rail is about how many rails are there in the produce carriage. And the carriage is designed to be able to carry 10 rails at most. So if there are already 10 rails in the carriage, the rail cannot be finished producing and new cannot be started to be produced before the player take some rails from the carriage.

​

For material carriage, there are two vectors which hold the planks and stones in the material carriage. The player can load planks and stones to the material carriage. When player loads themto the carriage, they will be added to the relevant vector. And when a new rail is started to be produced, they will be removed from the relevant vectors and be deleted from the world.

2.5 Place Rail

The train is running on the rails, so the player needs to place the rail to keep the train running.

More Code

When player carrying rails presses F, three conditions will be checked to see if the rail can be placed on the grid the player is in.

​

1: Is this grid empty ground? It is an empty ground if its type is 0.

2: Is there a rail near this grid? The grid with a rail onside has type 7, so if any one of the grid's four connected grids has the type 7, there is a rail nearby

3: Is the rail nearby the last rail? The rail can only be connected the last rail of the path. The distance of two centres of the grids is 10. The latest grid with one grid except its connected grids are the grid on its inclined top or bottom, which have a distance of 10*sqrt(2) ≈ 14. So if this grid's distance to the last rail's grid is less than 14 means it's connected to the last rail's grid.

​

When a rail is placed on the grid. The grid's type will become 7 from 0. And new path will be added to the train's path list to keep it running. The next step is to know which direction the new rail is to the last rail. For example, if the last rail is going right and the so is the new rail, nothing will be changed. And if the last rail is going right and the new rail is going up, the last rail's model will be changed to a turning rail to make the game looked more real.

2.6 Robot AI

There is a robot AI in this game who can help player to cut trees and dig rocks. It is based on state machine. When player carrying axe or pickaxe standing nearby the robot and facing at it pressed F. The axe or pickaxe will be sent to the robot. Then the robot will start to follow player. Player can press T to make it start to cut trees when it has axe or dig rocks when it has pickaxe. When it is ordered to cut trees, it will find the nearby trees first. if it managed to find a tree, it will start to cut tree. If not, it will move back to the player. So is digging rocks. And whenever the player presses T, it will move back to player. When it managed to find the player, it will drop whatever tools it has.

When finding the nearest tree, the robot will first sees if there are trees on the grids whose distance to it is less than 43. Then finds the tree which is the nearest to it. If it can't find any trees in a specific time, it will move back to player. The pathfinding alogorithm in this project is A* alogorithm like CSC8503.

Besides, the UI will guide the player how to use the robot. The UI is based on imgui library, which is mainly finished by my group mate. I designed the UI of guiding the player how to use the robot.

More Code

2.7 Managing Levels

When a player finishes the current level, the next level will be loaded. When a new level is loaded. The objects like player, axe, pickaxe and so on will be respawned in the starting position of the next level. And another .txt file will be loaded in to create the game map of the next level. This is finished in the function "InitGameWorld". The game has three levels, and if the player has passed the third level, the game is finished.

More Code

3. Network

This game is also a multi-player cooperation game. So the network is implemented. Like CSC8503, the network system is based on UDP protocol, and the game client, game server, "NetworkObject" and so on are the basic component of it. This game allows four players at most to play together.

​

I designed the UI of choosing server, player will choose if he's about to play as client or server in this interface.

No matter the player chooses to start as server or client, the function "InitGameWorld" will be performed to add the game objects to the game. At this stage, the objects will be spawned underneath the world. If the player chooses to start as server, the objects will be spawned at their starting position. When starting as client, the state of the objects will be updated by network to keep them synchornized with server player.

The state of game objects will be transmitted between the server and client by packets to keep the game synchronized. The state needed to be updated in this project includes position, orientation, scale, colour and so on. And there are many different types of packets that finished all the synchronization between server and clients.

3.1 Full Packet

All the game objects will be updated in the server including the client players' avatar. The state of the game objects will be updated to the client players by full packets. This is very similar to CSC8503.

3.2 Client Packet

As mentioned above, the client players' avater is also updated in server. So the all the information the clients needed to send to server is the states of key buttons (if any key is held or pressed in a frame). The server will update the client players based on the key buttons states received.

When updateing the client player, the program will check the received button states instead of the keyboard states.

3.3 Single Integer Packet

This kind of packet can only contain one integer. In this project, When a the server finds a new client is connected (received a ENet Event whose type is "ENET_EVENT_TYPE_CONNECT"), it will spawn a player character in server firstly, then send a single integer packet (numPacket) to the new connected client to spawn that client player's character in that client. The integer it contains is how many players are there in the game after spawning the new connected player's character. The client player's character will then be updated by full packets and client packets.

3.4 Single Bool Packet

This kind of packet contains only one bool variable, and is used to send message when the players win, lose or restart the game. The code to control when the game will win or lose are only performed in the server. So teh server need to update the information when the game is win or lose. So is when the server player chooses to restart the game.

3.5 Spawn Packet

When the game enters the next level or is restarted, the players are needed to be spawned again. The server player will be respawned by the server. And the clients will send a packet to tell the server to spawn their players, and then the client will also spawn the player in itself. After this, the player in server and it in client can be synchronized by full packets and client packets.

3.6 Update Packet

During the game, some objects like trees being cut or rocks being dug may be removed from the world, and some objects like plank or rails will be added to world. Since the game logic of removing and adding objects is finished in server. The server needs to update these objects to the clients. This is finished by the update packets, which can saves the networkID of the objects needed to be added, the worldID of the objects needed to be removed, and a tag that marks what kind of object is going be added or removed.

​

For example, when a tree is cut, a plank will be added to the world and a tree will be removed from the world. The networkID of the new added plank and the worldID of the removed tree will be written to the update packet. The tag will be set to 1. The client will determine what to do next based on the tag of the received update packet. If the tag is 1, the client will remove the tree with the received worldID and add a plank with the received networkdID so it can be synchronized with the server by full packets.

For example, when a tree is cut, a plank will be added to the world and a tree will be removed from the world. The networkID of the new added plank and the worldID of the removed tree will be written to the update packet. The tag will be set to 1. The client will determine what to do next based on the tag of the received update packet. If the tag is 1, the client will remove the tree with the received worldID and add a plank with the received networkdID so it can be synchronized with the server by full packets.

This is same for some other conditions in this game. These conditions can be removing rock being dug and adding a new stone (tag is 2), removing the plank and stone on the material carriage when starting to produce a new rail (tag is 3), adding a new produced rail (tag is 4), changing the model of the rail to turning rail (tag is 7), removing water being placed with a plank (tag is 8) and removing a disconnected player (tag is 9).

​

Besides, when a client has just joined the game, it will initialize the world as if the level has just started. But the game might have also been played for a time, so some of the objects might have already been removed and some object might have already been added. So this should be synchronized when a new client has just joined the game.

​

The new added objects can only be planks, stones or rails. So when the server finds a new client connected, it will iterate all the planks, stones and rails (excepte initial rails), and send their networkID to the clients by update packet (tag is 5). The client can then add them to the game. And when an object is removed from the world, their networkID will be saved to a vector. The server will send these networkID to the client (tag is 6) and the client will remove the objects according to the received networkID.

3.7 UI

I also designed the UI when playing in multi-player mode based on the UI in single-player mode designed by my group mate.

More Code

4. PS5 Development

After my group mate finished configuring the PS5 development environment, I finished most of the development. First of all, the rendering API of the PS5 is different of it in PC. The PS5 uses AGC instead of OpenGL. So the rendering pipeline and the shaders are also different. There are some models in PC can not be rendered correctly in this rendering engine, and I chenged the models of these objects in PS5.

​

The gameplay logic and physics engine is mostly same as it in PC, I didn't do any big changes to them. The network is not avaliable on PS5, so there's no multi-player mode in PS5. Since PS5 is controlled by the controller instead of mouse and keyboard, the only thing needed to be redesigned here is the buttons mapping.

During developing, I found that the buttons in the controller is too sensitive. It can generate signal for multiple times when I just pressed that button for once. So I designed a function to debounce the buttons.

More Code

Summary

In summary, this project not only integrate the knowledge of CSC8502 and CSC8503, but also developed some new gameplay and new features based on it. There are some improvement can be made to this game. Firstly, more gameplay can be introduced to the game. Like a shop system that sell some upgrade of the train or player, or the save game system that allows player to save and load game. Next, for the network, the multi-player mode is still based on the local host. It can be deployed on a server so it can be played in multiple deveices. Finally, this project just simply remove the models that's not able to be rendered by the renderer of PS5 (most of them are .obj mesh, obejcts with environment mapping or with skeletal animat). More research can be done on this render engine, so the rendering pipeline and shaders can be redesigned to make it capable for these models.

bottom of page