Full lifecycle production from initial concept to release on Steam.
The Secret Blue Forest is a puzzle-adventure game developed entirely from the ground up in Unity. Serving as the sole programmer and designer, I architected the core gameplay loops, custom physics interactions, and enemy AI, managing the entire production pipeline through to a public launch. The project required balancing scalable, performant systems with responsive game feel, specifically focusing on spatial puzzles and combat encounters.
public bool PushedMovement(int side, bool sprint)
{
this.touch = false;
float speedMult = sprint ? 1.8f : 1f;
if (this.player != null)
{
switch (side)
{
case 0: this.WallCheck(transform.lossyScale.x / 2f, transform.lossyScale.y / 2f, transform.lossyScale.z / 2f, -transform.forward); break;
case 1: this.WallCheck(transform.lossyScale.z / 2f, transform.lossyScale.y / 2f, transform.lossyScale.x / 2f, -transform.right); break;
case 2: this.WallCheck(transform.lossyScale.z / 2f, transform.lossyScale.y / 2f, transform.lossyScale.x / 2f, transform.right); break;
case 3: this.WallCheck(transform.lossyScale.x / 2f, transform.lossyScale.y / 2f, transform.lossyScale.z / 2f, transform.forward); break;
}
}
if (this.carryBox != null && !this.touch)
{
this.carryBox.GetComponent().PushedMovement(side, sprint);
if (this.carryBox.GetComponent().GetTouch()) this.touch = true;
}
if (!this.touch)
{
if (!this.pushSound) StartCoroutine(this.PushSoundRoutine());
Vector3 moveDir = Vector3.zero;
if (side == 0) moveDir = -transform.forward;
else if (side == 1) moveDir = -transform.right;
else if (side == 2) moveDir = transform.right;
else if (side == 3) moveDir = transform.forward;
transform.Translate(moveDir * 4f * speedMult * Time.deltaTime, Space.World);
}
return this.touch;
}
public void CheckNextMove()
{
if (!this.alive) return;
Vector3 playerDirection = (this.Player.transform.position - transform.position).normalized;
float turnDirection = Mathf.Abs(Vector3.SignedAngle(transform.forward, playerDirection, Vector3.up));
if (this.playerDistance > 180f)
{
this.anim.SetInteger("condition", 0);
this.attacking = false;
this.Player.GetComponent().SetDangerMusic(0);
return;
}
if (this.stats.GetHealth() < this.maxHealth / 1.6f && !this.anim.GetBool("damaged"))
{
this.anim.SetBool("damaged", true);
this.anim.SetInteger("condition", 5);
return;
}
// Distance is <= 180f. Weighted RNG for attack type based on proximity.
this.headbutt = this.playerDistance < 70f ? Random.Range(0, 5) >= 3 : Random.Range(0, 5) == 0;
this.anim.SetInteger("condition", 1);
}