Pitch

A tense survival horror experience set in an infested mansion, where a vulnerable girl and her loyal dog must work together to survive unseen threats. Explore dark, oppressive spaces built around careful navigation, subtle environmental storytelling, and a constant, low-level sense of dread.

Your main tool is not a weapon, but your canine companion. Send your dog ahead to scout unsafe areas, solve environmental puzzles, and reveal invisible entities that would otherwise remain hidden.

Tech Stack

Sense : Beyond Sight was developed on a modified version of Godot Engine 4.7. The whole game is written in GDScript. Alongside the engine, we used Wwise and Sentry.

What I Did

As my end-of-cycle project, I worked with a team of 8 people as Lead Programmer and Project Manager, and also helped with tech art, sound design and the game's art.

The dog and the player

Goal

The goal of this game was a synergy between the dog and the girl. The dog can be called through an action wheel, and can also be controlled through a camera. While controlled, the dog had to be nimble and able to jump, solving puzzles through paths the player can't reach. The player, on the other hand, had to feel heavy and couldn't jump, so the ghosts could catch her easily.

Player state machine in Godot

Development

To code these two characters, I started with a state machine to keep the code separated and easy to change. On the dog's side, the state machine even has a "controlled" state so the game can tell when we are in camera mode.

For the animations, I built an animation tree to blend between animations easily.

The dog has a viewport that displays its camera in the player's hands. I optimized it by disabling the dog's viewport when it isn't being controlled. To optimize further while it is, the game's main viewport drops to a lower resolution to avoid FPS drops.

Dog state machine in Godot

Problems encountered

I had quite a few problems with these two characters. On the player's side, to go faster given the number of states, I originally wrote a single script full of conditions. It ended up blocking us, so I switched to the state machine developed for the dog.

On the dog's side, I had several issues. I first set up a behavior tree with LimboAI, but the plugin required writing almost every task by hand, which would have cost a huge amount of time. On top of that, the behavior tree would have needed dozens of classes for only a few states. Instead, I wrote a simple state machine that switches states dynamically, simulating a behavior tree.

Finally, still on the dog's side, pathfinding caused trouble throughout the project: the dog couldn't always reach the player and got stuck in places. The first fix was making Godot's navigation mesh update at runtime, for example when doors open.

Cinematics and triggers

Goal

As a fairly linear, story-driven game, it needed cinematics. The goal was a modular cinematic system, tied to an equally modular event system.

Development

CinematicPlayer node and event stacks

For these cinematics, I coded a custom node called CinematicPlayer. It simply plays an animation that can, for example, move the camera or characters. Its main strength is that on start it smoothly takes over the player's camera for the cinematic. The cinematic also calls my Event Stacks: through several prebuilt events, they play animations, cinematics, sounds and more without writing any code.

Problems encountered

No issues on this mechanic: I had already built this kind of system in earlier projects (Endless Adventure), so I had the whole logic in mind.

The rope

Goal

The goal of this rope was simply and intuitively letting the dog trigger different actions by pulling it.

Development

Rope node settings

Having already built a physics rope for a previous jam with Cosmic Trip, I had the whole logic in mind. Here I focused on modularity: where my old rope had a single purpose, the idea was to make this one fully modular, for example letting the dog grab one end while anything, physical or not, is attached to the other. A whole signal system then reports when the rope is taut, and more, to trigger functions.

Problems encountered

As in Cosmic Trip, the big challenge with such physics-heavy code is avoiding physics explosions and keeping it stable even under high tension. This time I had no choice but to rewrite everything from scratch, but I wrote it in my Godot Engine addon, so I can reuse it as a prefab in future projects.

Art direction shader

Goal

On this workshop, I also worked as a tech artist, building the post-process shader for our Lead Artist. The goal was to add animated hatching on every object in the game. The hatching had to be more visible in shadows and fade in corners via SSAO. Finally, the player had to stand out from the background with different hatching.

Development

Shader parameters

I went through several approaches to design this shader.

  • First approach: my initial idea was a master shader applied to every asset in the game. I quickly hit its limit, since it was impossible to read the SSAO buffer from a regular material shader.
  • Second approach: I then turned to Godot's Compositor, a new system for post-processing with access to the engine's buffers. After several hours of trial and error, I went back to the old method: a plane in front of the camera.
  • Computing SSAO: I recomputed SSAO directly from the depth, with a visual result quite close to Godot's own.
  • Animating the hatching: I simply offset the UVs with the TIME variable combined with a floating offset, which breaks the linear scrolling effect of the texture.
  • Separating elements (stencil buffer): I needed separate post-process shaders for the player and the environment, while letting some meshes skip the effect entirely. Using stencils, the environment is on pass 0, the player and the dog on pass 1, and elements that ignore the effect on pass 2.

Wwise integration

Goal

As a horror game, it needed good, well-spatialized sound. That's why I decided to integrate Wwise, which I already use in several projects of my portfolio such as Object Wars.

Wwise project

Development

On Sense, I set up a fairly deep integration with RTPCs. The idea was that you can't see the ghost but can hear it coming. First, a fear RTPC rises gradually as you get closer to the ghost. On top of modulating every sound, it makes the game's music more distorted, as two versions of the track crossfade with that RTPC.

Finally, lots of events were set up to trigger sounds for every falling piece of furniture, moving cutlery, and so on.

Project Infos

Current state : Published

Links