CQMF #1 - Custom Obstruction Camera System
Updated: Apr 24, 2021
My most recent project involves the frequent traversal of tight corridors between tall objects, with a top down perspective, and therefore requires a camera system that can actively track what is meant to be seen by the player, and hide anything that might be obstructing that view, all while ensuring that any non-static objects are hidden or seen when they are supposed to be.
The goal of this system is to establish clarity in how this camera system renders key objects (such as enemies or items) of the game visible or not to the player in a way that promotes the feeling of uncertainty or tension in these tighter sections of a given map. The challenge is to set a specific set of rules that can be easily understood, and avoid being confusing enough for the player to ever feel cheated.
The Pieces Of The Puzzle
The objects that I am working with can be broken down in to two types of objects: Obstruction Objects (buildings or other static environmental assets) and Dynamic Objects (Enemies, NPC's or anything that is moving).
Also I am dealing with two different perspectives to determine "vision": Camera View (think of it as an "over-watch drone" hovering above the player character looking down) and the Avatar View (what the actual character model can see from its perspective).
These pieces are held together with use of an Obstruction Manager.
The Avatar View is a mesh that is drawn at runtime and dynamically rotates with the avatar, resizes and splits itself in to smaller sections when moving around Obstruction Objects.
At timed intervals, the view mesh checks for targets (Dynamic Objects or View Targets) within itself by using a Physics Overlap Sphere and then checking the position of any targets found to see if they currently lie within the Avatar View angle. If so, those targets are added to a list of visible targets. This list is cleared at the beginning of each interval. Intervals are set so that the Avatars View is not running on every single frame.
The validity of whether or not an object can be seen from the camera is determined by using raycasts from the camera to a given target. Three raycasts are sent out to check the two sides and center of the given mesh target it is looking for to check if any part of the target object is indeed visible to the camera. At least one of these raycasts must hit the target in order for it to be declared visible.
Dynamic Objects that are currently not visible to the camera check themselves against the camera at slower intervals compared to when they are currently being seen.
These game object prefabs are set up to contain three pieces:
- Base : remains visible at all times to keep a sense of the position of the object
- Obstruction Body : the part of the object that gets hidden, and the objects
- View Target : any number of targets placed in key positions around the object to determine whether the avatars view is being obstructed or not.
The Obstruction Body's material is of a custom transparent shader that also allows for shadows to also be rendered. In a real game setting the View Targets are hidden from the players sight.
As Dynamic Objects move around on their own, they check themselves to see if they are seen by the Camera View at set intervals. There are a few conditions that determine when a Dynamic Object is visible or not. In brief, the Dynamic Object either has to be seen by the Camera View or the Avatar View in order to be visible in the scene.
Don't worry, I'll explain these conditions in more visual detail below!
This manager is what each object within the scene talks to in order to run their checks against the camera or the player avatar. As well, it tracks the currently hidden Obstruction Objects, and hides or reveals them when appropriate.
To better help explain how this system works, I've provided a few scenarios below:
Avatar View, View Target & Camera:
Scenario 1: The player avatar has moved behind an Obstruction Object. The Camera View no longer detects the player model and hides the Obstruction Object blocking the avatar.
Scenario 2: The Avatar View has picked up a View Target that is obstructed from the Camera View. Because of this, we know that we are not able to see what the player avatar should be seeing, so the Obstruction Object is hidden from view.
Scenario 3: The player avatar is behind one obstruction, and the Avatar View has picked up a View Target obstructed from view to the camera by another Obstruction Object. Both Obstruction Objects are rendered invisible. Any number of Obstruction Objects can be hidden at a given time.
Dynamic Objects, Camera View, Avatar View
Scenario 4 - Both the player avatar and the Dynamic Object are seen by the camera and are visible. The Dynamic Object periodically checks itself for visibility to the Camera View. The camera automatically checks for view of the player at set intervals via raycast.
Scenario 5 - The Dynamic Object has moved partially behind an Obstruction Object, but one of the three raycasts from the Camera View is still un-obstructed to the target objects mesh allowing it to remain visible.
Scenario 6 - The Dynamic Object has moved and is now within the Avatar View. As long as it is within the Avatar View it will not perform view checks against the Camera View.
Problem 1 - The Avatar View is looking behind an Obstruction Object > target object is seen, rendering its relative Obstruction Object transparent > Dynamic Object on the other side of the Obstruction Object now has the chance to be seen through the now hidden object.
Solution 1.1 - The Dynamic Object is not inside the players line of sight, so it checks to see if it is being seen by the camera, which is is not, and stays hidden from view.
Solution 1.2 - The Dynamic Object has moved to a location where it is now within the Avatar View. Although it is still hidden by the Obstruction Object from the camera, it meets one of the required conditions and is now visible.
Problem 2 - The Avatar View is looking behind an Obstruction Object > target object is seen rendering its relative Obstruction Object transparent > Avatar View has also picked up a Dynamic Object on the other side of an Obstruction Object but it does not have a clear line of sight to the player avatar OR can be seen by the Camera View.
Solution 2.1 - The Dynamic Object checks to see if it has a clear line of sight to the players avatar. That line is indeed blocked by the now transparent Obstruction Object, and the Dynamic Object renders itself invisible.
Solution 2.2 - The Dynamic Object has moved to a location where it is now visible to two of the Camera View's raycasts. Although it is still within the Avatar View and doesn't have a direct line of sight to the player avatar, it meets at least one condition with the camera and is now rendered visible.
The End Result
Establishing these core concepts for the player is key so that they do not feel cheated by this system, while also keeping these tight corridor sections tense and exciting. This system can also easily be used to hide ceilings in indoor environments, which will be crucial for later on in development.
That about wraps up the overview of how the system works! There are some Unity set up details in there as well, but this is meant to be more of a brief summary so if you've made it this far and have more questions, comments or suggestions I'd love to hear them!
In the future I look forward to sharing more systems being developed for this project, so stay posted!
Until next time,
- Jordan Funk