General information

Date completed June 2019
Role in team Developer
Environment Unity 2018.3.0f2
Language C#

Description

The Light Of My Memory is a game I developed with a team of 6. It’s a narrative adventure game about a boy, Peter, whose mother has died at the hands of his father. Everything that happens is inside the mind of Peter. The light in the game represents his mother, and he does all he can to protect his mother in this fictional world, the way he could not in the real world.

Monster behaviour

In the game, there are monsters (representations of Peter’s father) that will try to attack you . These monsters had to have multiple different types of behaviours. For this, I created a Behaviour Tree that was connected to an Animation Controller. The Animations were triggered by the Behaviour Tree, and in turn, at certain points in the animation, information in the Behaviour Tree was updated.

Since I was working in a team with a Designer, I decided I should make editing the monster behaviour as easy as possible. I implemented a ScriptableObject that the designer could use to change all aspects of the behaviour in a matter of seconds. The monsters had different stages of anger, which were triggered by sound. I also made sure to make this part adjustable, so the designer had free range in editing how much noise has to be made until the monster goes to the next stage of anger.

The mechanics

The way the player avoids being killed by the monsters, is by using Peter’s shadow against them. The monsters are only scared of beings bigger than them. Peter, sadly, is much smaller. But he has figured out a trick to get through; if he positions the light in a certain way, he can make his shadow huge. The monsters will be scared by the shadow, and flee. To calculate the size of the shadow, I raycast from multiple positions on Peter’s body to the exact opposite of the light. I then use the hit information to calculate the size and position of the shadow.

/// <summary>
    /// Calculates the positions the shadow falls
    /// </summary>
    private void ShadowBehaviour() {
        int count = 0;

        //Initialize closest and furthest Vector positions to keep track of shadow size
        Vector3 closest = Vector3.positiveInfinity;
        float closestPointDistance = float.PositiveInfinity;
        Vector3 furthest = Vector3.zero;
        float furthestPointDistance = float.NegativeInfinity;
        Vector3 average = Vector3.zero;

        for (int i = 0; i &lt; PlayerSkeletonParts.Count; i++) { //For each part of the skeleton
            var heading = PlayerSkeletonParts[i].position - light.transform.position; 
            var distance = heading.magnitude; //Calculate the distance from the light to the skeleton part
            var direction = heading / distance;
            RaycastHit hit;
            if (distance &lt; light.intensity * lightRange &amp;&amp; Physics.Raycast(PlayerSkeletonParts[i].position, direction, out hit, light.intensity * lightRange - distance)) { //Raycast from the position, directly away from the light
                //Calculate the hit distance
                Vector3 headingToPoint = hit.point - PlayerSkeleton.transform.position;
                float distancePoint = headingToPoint.sqrMagnitude;

                //Update closest and furthest Vector positions
                if (distancePoint  furthestPointDistance) {
                    furthestPointDistance = distancePoint;
                    furthest = hit.point;
                }

                ScareMonstersUnderShadow(hit.collider); //Check whether the collider hit is a monster that should be scared when touched by the player shadow
                average += hit.point; //Add the hit point to the average position
                count++;

                if (ShowDebugLines) 
                    Debug.DrawRay(PlayerSkeletonParts[i].position, direction * 100.0f);
            }
        }

        if (count &gt; 0) { //If the shadow reaches at least one point in the level
            AveragePos = average / count; //Calculate the average position of the shadow
            ClosestPointShadow = Mathf.Sqrt(closestPointDistance);
            FurthestPointShadow = Mathf.Sqrt(furthestPointDistance);
            SizeShadow = FurthestPointShadow - ClosestPointShadow; //Calculate the size of the shadow
            ShadowFound = true;
        }
        else
            ShadowFound = false;
    }

The Light Of My Memory Gameplay