Project Overview

Fennec Peak is a local multiplayer arena fighting game. It was created during a seven week project with a team of twelve using Unity. The goal of the game is to be the last player alive, to achieve this you need to push the other players off the map using abilites and objects in the enviroment.

Game Info

Roles: Game Programmer

Time: 7 Weeks

Date: May 2019 - June 2019

Team Size: 12 (3 Programmers)

Genre: Party Arena

Engine: Unity

Version Control: Perforce

Code Language: C#

My Role

I worked on the movement and combat system for the characters together with the designers. But also some gameplay elements such as the power-up and exploding barrel.

The Combat System

The game is focused around the combat and snappy movement so it had to feel right. In the beginning we tried using colliders and triggers for knockback but realised it did not feel good enough. To make the combat feel better we instead used raycasts in an arc to mimic the swinging of the players weapon.

A problem that occured with the raycast method was that the rays originated from the characters center going straight outwards. This became a problem when we introduced height, jumping and smaller objects into the game!

To improve hit detection we used three ray arcs with different starting heights on the character, one arc each from the head, the feet and the middle of the character.


//TOP ATTACK int angle = (int)(hitArcAngle / 2) * -1; 
rayNumber = (int)hitArcAngle / 5; 
for (int i = 0; i < rayNumber; i++) 
{
    //Calculate ray direction
    Vector3 forwardDirection = Quaternion.Euler(0, angle, 0) * transform.forward; 
    angle += 5; 
    //Ray origin 
    Vector3 topPos = new Vector3(transform.position.x, transform.position.y + 1.5f, transform.position.z); 
    
    RaycastHit[] hits = Physics.RaycastAll(topPos, forwardDirection, maxAttackLength); 
    for (int j = 0; j < hits.Length; j++) 
    { 
        if (!hits[j].collider.isTrigger) 
        { 
            IKnockback knockbackEffect = hits[j].collider.GetComponent<IKnockback>();
            if (knockbackEffect != null) 
            { 
                Vector3 knockback = transform.forward * knockBackForce * attackCharge; 
                knockbackEffect.Knockback(gameObject, knockback); 
            } 
            break; 
        } 
    } 
    //Debug lines to see the rays
    Debug.DrawLine(topPos, topPos + forwardDirection * maxAttackLength, Color.red, 2); 
}
            

This was the solution that worked best for us with both time, experience and feeling in mind.

Power-up

The power-up structure is something that was rushed and could have been improved!

The structure ended up with a spawner that handles a timer and disables/hides the power-ups mesh and collider. But the power-up itself handles collisions and when a player enters the collision area the power-up searches the player for components located on different child objects. The characters weapon shader and a script that handles weapon variables such as knockback power

powerup structure

A desired structure would have been that the player has the shader and variables referenced on the main player object, making it easier and possibly faster to get the needed components. Since the game only had one power-up it could handle both spawning and collisions by itself, reducing the amount of objects involved in the process and making it easier to use by level designers.

wanted powerup structure
//Powerup.css
//Player collides with the powerup
private void OnTriggerEnter(Collider other) 
{ 
    if(other.tag == "Player" && !other.isTrigger) 
    { 
        PowerUpEffect(other); 
    } 
}

public override void PowerUpEffect(Collider player) 
{ 
    //Gets the player 
    playerMe = player.GetComponent<PlayerMovement>(); 
    if(playerMe) 
    { 
        //finds player weapon Changes material to gold 
        player.GetComponentInChildren<PlayerWeaponPowerUP>()?.ChangeMaterialToGold(); 
    }
}

//PlayerWeaponPowerUP.css
//Do visuals for powerup on player
public void ChangeMaterialToGold()
{
    //If weapon has multiple materials change all to gold and keep a list of old ones
    Material[] materials = new Material[oldMatList.Length];
    for (int i = 0; i < materials.Length; i++)
    {
        materials[i] = gold;
    }
    GetComponent().materials = materials;
    
    if (vfxPowerup && vfxPowerup.isStopped)
        vfxPowerup.Play();

    //Do actual weapon power increase
    IncreasePower();
}

public void IncreasePower()
{
    isReset = false;
    isPoweredUp = true;
    if(spawner)
    {
        spawner.isPoweredUp = true;
    }
    powerUPTimer = powerupTime;
    oldKnockbackForce = playerMe.GetComponent().knockBackForce;
    oldGroundslamStrength = playerMe.GetComponent().strength;
    playerMe.GetComponent().knockBackForce = newKnockbackForce;
    playerMe.GetComponent().strength = groundslamStrength;
}