Skip to main content

Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

DH2650 Game Dev Journey Weeks 8-9, Final Demo

With the new architecture ready in week seven and a clear definition of the game loop and backstory, we focused on building the Final Demo during weeks 8 and 9. I used the grey-box prototype on Week 7 to create a list of TODOs so each team member could pick what to work on.

image.png

The implementation went smoothly, not without some learnings I want to share. As always, I strive to make this journal as helpful as possible for dev venturing into game development for the first time.

🚀 Keep a LEAN Development approach

My years in consulting taught me that keeping a constant pace of deployments helps the team gauge the real effort required to release new features and get real-time feedback soon. Thus, we agreed to ship a new demo with fully texturized levels to get user feedback about the look and feel. We went after a “PSX”-low poly style, with low-tech models and textures to create a retro-futuristic vibe. We took inspiration from Half-life and Quake.

image.png

It was no surprise that we received a lot of feedback from friends, family, and team members. The methodology, publishing the new prototype on Itch, and having the team go through it and document each bug were effective and efficient ways to do game QA.

image.png

Among the many tasks each of us implemented, I enjoyed working on the last level and the main menu, which involved diegetic GUI, level transitions, and a fairly realistic elevator ride effect. Here are some highlights of those features:

🗺️ The diegetic interface of the area map

image.png

Diegetic UI refers to interfaces that become part of the in-game world, and both the character and the player interact, keeping the player immersed in the narrative. Dead Space is a fantastic reference for how to include gameplay stats and information inside the narrative. We decided to use this feature to give my insight into the character’s back story, his daughters, and the size of the facility he was trying to escape from.

image.png

Following our architecture rules, I created two new classes to control the map. The class makes changes to the map’s display using render materials. You can find the detailed implementation at MapScreenController.cs. Then, a set of game objects with a custom component MapInteractable, use UnityEvents to trigger the MapScreenController methods that changes the map’s materials.

MapScreenController.cs code snippet

[SerializeField] private Material[] m_screenMaterials;
private MeshRenderer m_meshRenderer;

m_meshRenderer = GetComponent<MeshRenderer>();


private void UpdateMeshScreenMaterial(int index)
{
  m_currentScreenMaterial = m_screenMaterials[index];
  Material[] materials = m_meshRenderer.materials;
  materials[m_screenIndexInMaterials] = m_currentScreenMaterial;
  m_meshRenderer.materials = materials;
  Debug.Log(m_meshRenderer);
  Debug.Log("Currently at screen:" + m_screenMaterials[m_currentScreen]);
}

public void GoBackScreen(){...}
public void CloseScreen(){...}
public void SetScreen(int screenIndex){...}

Thanks to NooИ’s clear architecture, I was able to implement the components while keeping a consistent and readable code. I could have also used in-world canvases instead of materials, but as a learning exercise, it was worth it. If the map had been curved, the materials would have been the way to go.

🗺️ Creating an elevator ride simulation with Unity’s state machine

We wanted to finish the game by giving a hint that the character was on a new quest to rescue his daughter. Thus, looking for a way to go down into the facility after seeing the map seemed plausible, hence the elevator. The straightforward approach would have been creating an elevator system, but the beauty of video games is that simple solutions can create a perception of reality. Therefore, instead of moving the elevator with the player, I added windows to the cabin and moved the tunnel outside from bottom to top.

image.png

The Animator.Play() allowed me to run the “opening doors” animation if the current animation clip was different from the “opening doors.” That last validation avoids restarting the clip halfway, creating a glitch effect of the door restating without the animation having finished.

ElevatorDoorController.cs code snippet


m_animator = GetComponent<Animator>();
//..

public void OpenDoors()
 {
   //Checks if the current state is the same as the openingAnimation
   if (m_animator == null) return;
   if (m_animator.GetCurrentAnimatorClipInfo(0)[0].clip.name == m_openingAnimationClip.name) return;
   m_animator.Play(m_openingAnimationClip.name, 0, 0.0f);
   m_animator.speed = 1;
 }

Finally, to avoid disrupting the game flow, I added the credits on the tunnel, concluding the game smoothly.

💨 Smooth transitions between levels to preserve immersion

I implemented a Singleton SceneTransitionManager to handle smooth fade-in and fade-out transitions between levels.

public class SceneTransitionManager : MonoBehaviour
{
/* more code */
public void FadeIn()
{
  if (m_fadingCanvas == null) Debug.LogError("The Fading Canvas is missing");
  m_fadingCanvas.gameObject.SetActive(true);
  if (m_transitionsAnimator) m_transitionsAnimator.Play(m_fadeIn.name, 0, 0.0f);
}

public void FadeOut()
{
  if (m_transitionsAnimator) m_transitionsAnimator.Play(m_fadeOut.name, 0, 0.0f);
}

The lift animation moved a trigger collider to tell the game when it was time to load the next scene. A component in that collider called the FadeOut() method from the singleton Instance of the SceneTransitionManager, starting the fading-out of the screen.

if (SceneTransitionManager.Instance != null) SceneTransitionManager.Instance.FadeOut(sceneToLoad);

Using the StateMachineBehavior, I checked for the moment the fade-out was finished to move to the next scene.

FadingOutState.cs code snippet

public class FadingOutState : StateMachineBehaviour
{
 override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
 {
   if (SceneTransitionManager.Instance == null) return;
   if (stateInfo.normalizedTime > 1) SceneTransitionManager.Instance.NextScene();
 }
}

🎰 Diegetic UI

I realized the map in-game screen had a lot of potential to be used as the main menu GUI. My assumption was that presenting a diegetic menu from the beginning would be a hint to the player that similar in-game screens (like the map on the fourth level) might be interactive. The dietetic main menu is controlled by a UIDiegeticMainMenuManager.cs component.

The menu’s taxonomy keeps a simple information architecture consisting of the following sections: image.png

  • (1) New Game that restarts the game
  • (2) Load Game that enables the user to access any level depending on their progress
  • (3) Controls which explain the input system and adjust mouse sensitivity and volume
  • (4) Extras that hold information about the backstory, the team, and the credits to the third-party assets.

There are many other things I could discuss from this experience, and I will soon share an overall reflection on the process.

Support this post

Did you like this post? Tell us

Leave a comment

Log in with your itch.io account to leave a comment.