Survive If You Can

Technical details

Engine: Unity
Version: 2020.3.21f1
Genre: FPS
Team of 2 people:

  • 2 programmers.

Assets: Free from Unity Marketplace
Itch.io: Link

Description

The game was created as an assessment for a course of study with a friend of mine. It was one of our first games created and it was done in around 24 hours. All the voicovers were done by my friend and I was responsible for the programming part. I was responsible for player movement, attack, weapon switching, main and pause menus. The tutorial map was also on my side of responsibilites. Below will be shown the most interesting parts of the code.

Player

There are few important parts of the code that I have created for the player. Below are parts of Attack and Movement functions.

First of all, depending on the weapon chosen, we have different clips to play, different for ranged and different for melee. Then we select the layerMask and then invert it, thanks to this approach we can interact with all layers except the player's to cast the raycast.

void Attack()
{
	if (weapon == "Melee") {
		int pickedClip = Random.Range(0, swordClips.Length - 1);
		melee.transform.GetComponent().PlayOneShot(swordClips[pickedClip]);
	}
	else if (weapon == "Ranged") {
		int pickedClip = Random.Range(0, gunClips.Length - 1);
		ranged.transform.GetComponent().PlayOneShot(gunClips[pickedClip]);
	}

	int layerMask = 1 << 7;
	layerMask = ~layerMask;

	RaycastHit hit;
}

Below code describes calculations on Vectors needed to get the player velocity, his movement direction and rotation. Combining this with mouse movement we can proceed with movement of the player.

void Movement()
{
	Vector3 forward = transform.TransformDirection(Vector3.forward);
	Vector3 right = transform.TransformDirection(Vector3.right);

	Vector3 vel = transform.forward * Input.GetAxis("Vertical") * speed;
	vSpeed -= gravity * Time.deltaTime;
	vel.y = vSpeed;

	characterController.Move(vel * Time.deltaTime);

	float curSpeedX = speed * Input.GetAxis("Vertical");
	float curSpeedY = speed * Input.GetAxis("Horizontal");
	float movementDirectionY = moveDirection.y;
	moveDirection = (forward * curSpeedX) + (right * curSpeedY);

	characterController.Move(moveDirection * Time.deltaTime);

	rotationX += -Input.GetAxis("Mouse Y") * lookSpeed;
	rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit);
	playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0);
	transform.rotation *= Quaternion.Euler(0, Input.GetAxis("Mouse X") * lookSpeed, 0);
}


UI

The most important part is pause menu, to stop the game and show the options. I have created a script for it, which is presented below. First is shown the part of the code that stops the game and makes the cursor visable and unlocked. Then the part of the code that unpause the game and makes the cursor invisable and locked:

Time.timeScale = 0.0f;

//Makes it visable
Cursor.visible = true;
//Unlocks the mouse
Cursor.lockState = CursorLockMode.None;

Second part:

Time.timeScale = 1.0f;
//Makes it invisable
Cursor.visible = false;
//Locks the mouse in place
Cursor.lockState = CursorLockMode.Locked;

Weapon spawner

To spawn the weapon I have created a script for it, which is presented below. It first chooses the position of the weapon and then destroys the one that is spawned (if it is spawned). Then it decides if it should be a melee or ranged weapon and spawns it. Thanks to that approach the game is more dynamic and the player has to be more adaptive as the weapons is spawned each wave. But the code is not perfect, as it is not the best approach. It violates SOLID principles. It is not easily extendable and it is not easy to add new weapons to the game.

float x = Random.Range(minVal, maxVal);
float z = Random.Range(minVal, maxVal);

if (weapon != null)
{
	Destroy(weapon);
}

Vector3 spawnPos = new Vector3(0.0f, 0.0f, 0.0f);
spawnPos.x = x;
spawnPos.z = z;
if (Random.value <= 0.5)
{
	spawnPos.y = melee.gameObject.transform.position.y;
	weapon = Instantiate(melee, spawnPos, Quaternion.identity);
}
else
{
	spawnPos.y = ranged.gameObject.transform.position.y;
	weapon = Instantiate(ranged, spawnPos, Quaternion.identity);
}

Key takeouts

Here I has seen how little time is needed to have a simple yet working and fun game. It lacks polish but has the core mechanics and sounds - where sounds make a lot of good impression. Also adding simple animations like player and enemy actions or weapon moving on the floor is low effort, but gives much better feeling. Last thing is handling menu and game pause, it wasn't that intuitive at the beggining but after this project I have some knowledge how it can be handled.