Project description
Signalparadox is about Livia Skye who is a military-trained woman in her mid-late 20’s. At the start of the game, Livia finds herself in a room with cryogenic sleeping pods where all the other pods are empty. Livia Skye discovers a ship with it’s crew being wiped and aliens wreaking havoc. Livia makes her way through the ship and finally reaches the escape pods.
- Sci-fi adventure/thriller
- Puzzle solving
- Unique sneak system
Echolocation

We wanted a realisitc soundsystem to make the game more alive and intresting for the sneaking mechanic, so I implemented a echolocation system where the player transmit a signal based on how the player is playing.
The Player and the Distraction granade is both using this script and transmitting a signal. The player has a dynamic system where the strength is based on the movement from the player. The granade has a constant signal. This system is really modular but it's not flawless if the transmitter frequency is set to high this system is not that perfomace light as recomended so I implemented a frequency attribute.
using UnityEngine;
namespace EchoLocation
{
public class EchoLocationTransmitter : MonoBehaviour
{
[SerializeField] private bool debugModeOn, debugTestSoundOn;
[SerializeField] [Range(1,1000)] private int debugXResolution, debugYResolution, debugMaxBounces;
[SerializeField] [Range(0f,1f)] private float debugBouncesDecay, debugMinStrengthTolerance, debugAirDecay;
[SerializeField] private LayerMask debugBounceLayer;
private void Update()
{
if (debugTestSoundOn)
CreateTestSound();
}
private void CreateTestSound()
{
CastAudioRays(debugXResolution, debugYResolution, debugMaxBounces, debugBouncesDecay, debugAirDecay, debugMinStrengthTolerance, debugBounceLayer);
}
public void CastAudioRays(int xResolution, int yResolution, int maxBounces, float bouncesDecay, float airDecay, float minStrengthTolerance, LayerMask bounceLayer)
{
Gizmos.color = Color.red;
var direction = transform.forward;
var directionChangeAmount = 360 / xResolution;
for (var x = 0; x < xResolution; x++)
{
direction = Quaternion.Euler(directionChangeAmount, 0, directionChangeAmount) * direction;
directionChangeAmount = 360 / yResolution;
for (var y = 0; y < yResolution; y++)
{
CastAudioRay(direction, maxBounces, bouncesDecay, airDecay, minStrengthTolerance, bounceLayer);
direction = Quaternion.Euler(0, directionChangeAmount, 0) * direction;
}
}
}
private void CastAudioRay(Vector3 direction, int maxBounces, float bouncesDecay, float airDecay, float minStrengthTolerance, LayerMask bounceLayer)
{
var location = transform.position;
var distance = 0f;
var strength = 1f;
for (var i = 0; i < maxBounces; i++)
{
Physics.Raycast(location, direction, out var hit, float.PositiveInfinity, bounceLayer);
if (debugModeOn)
Debug.DrawLine(location, hit.point);
var lastBounceLocation = location;
location = hit.point;
direction = Vector3.Reflect(direction, hit.normal);
distance += hit.distance;
strength *= 1f - distance * airDecay;
if(strength < minStrengthTolerance)
break;
if (hit.collider != null && hit.collider.CompareTag("Receiver"))
{
var echoLocationResult = new EchoLocationResult(strength, distance, lastBounceLocation, gameObject, hit.collider.gameObject);
hit.collider.GetComponent().ReceiveHit(echoLocationResult);
}
strength *= 1 - bouncesDecay;
}
}
}
}
Each enemy has a reciever and if the transmitter is hitting any recivers the reciver will be alerted.
using System;
using UnityEngine;
namespace EchoLocation
{
public class EchoLocationReceiver : MonoBehaviour
{
public Action heardSound;
public void ReceiveHit(EchoLocationResult echoLocationResult) => heardSound?.Invoke(echoLocationResult);
}
}