Future Earth

Future Earth is a VR adventure game set in a dystopian future, where the player has to grow trees, fight droids and collect parts. Achieved over 3,000 downloads and 4 stars on SideQuest.


Future Earth

Type

VR Game

Year

2020

Skills Applied

  • VR
  • Game Development
  • Project Management
  • UX / UI

Team

  • Robert Michels (PM)
  • 3 teammates (SFU IAT)

The Task

Future Earth was created as an exercise in designing and developing immersive environments.

With the concept design, we aimed to create a VR adventure game that encourages sustainable behaviors in players. This is achieved by placing the player in a dystopian futuristic environment and giving them the power to radically transform it for the better through gameplay.

future Earth – 3
future Earth – 4
future Earth – 5
future Earth – 6
future Earth – 7
future Earth – 8

The Result

Story

Set in a dystopian future, you are the first human to walk planet earth in a long time.

Your mission objective is to plant and sustain 100 trees. Whether or not humanity will attempt to return to earth hinges upon your success.

Success

Our project won best overall project, best interaction design, project for impact, and best VR/AR in our class.

future Earth – 9
future Earth – 10
future Earth – 11
future Earth – 12
future Earth – 13
future Earth – 14

Process

The project was developed in 4 months by a team of 4. I was the project manager, as well as one of the VR / game designers & developers.

After deciding to create a project for impact with the theme of sustainability, we started to create a game. Our goal was to create a VR game that appeals to players without particular interest in sustainability, to reach a broader audience.

As the PM, I split the concept design into a list of core and bonus features. The core design featured a small game, where players fight rogue robots, collect their parts, and build water filtering technology that helps trees to grow. This core prototype was implemented within the first three months.

After a round of usertesting, we proceed to implement updated features in response to our testing results. These included measures to better communicate the narrative, such as a major update to the level design and the implementation of an aesthetic change as the player plants more trees. We also had time to implement some of our bonus features, which were mostly aesthetic improvements such as the addition of VFX, better models, and multiple collectible parts.

future Earth – 15
future Earth – 16
future Earth – 17
future Earth – 18
future Earth – 19
future Earth – 20
future Earth – hud1
future Earth – hud2
future Earth – hud3
future Earth – hud4

The Code

My programming efforts for this project focussed on the more unusual features of our game, such as spare part collection, item building, UI interactions, story sequencing and more. Another interesting feature I implemented was the trees, which required animations for growth and monitoring of their health based on the available water supply. In order to achieve fine control over the growth behavior, I used a Coroutine, which is also used to control dying trees. Instead of using an Unity animation I implemented smooth growth by affecting scale and rotation with the help of Mathf.SmoothStep() and Mathf.Sin()

TreeLerpSize.cs
// CODE SNIPPET, NOT THE FULL FILE ////Coroutine that controls growth / death animation, colliders, presence and perch targetsIEnumerator TreeLerpSize (float time, bool death){    ////////////// before main loop    float startSize, endSize;    float elapsedTime = 0;    if (death)    {        startSize = 1;        endSize = 0;    } else    {        growing = true;        startSize = 0;        endSize = 1;        //Activate collider        treeCollider.enabled = true;    }    ////////////// Main loop: Handle growth / shrinking    while (elapsedTime < time)    {        //Transition between start and end size (0 to  1)        float curSize = Mathf.SmoothStep(startSize, endSize, (elapsedTime / time));        //Rotations work different. It's best to define the rate of rotation, the sine function is handy for this (between 0, 1, back to 0)        float curRotationRate = Mathf.Sin(Util.mapVal((elapsedTime / time), 0, 1, 0, Mathf.PI));        //Apply size & rotation        treeTransform.localScale = new Vector3(curSize, curSize, curSize);        treeTransform.RotateAround(treeTransform.position, Vector3.up, curRotationRate * turnDirection);        elapsedTime += Time.deltaTime;        yield return new WaitForEndOfFrame();    }    ////////////// after main loop    if (death)    {        Destroy(gameObject);    } else    {        //Activate perch targets once growth complete        Util.FindInactiveChild(gameObject, "perchParent").SetActive(true);        growing = false;        if (dead)        {            StartDeath();        }     }}

View gist on GitHub

One of the interesting changes that resulted from our user tests was the more drastic environment change coupled to player progress. The environment changes as the player plants more trees. In order to achieve the desired emotional effect with the player, we incorporated many variable layers: the skybox, fog, dust particles, water, lighting and post processing. All of these aspects of the environment are interpolated between a start and an end state, by the method SetEnvironment() which I implemented in GameCtrl.cs. For instance, the fog has definitions of its color, start distance and end distance for both the beginning and the end.

SetEnvironment.cs
// CODE SNIPPET, NOT THE FULL FILE ////Sets the mood of the environment (skybox, fog, dust, water). Input a value between 0 (beginning: grim) and 1 (ending: bright).private int startDust = 600;private int endDust = 0;private int startFogLimit = 300;private int endFogLimit = 1250;private int startFog = 0;private int endFog = 50;private void SetEnvironment (float lerp){    lerp = Util.capVal(lerp, 0, 1);    Color horizonCol = Color.Lerp(startColors[1], endColors[1], lerp);    //sky    skyBox.SetColor("_TopColor", Color.Lerp(startColors[0], endColors[0], lerp));    skyBox.SetColor("_HorizonColor", horizonCol);    skyBox.SetColor("_BottomColor", Color.Lerp(startColors[2], endColors[2], lerp));    //fog    RenderSettings.fogColor = horizonCol;    RenderSettings.fogEndDistance = Util.mapVal(lerp, 0, 1, startFogLimit, endFogLimit);    RenderSettings.fogStartDistance = Util.mapVal(lerp, 0, 1, startFog, endFog);    //dust    int dustCount = (int)Mathf.SmoothStep(startDust, endDust, lerp);    dust1.maxParticles = dustCount;    dust2.maxParticles = dustCount / 12;    //water    waterMat.SetColor("_Color", Color.Lerp(waterColors[0], waterColors[1], lerp));    //Post Processing (disabled for mobile)    ppBefore.weight = Util.mapVal(lerp, 0, 1, 1, 0);    ppAfter.weight = Util.mapVal(lerp, 0, 1, 0, .4f);    //sun    sun.intensity = Util.mapVal(lerp, 0, 1, 0.5f, 1.1f);}

View gist on GitHub

This portfolio website was developed with Astro. Copyright © 2026 Robert Michels. All Rights Reserved.
Privacy Policy