My Unity Depth Charges remake is not an exact remake. I took the idea of a destroyer dropping depth charges to bomb submarines. Other than that there are some major differences from the original game from Gremlin. The 1977 version is time-based. My version runs until you are killed.
The ship is controlled with A and D or the left and right arrow keys. The subs
You can download the entire project from my GitHub Repository.
Unity Depth Charges “Remake” Demo Video
Check out the short demo video below. It was a quick run. Those torpedos are fast.
Scripts used in Unity Depth Charges
Barrel.cs – Controls the sinking of the depth charges, and check if it hits a sub or goes below the bottom of the screen.
BoatController.cs – Controlls the boat and fires depth charges.
EnemyBullet.cs – Moves the bomb and torpedos upwards, and check if it hits the player or the sky.
ExplosionPlayer.cs – Spawns the explosion
MenuManager.cs – Load the game scene or quit, depends on what the player clicks.
SceneManager.cs – Spawns the subs.
Score.cs – A class made to keep track of the score, ammo and kills.
SubController.cs – Controls the sub, fire torpedos, and bombs, and kills the sub if it gets hit or leaves the screen.
A lot of the code is pretty basic so I wont cover every code line.
Barrel.cs
The barrel script just make sure the barrel moves downward. Just a basic transform
// The main part of barrel script
void Update()
{
translation = speed * Time.deltaTime;
transform.Translate(0, translation, 0);
if (transform.position.y < bottomBorder.y)
{
Score.SetCharges(1);
Destroy(gameObject);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "Submarine")
{
Score.SetCharges(1);
Destroy(gameObject);
}
}
BoatController.cs
This is the script for controlling the player boat. It makes sure you can move the boat right and left, and drop bombs. The script will also make sure you can not leave the screen. Here is the complete script.
The update function does three things. Move the ship by using Input.GetAxis(“Horizontal”), drop a depth charge when pressing space, and update the player position for the subs to aim at once a second.
The LateUpdate() function is used to keep the player on the screen. This should work on any screen resolutions. Here is the code used.
private void LateUpdate()
{
// Keep the player boat inside the visible screen
float spriteLeft = transform.position.x - spriteHalfSize.x;
float spriteRight = transform.position.x + spriteHalfSize.x;
Vector3 clampedPosition = transform.position;
if (spriteLeft < leftBorder.x)
clampedPosition.x = leftBorder.x + spriteHalfSize.x;
else if (spriteRight > rightBorder.x)
clampedPosition.x = rightBorder.x - spriteHalfSize.x;
transform.position = clampedPosition;
}
The 2d box collider checks for collisions between torpedos and bombs launched from the subs. Since there is only one life in this game, it will also send the player back to the menu. There is a
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.tag == "bomb" || collision.tag == "Torpedo")
{
GameObject ExPlayer = Instantiate(bomb, transform.position, Quaternion.identity);
Invoke("GoToMenu", 2); // Go back to menu after 2 seconds
Destroy(ExPlayer, 2.5f);
rend.enabled = false; // Make player invisible
mCollider.enabled = false; // Turn of collider
}
}
void GoToMenu()
{
Destroy(gameObject);
UnityEngine.SceneManagement.SceneManager.LoadScene("Menu");
}
EnemyBullet.cs
The EnemyBullet script does three things. Check if it a bomb or torpedo, and then set the speed to 1 if it is a bomb, or 7 if it is a torpedo. The update function moves the bullet, and a 2d collider checks if it hits the player or the sky. Both make it disappear. You can see the entire script here.
ExplosionPlayer.cs
This script has only one purpose, and that is to play the explosion. It is the same explosion for all object. This is the script used to play all of them.
public class ExplosionPlayer : MonoBehaviour
{
[SerializeField]
GameObject ExplosionVfx = default;
private void Start()
{
GameObject explosion = Instantiate(ExplosionVfx, transform.position, Quaternion.identity);
Destroy(explosion, 1);
}
}
MenuManager.cs
MenuManager is the script for the menu scene. Just load the game if the player clicks play, quit if they click quit. And display the high score. That is it.
using UnityEngine;
using UnityEngine.UI;
public class MenuManager : MonoBehaviour
{
[SerializeField]
private Text highScoreText;
public void MainScene()
{
UnityEngine.SceneManagement.SceneManager.LoadScene("MainScene");
}
public void QuitGame()
{
Application.Quit();
}
private void Start()
{
highScoreText.text = "High Score: " + Score.GetHighScore().ToString();
}
}
SceneManager.cs
The script for the game scene. It spawns the submarines. When the script starts we find the screen size (width) and reset all player variables such as ammo, kills
void Start()
{
audioPlayer = GetComponent<AudioSource>();
leftBorder = Camera.main.ViewportToWorldPoint(Vector3.zero);
rightBorder = Camera.main.ViewportToWorldPoint(Vector3.one);
Score.Reset(); // Reset score, kills, subslots, ammo
}
The Update function instantiates the subs every 2 to 4 seconds. The first spawn is set to spawn after 2 seconds.
void Update()
{
spawnTimer -= Time.deltaTime;
if (spawnTimer <= 0)
{
spawnTimer = Random.Range(2f, 4f); // Spawn between 2 and 4s
SpawnSub();
}
}
There are probably easier and smarter ways of doing the SpawnSub() function.
void SpawnSub()
{
bool slotFound = false;
int counter = 0;
int direction = Random.Range(0, 2);
audioPlayer.PlayOneShot(sonarSound, 1f);
switch (direction)
{
case 0:
subPos.x = leftBorder.x - 2f;
break;
default:
subPos.x = rightBorder.x + 2f;
break;
}
while (!slotFound) // find a free slot to spawn the sub
{ // only one sub for each depth
subPos.y = Random.Range(-4, 2);
slotFound = Score.ReadSlot((int)subPos.y);
counter++;
if (counter > 6)
{
subPos.y = Random.Range(-4, 2);
counter = 0;
slotFound = true;
}
}
Score.SetSlot((int)subPos.y, false);
Instantiate(enemy, subPos, Quaternion.identity);
}
First the script picks a direction for the sub to go. Either from left to right or right to left. Then the script finds a depth for the sub to spawn in on. See the pic below for how I arranged the slots. But I only want one sub for each slot at the time. So a maximum of 6 subs at the time. However, if someone changed the script a reduced the minimum spawn time all slots might be taken. So instead of the game freezing, I just pick a random slot for the next sub. So there will be two subs on the same slot. I try 6 times before spawning the sub on the same slot. Why 6? No idea. It works probably better if that was changed to 1.
Score.cs
The score script was at first only the class for keeping track of the score. Then I found it handy to keep a few more variables.
private static int score;
private static int highScore;
private static int charges;
private static int kills;
private static Vector2 boatPos;
private static bool[] subSlots = new bool[6]
{
true, true, true, true, true, true
};
The functions in this script are just methods for reading and setting these variables. The AddScore function has the scoring algorithm. It is easy tho.
public static void AddScore(int depth)
{
score += 70 - ((depth + 5) * 10);
kills++;
if (score > highScore) // Check if there is a new high score
highScore = score; // every time the player get some points
}
Every kill starts out as 70 points as maximum. But that is for hitting the subs in slot 0. For every slot closer to the surface the scripts subtract 10 points. So subs hit in slot 5 only get 10 points.
SubController.cs
Last script in the game. The script that controls the submarines. At the start of the script, we decide if the sub should release a bomb or a torpedo. There is a 10% chance the sub will release a torpedo.
int torpedoChance = Random.Range(0, 10);
if (torpedoChance == 7)
{
willFireTorpedo = true;
audioPlayer.PlayOneShot(torpedoWarning, 1f);
}
Then we check on which side the sub has to spawn on, right or left. We flip the sprite if it was spawned on the left side. At the end of the start function, we check for the player position for where to drop the bombs.
The update function moves the sub. Check for when we reached the player position we got from the start function. And make sure we kill the sub when it leaves the screen.
void Update()
{
translation = direction * speed * Time.deltaTime;
transform.Translate(translation, 0, 0);
// Release the bomb
if (direction == -1 && transform.position.x < bombCoordinates && !hasFired)
BombRelease();
else if (direction == 1 && transform.position.x > bombCoordinates && !hasFired)
BombRelease();
// Kill the sub outside of borders
if (direction == -1 && (transform.position.x < leftBorder.x - spriteHalfSize.x))
KillSub();
else if (direction == 1 && (transform.position.x > rightBorder.x + spriteHalfSize.x))
KillSub();
}
Rest of the script only checks if the subs get hit by a depth charge and kill the sub if it does.
Unity Depth Charges, known bugs
At the moment I only know of one bug in the game. That is you can continue to drop depth charges after you are killed. Should be an easy fix, right?
If you are into retro stuff, check out my simple but cool retro demo.
This Post Has One Comment