Beyond

Beyond is a top-down 2D dungeon-delving twin-stick shooter with a moody aesthetic, in which the player is a young adult that ventures into danger to defeat evil and put their family to rest.

Beyond is released on Steam! Download it here: https://store.steampowered.com/app/1137880/Beyond/

Beyond was also taken to PAX 2019 with the DigiPen booth.

Beyond is a student game developed during my sophomore year at DigiPen over 26 weeks. The team was comprised of 2 designers, 6 programmers, and 5 artists. Beyond was developed in a C++ component based custom engine planned by me, the technical lead. We heavily used RTTR (Real Time Type Reflection for C++) for our engine and editor to serialize data and edit components without manually programming editor code for each component. In this document, I will go over the basics of my engine and the work I did on the project, and then focus on my experience working with a large, cross-disciplinary team as the tech lead.

GameObject/Component Systems

I decided to go with a component-based engine for this project because I felt it was simple to make and easy to understand.  Getting the engine up and running was my main priority for the first few weeks, so I went with a simple design for the core object system.  First, let us go over how a component is defined.

All components in our game derive from an abstract base Component class.  This component class has the virtual member functions Init, Update, and Shutdown that can be changed through polymorphism.  Each component also has a string that contains its name used for reflection.  I will dive deeper into reflection and the editor further down.

The GameObject class contains a vector of Component pointers that belong to the object.  Each of these components are initialized, updated, and shutdown in the GameObject class’s respective Init, Update, and Shutdown calls.  The class also contains a templated function, AddComponent.  This function takes in the name of the component the user would like to add, such as “Transform”.  RTTR would then use this to find and create the asked for component and add it to the component list in the object.  Since some components in our game require another component to be on the object already (ex: PlayerController needs to edit the Transform component to move the player), users would add all the components they wanted, then call Init, initializing all the components in the component list.

The main engine loop then had access to all the objects in the game and updated them each frame.  The Update call would just call each component’s Update call and would poll through all objects currently loaded.

Once this was created, I worked on serializing our objects to JSON so they could be saved and loaded easily without the need to recreate objects for each level.  I heavily used RTTR here and made a generic Serialize function using rapidJson.  This would go through a GameObject and serialize each component and any variables the author specified.  This would then save to a JSON file that could be loaded into the game with a generic Parse function using the same principals as the Serialize function but in reverse.

Editor

I also wrote the level editor for our game. The editor contained a tile editor, object placement, object editing, and prefab saving. I already discussed object serialization above, so I will briefly go over the other two.

The editor used ImGui and RTTR to edit objects on the fly. A user could click on an object in the hierarchy on the left, then edit the components on the right. Any members in a component specified to be edited by the author would show on the right, and the user can change them and save them. You can also add in pre-existing prefabs by clicking file, Add Existing Object, and typing in the name of the json file. Inside the editor, you can click on an object and drag it around with your mouse. This will also select it to edit on the right.

Here, this stump object is currently selected.

Here, this stump object is currently selected.

The tile editor used ImGui and a tileset created by our artists. The tiles were known to be 32x32, so I used ImGui to cut them up and use buttons to show which tile you want to use.

Then, the user can click on the level to add the chosen tile.

Particle System

I also wrote the final particle system for our game. I wanted a very robust particle editor that would add a ton of easily created effects to our game, so I went with a component particle system. This was very similar to our object system, with each particle emitter having a vector of particle “effectors”, or different ways to affect the particle. Then, the emitter would run the update loop for each effector, which would change the way a particle’s movement.

Graphics Engine/Shaders

I also wrote a decent amount of graphics code for our engine. I helped write the main graphics draw loop with the help of one of our other programmers but spent most of my time writing shaders. I wrote the lighting system in our game using a simple point light shader. I used uniforms to send in all the data for the lighting and essentially made everything else darker while lighting up the area around the point. I also implemented bloom in our game by running a gaussian blur around the object to give it a glowing effect.

Team Experience

Lastly, I want to discuss the experience I had working as a lead on such a diverse and large team. This was the largest team I had worked on to date, and I did not know anyone on the team beforehand. I wanted to experience working with people I did not know, as before I had only been on teams with friends.

As the tech lead, I talked to art team constantly. Since we were a custom engine, I was in charge of helping our artists get their assets in game using the editor. Making tools for non-programmers is difficult, but over a couple of iterations we had a system that they could use and understand. I also worked a lot with our art lead on particles, as he had the main vision for how they should look. Him and I created a ton of particle effects together, as he would ask me to make specific particle effectors for the effects he wanted. We made fire particles, smoke particles, enemy shot particles, and much more. We also iterated on the lighting system together, as there were many times where the art team thought that the game was either too dark or too bright. Outside of that, I mainly helped our artists with tech issues and editor problems they encountered throughout our development time.

I talked a lot to the designers about how to improve the editor and the different ideas they had for gameplay. We iterated on many different UI principals for the editor until we came to a finished product that helped their workflow. Then, when it came to gameplay, I would ask the designers what kind of things they needed for gameplay, then designate specific tasks to the rest of the tech team. With our producer, we came up with milestone goals and scheduled out what each programmer would be doing on our team.

While this was our first foray into a cross-disciplinary team, I felt that I gained a lot of experience working with artists and designers. I gained a much better understanding of what artists and designers need in order to get their work into a game, along with learning how to make something better through iteration. As a technical lead, I felt that I did a lot more work than I really should have. I should have talked to the other programmers more to offload some of the work I was doing, but I felt that the gameplay they were doing was also important.

Previous
Previous

Blorb Island

Next
Next

Battle on Big Island