From 8f6792c85ebac2a89e0189e54da5f831c3533579 Mon Sep 17 00:00:00 2001
From: MuhamadAjiW <16521119@mahasiswa.itb.ac.id>
Date: Fri, 19 Apr 2024 07:57:04 +0700
Subject: [PATCH] feat: collectibles

---
 Assets/Scenes/SampleScene.unity               |  8 +--
 .../Scripts/Config/GameEnvironmentConfig.cs   |  3 +-
 .../Scripts/Core/Entities/Mobs/Dummy/Dummy.cs |  2 +-
 .../Scripts/Core/Entities/Mobs/EnemyEntity.cs |  2 +-
 Assets/Scripts/Core/Game/Data/GameControls.cs |  6 ++-
 Assets/Scripts/Core/Game/GameController.cs    |  4 +-
 .../Core/Game/Managers/EntityManager.cs       | 17 +++---
 .../Core/Game/Managers/EnvironmentManager.cs  | 17 +++---
 .../Core/Game/Managers/ObjectManager.cs       | 11 ++++
 .../Core/Game/Managers/ObjectManager.cs.meta  | 11 ++++
 .../Core/Objects/Collectibles/Collectible.cs  | 53 +++++++++++++++++++
 .../Objects/Collectibles/Collectible.cs.meta  | 11 ++++
 .../Objects/Collectibles/TestCollectible.meta |  8 +++
 .../TestCollectible/TestCollectible.cs        | 11 ++++
 .../TestCollectible/TestCollectible.cs.meta   | 11 ++++
 .../Core/Objects/Weapons/TestWeapon.meta      |  8 +++
 .../Weapons/{ => TestWeapon}/TestWeapon.cs    |  0
 .../{ => TestWeapon}/TestWeapon.cs.meta       |  0
 .../Objects/Weapons}/WeaponObject.cs          |  2 +-
 .../Objects/Weapons}/WeaponObject.cs.meta     |  0
 .../Library/BaseClasses/AttackHitbox.cs       |  2 +-
 .../BaseClasses/EntityObject/AttackObject.cs  |  1 +
 .../CameraBehaviour/CameraFollowObject.cs     |  8 +--
 Assets/Scripts/Library/Util/ObjectFactory.cs  | 21 ++++++--
 24 files changed, 174 insertions(+), 43 deletions(-)
 create mode 100644 Assets/Scripts/Core/Game/Managers/ObjectManager.cs
 create mode 100644 Assets/Scripts/Core/Game/Managers/ObjectManager.cs.meta
 create mode 100644 Assets/Scripts/Core/Objects/Collectibles/Collectible.cs
 create mode 100644 Assets/Scripts/Core/Objects/Collectibles/Collectible.cs.meta
 create mode 100644 Assets/Scripts/Core/Objects/Collectibles/TestCollectible.meta
 create mode 100644 Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs
 create mode 100644 Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs.meta
 create mode 100644 Assets/Scripts/Core/Objects/Weapons/TestWeapon.meta
 rename Assets/Scripts/Core/Objects/Weapons/{ => TestWeapon}/TestWeapon.cs (100%)
 rename Assets/Scripts/Core/Objects/Weapons/{ => TestWeapon}/TestWeapon.cs.meta (100%)
 rename Assets/Scripts/{Library/BaseClasses => Core/Objects/Weapons}/WeaponObject.cs (95%)
 rename Assets/Scripts/{Library/BaseClasses => Core/Objects/Weapons}/WeaponObject.cs.meta (100%)

diff --git a/Assets/Scenes/SampleScene.unity b/Assets/Scenes/SampleScene.unity
index 01903196..904f3548 100644
--- a/Assets/Scenes/SampleScene.unity
+++ b/Assets/Scenes/SampleScene.unity
@@ -507,8 +507,8 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   knockbackResistance: 1
   baseSpeed: 0
-  maxHealth: 100
-  health: 100
+  maxHealth: 100000
+  health: 100000
   baseDamage: 0
 --- !u!1 &675919034
 GameObject:
@@ -1194,11 +1194,11 @@ PrefabInstance:
     m_Modifications:
     - target: {fileID: 2635269686106844091, guid: 1a7698227caac3d429dceb8aa5056502, type: 3}
       propertyPath: BaseDamage
-      value: 1
+      value: 10
       objectReference: {fileID: 0}
     - target: {fileID: 2635269686106844091, guid: 1a7698227caac3d429dceb8aa5056502, type: 3}
       propertyPath: KnockbackPower
-      value: 100
+      value: 200
       objectReference: {fileID: 0}
     - target: {fileID: 3608611397487402253, guid: 1a7698227caac3d429dceb8aa5056502, type: 3}
       propertyPath: m_Name
diff --git a/Assets/Scripts/Config/GameEnvironmentConfig.cs b/Assets/Scripts/Config/GameEnvironmentConfig.cs
index 4a55d8d1..32f35ec8 100644
--- a/Assets/Scripts/Config/GameEnvironmentConfig.cs
+++ b/Assets/Scripts/Config/GameEnvironmentConfig.cs
@@ -8,7 +8,8 @@ public static class GameEnvironmentConfig{
 
     // Layers
     public static readonly string LAYER_ENEMY = "Enemy";
+    public static readonly string LAYER_PLAYER_ATTACK = "PlayerAttack";
     public static readonly string LAYER_PLAYER = "Player";
     public static readonly string LAYER_ENEMY_ATTACK = "EnemyAttack";
-    public static readonly string LAYER_PLAYER_ATTACK = "PlayerAttack";
+    public static readonly string LAYER_COLLECTIBLE = "Collectible";
 }
\ No newline at end of file
diff --git a/Assets/Scripts/Core/Entities/Mobs/Dummy/Dummy.cs b/Assets/Scripts/Core/Entities/Mobs/Dummy/Dummy.cs
index 65c70ece..bc52d4d9 100644
--- a/Assets/Scripts/Core/Entities/Mobs/Dummy/Dummy.cs
+++ b/Assets/Scripts/Core/Entities/Mobs/Dummy/Dummy.cs
@@ -6,7 +6,7 @@ public class Dummy : EnemyEntity{
     public DummyStateController stateController;
 
     // Constructor
-    new void Start(){
+    new protected void Start(){
         base.Start();
         stateController = new DummyStateController(this);
         animationController = new DummyAnimationController(this);
diff --git a/Assets/Scripts/Core/Entities/Mobs/EnemyEntity.cs b/Assets/Scripts/Core/Entities/Mobs/EnemyEntity.cs
index 88a464b0..9cdbbde9 100644
--- a/Assets/Scripts/Core/Entities/Mobs/EnemyEntity.cs
+++ b/Assets/Scripts/Core/Entities/Mobs/EnemyEntity.cs
@@ -1,6 +1,6 @@
 public abstract class EnemyEntity : Combatant {
     // Functions
-    new void Start(){
+    new protected void Start(){
         base.Start();
         Health *= GameConfig.DIFFICULTY_MODIFIERS[GameSaveData.instance.difficulty].EnemyHealthMultiplier;
         BaseDamage *= GameConfig.DIFFICULTY_MODIFIERS[GameSaveData.instance.difficulty].EnemyDamageMultiplier;
diff --git a/Assets/Scripts/Core/Game/Data/GameControls.cs b/Assets/Scripts/Core/Game/Data/GameControls.cs
index 3e86ad3f..acd8630a 100644
--- a/Assets/Scripts/Core/Game/Data/GameControls.cs
+++ b/Assets/Scripts/Core/Game/Data/GameControls.cs
@@ -1,13 +1,15 @@
 using UnityEngine;
 
 public class GameControls : MonoBehaviour {
-    // Attributes
+    // Static instance
     public static GameControls instance;
+
+    // Attributes
     public KeyCode backButton = KeyCode.Escape;
     public KeyCode attackButton = KeyCode.Z;
 
     // Constructor
-    private void Awake(){
+    protected void Awake(){
         instance = this;
         DontDestroyOnLoad(gameObject);
     }
diff --git a/Assets/Scripts/Core/Game/GameController.cs b/Assets/Scripts/Core/Game/GameController.cs
index 61234df2..065a1525 100644
--- a/Assets/Scripts/Core/Game/GameController.cs
+++ b/Assets/Scripts/Core/Game/GameController.cs
@@ -11,7 +11,7 @@ public class GameController : MonoBehaviour {
     public bool IsPaused => Time.timeScale == 0;
 
     // Constructor
-    private void Awake(){
+    protected void Awake(){
         if(instance == null) instance = this;
         mainCamera = new GameCameraController(GetComponentInChildren<Camera>());
         stateController = new GameStateController();
@@ -19,7 +19,7 @@ public class GameController : MonoBehaviour {
     }
 
     // Functions
-    void Update(){
+    protected void Update(){
          if(Input.GetKeyDown(GameControls.instance.backButton)){
             stateController.HandleEscape();
          }
diff --git a/Assets/Scripts/Core/Game/Managers/EntityManager.cs b/Assets/Scripts/Core/Game/Managers/EntityManager.cs
index 54aa7fef..aec186b7 100644
--- a/Assets/Scripts/Core/Game/Managers/EntityManager.cs
+++ b/Assets/Scripts/Core/Game/Managers/EntityManager.cs
@@ -2,17 +2,12 @@ using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
-public class EntityManager : MonoBehaviour
-{
-    // Start is called before the first frame update
-    void Start()
-    {
-        
-    }
+public class EntityManager : MonoBehaviour{
+    // Static instance
+    public static EntityManager instance;
 
-    // Update is called once per frame
-    void Update()
-    {
-        
+    // Constructor
+    protected void Awake(){
+        instance = this;
     }
 }
diff --git a/Assets/Scripts/Core/Game/Managers/EnvironmentManager.cs b/Assets/Scripts/Core/Game/Managers/EnvironmentManager.cs
index 58bd398c..1d7c8260 100644
--- a/Assets/Scripts/Core/Game/Managers/EnvironmentManager.cs
+++ b/Assets/Scripts/Core/Game/Managers/EnvironmentManager.cs
@@ -2,17 +2,12 @@ using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 
-public class EnvironmentManager : MonoBehaviour
-{
-    // Start is called before the first frame update
-    void Start()
-    {
-        
-    }
+public class EnvironmentManager : MonoBehaviour{
+    // Static instance
+    public static EnvironmentManager instance;
 
-    // Update is called once per frame
-    void Update()
-    {
-        
+    // Constructor
+    protected void Awake(){
+        instance = this;
     }
 }
diff --git a/Assets/Scripts/Core/Game/Managers/ObjectManager.cs b/Assets/Scripts/Core/Game/Managers/ObjectManager.cs
new file mode 100644
index 00000000..38a3f90a
--- /dev/null
+++ b/Assets/Scripts/Core/Game/Managers/ObjectManager.cs
@@ -0,0 +1,11 @@
+using UnityEngine;
+
+public class ObjectManager : MonoBehaviour{
+    // Static Instance
+    public static ObjectManager instance;
+
+    // Constructor
+    protected void Awake(){
+        instance = this;
+    }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Core/Game/Managers/ObjectManager.cs.meta b/Assets/Scripts/Core/Game/Managers/ObjectManager.cs.meta
new file mode 100644
index 00000000..93153c09
--- /dev/null
+++ b/Assets/Scripts/Core/Game/Managers/ObjectManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c051aae39aef0264ba144bc30cbe301e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/Core/Objects/Collectibles/Collectible.cs b/Assets/Scripts/Core/Objects/Collectibles/Collectible.cs
new file mode 100644
index 00000000..6985de0e
--- /dev/null
+++ b/Assets/Scripts/Core/Objects/Collectibles/Collectible.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections;
+using UnityEngine;
+
+public abstract class Collectible : MonoBehaviour {
+    // Attributes
+    [SerializeField] float TimeToLive;
+    private event Action OnCollectEvent;
+    private event Action OnTimeoutEvent;
+
+    // Constructor
+    protected void Start(){
+        OnCollectEvent += OnCollect;
+        OnCollectEvent += OnCollectEnd;
+        OnTimeoutEvent += OnTimeout;
+        OnTimeoutEvent += OnTimeoutEnd;
+        StartCoroutine(Timeout());
+    }
+
+    // Functions
+    protected void OnTriggerEnter(Collider otherCollider){
+        OnCollectEvent?.Invoke();
+    }
+
+    protected virtual void OnCollectEnd(){
+        Destroy(gameObject);
+    }
+
+    protected IEnumerator Timeout(){
+        yield return new WaitForSeconds(TimeToLive);
+        OnTimeoutEvent?.Invoke();
+    }
+
+    protected void OnTimeoutEnd(){
+        Destroy(gameObject);
+    }
+
+    public void AddOnTimeout(Action onTimeout){
+        OnTimeoutEvent -= OnTimeoutEnd;
+        OnTimeoutEvent += onTimeout;
+        OnTimeoutEvent += OnTimeoutEnd;
+    }
+
+    public void RemoveOnTimeout(Action onTimeout){
+        OnTimeoutEvent -= OnTimeoutEnd;
+        OnTimeoutEvent -= onTimeout;
+        OnTimeoutEvent += OnTimeoutEnd;
+    }
+
+    // Abstract Functions
+    protected virtual void OnTimeout(){}
+    protected abstract void OnCollect();
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Core/Objects/Collectibles/Collectible.cs.meta b/Assets/Scripts/Core/Objects/Collectibles/Collectible.cs.meta
new file mode 100644
index 00000000..f55811d3
--- /dev/null
+++ b/Assets/Scripts/Core/Objects/Collectibles/Collectible.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4e18c2d365e00fd499ac5225fe4902d0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/Core/Objects/Collectibles/TestCollectible.meta b/Assets/Scripts/Core/Objects/Collectibles/TestCollectible.meta
new file mode 100644
index 00000000..d22119aa
--- /dev/null
+++ b/Assets/Scripts/Core/Objects/Collectibles/TestCollectible.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: b6fc1a2d2d2eedb4a9e6def6037766cc
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs b/Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs
new file mode 100644
index 00000000..4fa1dcf9
--- /dev/null
+++ b/Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs
@@ -0,0 +1,11 @@
+using UnityEngine;
+
+public class TestCollectible : Collectible{
+    protected override void OnCollect(){
+        Debug.Log("Test collectible collected");
+    }
+
+    protected override void OnTimeout(){
+        Debug.Log("Test collectible timeout");
+    }
+}
\ No newline at end of file
diff --git a/Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs.meta b/Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs.meta
new file mode 100644
index 00000000..cd151e92
--- /dev/null
+++ b/Assets/Scripts/Core/Objects/Collectibles/TestCollectible/TestCollectible.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6a318ebd05eb15c4fabf9cbe7355eb41
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/Core/Objects/Weapons/TestWeapon.meta b/Assets/Scripts/Core/Objects/Weapons/TestWeapon.meta
new file mode 100644
index 00000000..9fcdc3dd
--- /dev/null
+++ b/Assets/Scripts/Core/Objects/Weapons/TestWeapon.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 78564463204f1334eb36e66455d73aa3
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/Core/Objects/Weapons/TestWeapon.cs b/Assets/Scripts/Core/Objects/Weapons/TestWeapon/TestWeapon.cs
similarity index 100%
rename from Assets/Scripts/Core/Objects/Weapons/TestWeapon.cs
rename to Assets/Scripts/Core/Objects/Weapons/TestWeapon/TestWeapon.cs
diff --git a/Assets/Scripts/Core/Objects/Weapons/TestWeapon.cs.meta b/Assets/Scripts/Core/Objects/Weapons/TestWeapon/TestWeapon.cs.meta
similarity index 100%
rename from Assets/Scripts/Core/Objects/Weapons/TestWeapon.cs.meta
rename to Assets/Scripts/Core/Objects/Weapons/TestWeapon/TestWeapon.cs.meta
diff --git a/Assets/Scripts/Library/BaseClasses/WeaponObject.cs b/Assets/Scripts/Core/Objects/Weapons/WeaponObject.cs
similarity index 95%
rename from Assets/Scripts/Library/BaseClasses/WeaponObject.cs
rename to Assets/Scripts/Core/Objects/Weapons/WeaponObject.cs
index 6d4c55d9..26c4ecc2 100644
--- a/Assets/Scripts/Library/BaseClasses/WeaponObject.cs
+++ b/Assets/Scripts/Core/Objects/Weapons/WeaponObject.cs
@@ -9,7 +9,7 @@ public abstract class WeaponObject : MonoBehaviour {
     [SerializeField] protected float KnockbackPower;
 
     // Constructor
-    void Start(){
+    protected void Start(){
         bearer = GetComponentInParent<IArmed>();
         if(bearer is Player) bearerType = AttackObjectType.PLAYER;
         else if(bearer is EnemyEntity) bearerType = AttackObjectType.ENEMY;
diff --git a/Assets/Scripts/Library/BaseClasses/WeaponObject.cs.meta b/Assets/Scripts/Core/Objects/Weapons/WeaponObject.cs.meta
similarity index 100%
rename from Assets/Scripts/Library/BaseClasses/WeaponObject.cs.meta
rename to Assets/Scripts/Core/Objects/Weapons/WeaponObject.cs.meta
diff --git a/Assets/Scripts/Library/BaseClasses/AttackHitbox.cs b/Assets/Scripts/Library/BaseClasses/AttackHitbox.cs
index fc16be16..a9455860 100644
--- a/Assets/Scripts/Library/BaseClasses/AttackHitbox.cs
+++ b/Assets/Scripts/Library/BaseClasses/AttackHitbox.cs
@@ -3,7 +3,7 @@ using UnityEngine;
 
 public class AttackHitbox : AttackObject{
     // Functions
-    void OnTriggerStay(Collider otherCollider){
+    protected void OnTriggerStay(Collider otherCollider){
         Hit(otherCollider);
     }
 }
diff --git a/Assets/Scripts/Library/BaseClasses/EntityObject/AttackObject.cs b/Assets/Scripts/Library/BaseClasses/EntityObject/AttackObject.cs
index 07180f9f..41c5ea2c 100644
--- a/Assets/Scripts/Library/BaseClasses/EntityObject/AttackObject.cs
+++ b/Assets/Scripts/Library/BaseClasses/EntityObject/AttackObject.cs
@@ -21,6 +21,7 @@ public class AttackObject : MonoBehaviour, IAttack{
         var knockbackModifier = (-1) * knockbackPower / rigidObject.KnockbackResistance;
         Vector3 knockbackVector = MathUtils.GetDirectionVector(KnockbackOrigin, rigidObject.Position) * knockbackModifier;
         rigidObject.Rigidbody.AddForce(knockbackVector, ForceMode.Impulse);
+        Debug.Log(knockbackVector);
     }
 
     protected void Hit(Collider otherCollider){
diff --git a/Assets/Scripts/Library/CameraBehaviour/CameraFollowObject.cs b/Assets/Scripts/Library/CameraBehaviour/CameraFollowObject.cs
index 3ee12225..b489f0e1 100644
--- a/Assets/Scripts/Library/CameraBehaviour/CameraFollowObject.cs
+++ b/Assets/Scripts/Library/CameraBehaviour/CameraFollowObject.cs
@@ -2,13 +2,13 @@ using UnityEngine;
 
 public class CameraFollowObject : CameraBehaviour {
     // Attributes
-    [SerializeField] public Transform target;
-    [SerializeField] public float followingTime = CameraConfig.DEFAULT_FOLLOWING_SPEED;
-    [SerializeField] public Vector3 offset = CameraConfig.DEFAULT_CAMERA_OFFSET;
+    public Transform target;
+    public float followingTime = CameraConfig.DEFAULT_FOLLOWING_SPEED;
+    public Vector3 offset = CameraConfig.DEFAULT_CAMERA_OFFSET;
     private Vector3 velocity = Vector3.zero;
     
     // Functions
-    void FixedUpdate(){
+    protected void FixedUpdate(){
         Vector3 targetPosition = target.position + offset;
         Vector3 newPosition = Vector3.SmoothDamp(transform.position, targetPosition, ref velocity, followingTime);
         transform.position = newPosition;
diff --git a/Assets/Scripts/Library/Util/ObjectFactory.cs b/Assets/Scripts/Library/Util/ObjectFactory.cs
index 33c8c84f..e0d8a44c 100644
--- a/Assets/Scripts/Library/Util/ObjectFactory.cs
+++ b/Assets/Scripts/Library/Util/ObjectFactory.cs
@@ -73,11 +73,24 @@ public static class ObjectFactory{
         return prefabObject;
     }
 
+    public static GameObject CreateCollectibleObject(
+        string prefabPath,
+        Transform parent = null,
+        Vector3? position = null,
+        Vector3? scale = null,
+        Quaternion? rotation = null,
+        int renderingOrder = 0,
+        string objectName = "Unnamed Object"
+    ){
+        GameObject prefabObject = CreateObject(prefabPath, parent == null? ObjectManager.instance.transform : parent, position, scale, rotation, renderingOrder, objectName);
+        if(!prefabObject.TryGetComponent<Collectible>(out var collectibleObject)) Debug.LogError("Loaded prefab is not a Collectible: " + prefabPath);
+        prefabObject.layer = LayerMask.NameToLayer(GameEnvironmentConfig.LAYER_COLLECTIBLE);
+
+        return prefabObject;
+    }
+
     public static void Destroy(GameObject gameObject, float delay = 0){
-        if(gameObject == null){
-            Debug.LogError("Tried to destroy a null gameObject");
-            return;
-        }
+        if(gameObject == null) return;
         GameController.instance.StartCoroutine(DestroyWithDelay(gameObject, delay));
     }
 
-- 
GitLab