From 23f7283e28793ff56ada7016649dbb103ce5c8d9 Mon Sep 17 00:00:00 2001 From: max Date: Wed, 28 Dec 2022 14:56:13 +0100 Subject: [PATCH] achievement system example --- .../ExamplesAchievementSysemAssembly.meta | 8 + .../AchievementSystem.asmdef | 16 ++ .../AchievementSystem.asmdef.meta | 7 + .../Achievements.meta | 8 + .../Achievements/DatabaseObject.asset | 53 +++++++ .../Achievements/DatabaseObject.asset.meta | 8 + .../Achievements/DatabaseObject.cs | 18 +++ .../Achievements/DatabaseObject.cs.meta | 11 ++ .../Achievements/IPlatform.cs | 54 +++++++ .../Achievements/IPlatform.cs.meta | 11 ++ .../Achievements/IUnlockCondition.cs | 141 ++++++++++++++++++ .../Achievements/IUnlockCondition.cs.meta | 11 ++ .../Achievements/IUnlockTrigger.cs | 31 ++++ .../Achievements/IUnlockTrigger.cs.meta | 11 ++ .../Achievements/Unlock.cs | 103 +++++++++++++ .../Achievements/Unlock.cs.meta | 11 ++ .../Achievements/UnlockSystem.cs | 14 ++ .../Achievements/UnlockSystem.cs.meta | 11 ++ 18 files changed, 527 insertions(+) create mode 100644 Samples~/ExamplesAchievementSysemAssembly.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef create mode 100644 Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs.meta create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs create mode 100644 Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs.meta diff --git a/Samples~/ExamplesAchievementSysemAssembly.meta b/Samples~/ExamplesAchievementSysemAssembly.meta new file mode 100644 index 0000000..5909451 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 15056bf3e6f72ae4c8d41c0f408b1ef1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef b/Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef new file mode 100644 index 0000000..bf443a2 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef @@ -0,0 +1,16 @@ +{ + "name": "AchievementSystem", + "rootNamespace": "", + "references": [ + "GUID:73106583b323919458c1e05166706ce3" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef.meta b/Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef.meta new file mode 100644 index 0000000..efcede9 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/AchievementSystem.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7b45b7480b703784cbbb1d5d6fe4f98c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements.meta new file mode 100644 index 0000000..369edaf --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9576dedab4cf70a439e6c24795efdc19 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset new file mode 100644 index 0000000..0741bbe --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset @@ -0,0 +1,53 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c041c0f0630187644bd2e92ba3dbbb37, type: 3} + m_Name: DatabaseObject + m_EditorClassIdentifier: + achievements: + - name: KillEasySkeletons + icon: {fileID: 0} + platformsSettings: + - rid: 332205990316343307 + - rid: 332205990316343308 + - rid: 332205990316343312 + unlock: + unlockTriggers: + - rid: 332205990316343309 + unlockConditions: + - rid: 332205990316343310 + - rid: 332205990316343311 + references: + version: 2 + RefIds: + - rid: 332205990316343307 + type: {class: PC, ns: , asm: AchievementSystem} + data: + achievementKey: sadkjhw8rh23hr0293rh2039rh + - rid: 332205990316343308 + type: {class: PS4, ns: , asm: AchievementSystem} + data: + achievementKey: asd234e234sd2342d23e + - rid: 332205990316343309 + type: {class: EnemyKilledTrigger, ns: , asm: AchievementSystem} + - rid: 332205990316343310 + type: {class: KillEnemies, ns: , asm: AchievementSystem} + data: + targetType: 0 + targetKills: 100 + - rid: 332205990316343311 + type: {class: LevelDifficulty, ns: , asm: AchievementSystem} + data: + difficulty: 0 + - rid: 332205990316343312 + type: {class: SteamDeck, ns: , asm: AchievementSystem} + data: + achievementKey: 12342673658362456458356824612 diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset.meta new file mode 100644 index 0000000..cf74e12 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 769f40e54734cab4598106717122485f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs new file mode 100644 index 0000000..ddcbbfd --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(fileName = "DatabaseObject", menuName = "DatabaseObject")] +public class DatabaseObject : ScriptableObject +{ + public List achievements = new List(); +} + +[System.Serializable] +public class Achievement +{ + public string name; + public Sprite icon; + [SerializeReference, SerializeReferenceButton] + public IPlatform[] platformsSettings = null; + public Unlock unlock; +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs.meta new file mode 100644 index 0000000..1be69b6 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/DatabaseObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c041c0f0630187644bd2e92ba3dbbb37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs new file mode 100644 index 0000000..63999b4 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs @@ -0,0 +1,54 @@ +using UnityEngine; + +public interface IPlatform +{ + public string AchievementKey { get; } +} + +[System.Serializable] +public class PC : IPlatform +{ + public string AchievementKey => achievementKey; + [SerializeField] + private string achievementKey; +} + +[System.Serializable] +public class PS4 : IPlatform +{ + public string AchievementKey => achievementKey; + [SerializeField] + private string achievementKey; +} + +[System.Serializable] +public class PS5 : IPlatform +{ + public string AchievementKey => achievementKey; + [SerializeField] + private string achievementKey; +} + +[System.Serializable] +public class XBOX : IPlatform +{ + public string AchievementKey => achievementKey; + [SerializeField] + private string achievementKey; +} + +[System.Serializable] +public class Quest : IPlatform +{ + public string AchievementKey => achievementKey; + [SerializeField] + private string achievementKey; +} + +[System.Serializable] +public class SteamDeck : IPlatform +{ + public string AchievementKey => achievementKey; + [SerializeField] + private string achievementKey; +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs.meta new file mode 100644 index 0000000..00a25cb --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IPlatform.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0745aac36e103340b5d5e4ea5fd9e68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs new file mode 100644 index 0000000..947a037 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs @@ -0,0 +1,141 @@ +using System; +using UnityEngine; + +public interface IUnlockCondition +{ + public event Action OnUnlockEvent; + public bool IsUnlocked { get; } + public float Progress { get; } + public bool ResetOnFailedCheck { get; } + //public UnlockResetMode { get; } + //public IString ProgressString { get; } + //public IString UnlockString { get; } + public bool ShouldBePersistent { get; } + public string Data { get; set; } + + public void Initialize(); + public void Reset(); +} + +// Maybe make an IUnlockReset interface to have expandable unlock reset modes. +// The interface could then return a bool if it should reset or not. +public enum UnlockResetMode +{ + NeverReset, + ResetOnFailedCheck, + ResetWithOthers, +} + +public enum EnemyType +{ + Skeleton, + Zombie, + Dragon, + Snek +} + +public enum Difficulty +{ + Easy, + Medium, + Hard +} + +[System.Serializable] +public class KillEnemies : IUnlockCondition +{ + // Serialized Parameters. + [SerializeField] + private EnemyType targetType = EnemyType.Skeleton; + [SerializeField] + private int targetKills = 100; + + // Implementation. + public event Action OnUnlockEvent; + public bool IsUnlocked => kills >= targetKills; + public float Progress => kills / targetKills; + public bool ResetOnFailedCheck => false; + public bool ShouldBePersistent => true; + public string Data { get => kills.ToString(); set { kills = int.Parse(value); } } + + private int kills = 0; + + public void Initialize() + { + // Start listening to some events to collect data. + } + + public void Reset() + { + kills = 0; + } +} + +[System.Serializable] +public class LevelDifficulty : IUnlockCondition +{ + [SerializeField] + private Difficulty difficulty = Difficulty.Easy; + + public event Action OnUnlockEvent; + public bool IsUnlocked => false; + public float Progress => 0; + public bool ResetOnFailedCheck => true; + public bool ShouldBePersistent => false; + public string Data { get => ""; set { } } + + public void Initialize() + { + // Start listening to some events to collect data. + } + + public void Reset() + { + } +} + +[System.Serializable] +public class Accuracy : IUnlockCondition +{ + [SerializeField, Range(0, 1)] + private float targetAccuracy = 0.5f; + + public event Action OnUnlockEvent; + public bool IsUnlocked => false; + public float Progress => 0; + public bool ResetOnFailedCheck => true; + public bool ShouldBePersistent => false; + public string Data { get => ""; set { } } + + public void Initialize() + { + // Start listening to some events to collect data. + } + + public void Reset() + { + } +} + +[System.Serializable] +public class OwnDLC : IUnlockCondition +{ + [SerializeField] + private string dlcName = ""; + + public event Action OnUnlockEvent; + public bool IsUnlocked => false; + public float Progress => 0; + public bool ResetOnFailedCheck => true; + public bool ShouldBePersistent => false; + public string Data { get => ""; set { } } + + public void Initialize() + { + // Start listening to some events to collect data. + } + + public void Reset() + { + } +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs.meta new file mode 100644 index 0000000..8543023 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockCondition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da381efaa214d1048aa1f48f25bb73d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs new file mode 100644 index 0000000..174ddae --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs @@ -0,0 +1,31 @@ +using System; + +public interface IUnlockTrigger +{ + public event Action OnTriggerEvent; + public void Initialize(); +} + +[System.Serializable] +public class LevelCompleteTrigger : IUnlockTrigger +{ + public event Action OnTriggerEvent; + + public void Initialize() + { + // Subscribe to on level complete event. + // OnTriggerEvent?.Invoke(); + } +} + +[System.Serializable] +public class EnemyKilledTrigger : IUnlockTrigger +{ + public event Action OnTriggerEvent; + + public void Initialize() + { + // Subscribe to on enemy killed event. + // OnTriggerEvent?.Invoke(); + } +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs.meta new file mode 100644 index 0000000..2efbc1e --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/IUnlockTrigger.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d96d29f1a9f180a45adba792e2e8c820 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs b/Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs new file mode 100644 index 0000000..d77cf3b --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs @@ -0,0 +1,103 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +[System.Serializable] +public class Unlock : IDisposable +{ + public event Action OnUnlockEvent; + + [SerializeReference, SerializeReferenceButton] private List unlockTriggers = new List(); + [SerializeReference, SerializeReferenceButton] private List unlockConditions = new List(); + + public void Initialize() + { + foreach (IUnlockCondition condition in unlockConditions) + { + condition.Initialize(); + } + + foreach (IUnlockTrigger trigger in unlockTriggers) + { + trigger.OnTriggerEvent += HandleOnTriggerEvent; + trigger.Initialize(); + } + } + + public void Dispose() + { + foreach (IUnlockTrigger trigger in unlockTriggers) + { + trigger.OnTriggerEvent -= HandleOnTriggerEvent; + } + } + + // Format data in some way to store compactly and be re-storable after load. + public bool Save(out string data) + { + data = ""; + + bool shouldSave = false; + foreach (IUnlockCondition condition in unlockConditions) + { + if (condition.ShouldBePersistent) + { + data += condition.Data; + shouldSave = true; + } + } + + return shouldSave; + } + + // Unpack data and load into conditions. + public void Load(string data) + { + foreach (IUnlockCondition condition in unlockConditions) + { + if (condition.ShouldBePersistent) + { + condition.Data = data; + } + } + } + + public bool IsUnlocked() + { + foreach (IUnlockCondition condition in unlockConditions) + { + if (!condition.IsUnlocked) + { + return false; + } + } + + return true; + } + + private void HandleOnTriggerEvent() + { + bool shouldReset = false; + + foreach (IUnlockCondition condition in unlockConditions) + { + if (!condition.IsUnlocked && condition.ResetOnFailedCheck) + { + shouldReset = true; + break; + } + } + + if (shouldReset) + { + foreach (IUnlockCondition condition in unlockConditions) + { + condition.Reset(); + } + } + else if (IsUnlocked()) + { + OnUnlockEvent?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs.meta new file mode 100644 index 0000000..32debad --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/Unlock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf4a89c4c5e1c5749add4d7d4c9b9ec2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs b/Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs new file mode 100644 index 0000000..e46507a --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +public class UnlockSystem : MonoBehaviour +{ + public DatabaseObject dataBase; + + public void OnFireBaseLoaded() + { + foreach (Achievement achievement in dataBase.achievements) + { + achievement.unlock.Initialize(); + } + } +} \ No newline at end of file diff --git a/Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs.meta b/Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs.meta new file mode 100644 index 0000000..47aac82 --- /dev/null +++ b/Samples~/ExamplesAchievementSysemAssembly/Achievements/UnlockSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3df439a4f8ef8947a80b7b3e65dad0b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: