AQUARIØS

Project Status

Finished

Project type

School assignment

Project Duration

8 weeks

Software Used

Unity

Languages Used

C#

My Role(s)

Lead programmer

It is included in my portfolio because
It includes some common survival systems.

AQUARIØS was created within 8 weeks for a school assignment. It was made with a team of 4 people, where I took the role of lead programmer. This project teached me to create SOLID systems.

Full playthrough

Inventory System

The inventory system or actually item storage system is an important part of any survival/gather game. It was important that this system could be used for any type of storage, for example chests, backpacks, etc. This has been done through inheritance and polymorphism. Although it could be done with interfaces, inheritance and polymorphism is a powerful combination and especially with a game that is fairly small in size.
I do think that using inheritance is also the best way an item storage system in a survival game, since that guarantees that interactions between different types of storage systems are the same and have the same functionality.
This would perhaps be a different case if the game had creative or very custom storage systems.

Code snippet - Inventory System

In this code you can see how item stacking and taking works in the inventory. Items are stored in an ItemSlot.
When adding an item each item slot is checked to see if the item already exists in the inventory, if this is the case then the quantity is increased.
If the quantity is bigger than the maximum quantity of the item it is added to the next item slot. With each item having their own max quantity, I could also easily create non-stackable items, by setting the max quantity to 1.

1    //Returns the total amount of one item
2    public int AmountOf(int itemId) {
3        int total = 0;
4
5        for (int i = 0; i < itemSlots.Count; i++) {
6            if (itemSlots[i].itemID == itemId)
7            {
8                total += itemSlots[i].Quantity;
9            }
10        }
11
12        return total;
13    }
14
15    /// <summary>
16    /// Adds item is possible, returns true if item was added succesfully
17    /// </summary>
18    /// <param name="itemId"></param>
19    /// <returns>True if item was added</returns>
20    public virtual bool AddItem(int itemId, int quantity = 1) {
21        if (items.Contains(itemId)) {
22            do
23            {
24                ItemSlot sd = GetItemStackWithRoom(itemId);
25                if (sd == null) {
26                    return AddNewItem(itemId, quantity);
27                } else if (sd.HasRoom(quantity)) {
28                    sd.Quantity += quantity;
29                    break;
30                } else {
31                    int temp = (sd.MaxQuantity - sd.Quantity);
32                    quantity -= temp;
33                    sd.Quantity += temp;
34                }
35            } while (quantity > 0);
36        } else {
37            return AddNewItem(itemId, quantity);
38        }
39
40        return true;
41    }
42
43    public void RemoveItem(int itemId, int removalQuantity) {
44        if (!items.Contains(itemId)) {
45            Debug.LogError($"Tried to remove item ID: {itemId} while it doesn't exist");
46        }
47
48        do {
49            ItemSlot sd = GetItemStack(itemId);
50            int sdQuantity = sd.Quantity;
51
52            if (sdQuantity >= removalQuantity) {
53                sd.Quantity -= removalQuantity;
54                removalQuantity -= removalQuantity;
55            } else {
56                removalQuantity -= sdQuantity;
57                sd.Quantity -= sdQuantity;
58            }
59
60        } while (removalQuantity > 0);
61    }
62
63    private bool AddNewItem(int itemId, int quantity) {
64        if (HasRoom()) {
65            items.Add(itemId);
66            ItemSlot sd = GetEmptyStack();
67
68            sd.AssignItem(itemId, quantity);
69
70            //If for some reason the quantity is bigger than a full stack, fix it
71            if (quantity > sd.MaxQuantity) {
72                sd.Quantity = sd.MaxQuantity;
73                quantity -= sd.MaxQuantity;
74                return AddItem(itemId, quantity);
75            }
76
77            if (sd.OnStackEmpty == null) {
78                sd.OnStackEmpty += RemoveItemStack;
79            }
80
81            occupiedDisplays += 1;
82            return true;
83        } else {
84            return false;
85        }
86    }
87
88    private void RemoveItemStack(int itemId) {
89        occupiedDisplays -= 1;
90        int index = items.IndexOf(itemId);
91        items.RemoveAt(index);
92    }

Weapon System

In AQUARIØS there are around 7-8 different types of weapons, with some being completely different mechanically compared to others. The game has crossbows, shields, hammers, daggers, spears, etc. With weapons I decided to use an interface, which allowed me to create all of these different workings while the player does not need to know the mechanics of each weapon.

1     public interface IWeapon {
2
3        Animator PlayerAnim { get; set; }
4        float AttackInterval { get; }
5        void DoAttackAnimation();
6        void Attack();
7    
8    }

Shield preview

Code snippet - Shield
1     public class Shield : MeleeWeapon {
2
3        public override void DoAttackAnimation() {
4            PlayerCombat.OnChangeHpPlayerEvent += Block;
5            base.DoAttackAnimation();
6        }
7    
8        public override void Attack() {
9            PlayerCombat.OnChangeHpPlayerEvent -= Block;
10        }
11    
12        private void Block(int damage) {
13            if (damage < 0) {
14                PlayerCombat.HealingPlayerEvent?.Invoke(Mathf.Abs(damage));
15                StunEnemy();
16            }
17        }
18    
19        private void StunEnemy() {
20            if (CheckForHits(out Collider[] hits)) {
21                for (int i = 0; i < hits.Length; i++) {
22                    hits[i].GetComponent<IDamagable>().Stun(1.5f);
23                }
24                FMODUnity.RuntimeManager.PlayOneShot(attackSFX, transform.position);
25            }
26        }
27    
28    }

Hammer preview

Code snippet - Hammer
1     public class Hammer : MeleeWeapon {
2
3        public override void Attack() {
4            if (CheckForHits(out Collider[] hits)) {
5                for (int i = 0; i < hits.Length; i++) {
6                    var hit = hits[i].GetComponent<IDamagable>();
7                    hit.TakeDamage(damage);
8                    hit.Stun(1f);
9                }
10    
11                FMODUnity.RuntimeManager.PlayOneShot(attackSFX, transform.position);
12            }
13        }
14    
15    }

Spear preview

Code snippet - Spear
1     public class Spear : RangedWeapon {
2
3        public override void Attack() {
4            base.Attack();
5    
6            if (!UIManager.Instance.inventory.Contains(ammo.id)) {
7                ItemOptionMenu.Instance.UnEquip();
8            }
9        }
10    
11    }