diff --git a/.gitignore b/.gitignore index 8af868e..58cbc82 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # This .gitignore file should be placed at the root of your Unity project directory # -# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore # /[Ll]ibrary/ /[Tt]emp/ @@ -8,16 +8,20 @@ /[Bb]uild/ /[Bb]uilds/ /[Ll]ogs/ +/[Uu]ser[Ss]ettings/ + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data /[Mm]emoryCaptures/ -# Asset meta data should only be ignored when the corresponding asset is also ignored -!/[Aa]ssets/**/*.meta +# Recordings can get excessive in size +/[Rr]ecordings/ # Uncomment this line if you wish to ignore the asset store tools plugin # /[Aa]ssets/AssetStoreTools* # Autogenerated Jetbrains Rider plugin -[Aa]ssets/Plugins/Editor/JetBrains* +/[Aa]ssets/Plugins/Editor/JetBrains* # Visual Studio cache directory .vs/ @@ -53,8 +57,16 @@ sysinfo.txt # Builds *.apk +*.aab *.unitypackage +*.app # Crashlytics generated file crashlytics-build.properties +# Packed Addressables +/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* + +# Temporary auto-generated Android Assets +/[Aa]ssets/[Ss]treamingAssets/aa.meta +/[Aa]ssets/[Ss]treamingAssets/aa/* diff --git a/.vsconfig b/.vsconfig new file mode 100644 index 0000000..d70cd98 --- /dev/null +++ b/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/Assets/MonoBehaviourLifeCycle.cs b/Assets/MonoBehaviourLifeCycle.cs new file mode 100644 index 0000000..feea69c --- /dev/null +++ b/Assets/MonoBehaviourLifeCycle.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class MonoBehaviourLifeCycle : MonoBehaviour +{ + + private void Awake() + { + print("Awake"); + } + + // Start is called before the first frame update + void Start() + { + print("Start"); + } + + public int count = 0; + + // Update is called once per frame + void Update() + { + count++; + // if (count % 500 == 0) + print("Update"); + } + + private void FixedUpdate() + { + // if (count % 500 == 0) + print("FixedUpdate"); + } + + private void LateUpdate() + { + // if (count % 500 == 0) + print("LateUpdate"); + } + + + private void OnEnable() + { + print("OnEnable"); + } + + private void OnDisable() + { + print("OnDisable"); + } + + private void OnDestroy() + { + print("OnDestroy"); + } + + private void OnValidate() + { + print("OnValidate"); + } + + private void Reset() + { + print("Reset"); + } + + + +} \ No newline at end of file diff --git a/Assets/MonoBehaviourLifeCycle.cs.meta b/Assets/MonoBehaviourLifeCycle.cs.meta new file mode 100644 index 0000000..fc3d759 --- /dev/null +++ b/Assets/MonoBehaviourLifeCycle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 563221c015a0b1b4e9b7790e022efa73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/New Scene.unity b/Assets/New Scene.unity new file mode 100644 index 0000000..863fbab --- /dev/null +++ b/Assets/New Scene.unity @@ -0,0 +1,303 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &1716421094 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1716421097} + - component: {fileID: 1716421096} + - component: {fileID: 1716421095} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1716421095 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1716421094} + m_Enabled: 1 +--- !u!20 &1716421096 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1716421094} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1716421097 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1716421094} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &2141136459 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2141136461} + - component: {fileID: 2141136460} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &2141136460 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2141136459} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &2141136461 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2141136459} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/New Scene.unity.meta b/Assets/New Scene.unity.meta new file mode 100644 index 0000000..fed7286 --- /dev/null +++ b/Assets/New Scene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 83b6987a24424d643825f4b5163a119b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Bird.cs b/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Bird.cs index 2282379..cc60890 100644 --- a/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Bird.cs +++ b/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Bird.cs @@ -13,7 +13,7 @@ public Bird(string name, bool canFly) { this.name = name; - this.flyingType = canFly ? new ICanFly() as IFlyingType : new ICantFly(); + this.flyingType = canFly ? new ICanFly() : new ICantFly(); } public override void Talk() diff --git a/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Fish.cs b/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Fish.cs index 3596332..12354c5 100644 --- a/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Fish.cs +++ b/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Fish.cs @@ -13,7 +13,7 @@ public Fish(string name, bool canFly) { this.name = name; - this.flyingType = canFly ? new ICanFly() as IFlyingType : new ICantFly(); + this.flyingType = canFly ? new ICanFly() : new ICantFly(); } public override void Talk() diff --git a/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Mammal.cs b/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Mammal.cs index a9ccc37..cd12896 100644 --- a/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Mammal.cs +++ b/Assets/Patterns/12. Type Object/Animal/Scripts/Animals/Mammal.cs @@ -13,7 +13,7 @@ public Mammal(string name, bool canFly) { this.name = name; - this.flyingType = canFly ? new ICanFly() as IFlyingType : new ICantFly(); + this.flyingType = canFly ? new ICanFly() : new ICantFly(); } public override void Talk() diff --git a/Assets/Patterns/12. Type Object/Animal/Scripts/TypeObjectController.cs b/Assets/Patterns/12. Type Object/Animal/Scripts/TypeObjectController.cs index 16b3900..c9ab14f 100644 --- a/Assets/Patterns/12. Type Object/Animal/Scripts/TypeObjectController.cs +++ b/Assets/Patterns/12. Type Object/Animal/Scripts/TypeObjectController.cs @@ -17,7 +17,9 @@ void Start() Mammal bat = new Mammal("bat", canFly: true); - Fish flyingFish = new Fish("Flying fish", canFly: true); + Fish flyingFish = new Fish("flying fish", canFly: true); + + Fish goldFish = new Fish("goldfish", canFly: false); ostrich.Talk(); @@ -29,6 +31,8 @@ void Start() bat.Talk(); flyingFish.Talk(); + + goldFish.Talk(); } } } diff --git a/Assets/Patterns/14. Command Queue (Event Queue).meta b/Assets/Patterns/14. Command Queue (Event Queue).meta new file mode 100644 index 0000000..5296742 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue).meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 64e066b22053b694dafc5fbef88b7d5c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueue.cs b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueue.cs new file mode 100644 index 0000000..babba94 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueue.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; + +namespace CommandQueuePattern +{ + public class CommandQueue + { + // queue of commands + private readonly Queue _queue; + + // it's true when a command is running + private bool _isPending; + + public CommandQueue() + { + // create a queue + _queue = new Queue(); + + // no command is running + _isPending = false; + } + + public void Enqueue(ICommand cmd) + { + // add a command + _queue.Enqueue(cmd); + + // if no command is running, start to execute commands + if (!_isPending) + DoNext(); + } + + public void DoNext() + { + // if queue is empty, do nothing. + if (_queue.Count == 0) + return; + + // get a command + var cmd = _queue.Dequeue(); + // setting _isPending to true means this command is running + _isPending = true; + // listen to the OnFinished event + cmd.OnFinished += OnCmdFinished; + // execute command + cmd.Execute(); + } + + private void OnCmdFinished() + { + // current command is finished + _isPending = false; + + // run the next command + DoNext(); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueue.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueue.cs.meta new file mode 100644 index 0000000..b0860c9 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5e2c3806c187c964fb1b8e559c15dbd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueueScene.unity b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueueScene.unity new file mode 100644 index 0000000..60cfbc5 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueueScene.unity @@ -0,0 +1,1790 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &39917111 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 39917112} + - component: {fileID: 39917114} + - component: {fileID: 39917113} + - component: {fileID: 39917115} + m_Layer: 5 + m_Name: FirstPopup + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &39917112 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 39917111} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1953702264} + - {fileID: 854852039} + m_Father: {fileID: 503701280} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -0.000030517578, y: 0} + m_SizeDelta: {x: -435.30905, y: -198.01656} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &39917113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 39917111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 0, b: 0, a: 0.69411767} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &39917114 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 39917111} + m_CullTransparentMesh: 0 +--- !u!114 &39917115 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 39917111} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7aad7754c7316194fbcef0c515cfd3d6, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &117838404 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 117838405} + - component: {fileID: 117838408} + - component: {fileID: 117838407} + - component: {fileID: 117838406} + m_Layer: 5 + m_Name: Close Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &117838405 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 117838404} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 2046382975} + m_Father: {fileID: 1265532431} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -104.4} + m_SizeDelta: {x: 80, y: 33.202057} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &117838406 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 117838404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 117838407} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1265532434} + m_MethodName: Close + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &117838407 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 117838404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &117838408 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 117838404} + m_CullTransparentMesh: 0 +--- !u!1 &163705240 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 163705243} + - component: {fileID: 163705242} + - component: {fileID: 163705241} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &163705241 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 163705240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &163705242 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 163705240} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &163705243 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 163705240} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &388960864 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 388960865} + - component: {fileID: 388960867} + - component: {fileID: 388960866} + m_Layer: 5 + m_Name: Header Txt + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &388960865 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388960864} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 503701280} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -0.000038147, y: 171.2} + m_SizeDelta: {x: 276.14392, y: 69.658905} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &388960866 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388960864} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Welcome to the game! +--- !u!222 &388960867 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 388960864} + m_CullTransparentMesh: 0 +--- !u!1 &503701279 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 503701280} + - component: {fileID: 503701282} + - component: {fileID: 503701281} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &503701280 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 503701279} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 388960865} + - {fileID: 39917112} + - {fileID: 1265532431} + - {fileID: 1976395495} + m_Father: {fileID: 603566541} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &503701281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 503701279} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0, b: 0, a: 0.392} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &503701282 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 503701279} + m_CullTransparentMesh: 0 +--- !u!1 &603566537 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 603566541} + - component: {fileID: 603566540} + - component: {fileID: 603566539} + - component: {fileID: 603566538} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &603566538 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603566537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &603566539 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603566537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 0 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 800, y: 600} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 +--- !u!223 &603566540 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603566537} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &603566541 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603566537} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_Children: + - {fileID: 503701280} + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &610259451 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 610259452} + - component: {fileID: 610259454} + - component: {fileID: 610259453} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &610259452 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 610259451} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 612968657} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &610259453 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 610259451} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Close +--- !u!222 &610259454 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 610259451} + m_CullTransparentMesh: 0 +--- !u!1 &612968656 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 612968657} + - component: {fileID: 612968660} + - component: {fileID: 612968659} + - component: {fileID: 612968658} + m_Layer: 5 + m_Name: Close Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &612968657 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612968656} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 610259452} + m_Father: {fileID: 1976395495} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -104.4} + m_SizeDelta: {x: 80, y: 33.202057} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &612968658 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612968656} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 612968659} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 1976395498} + m_MethodName: Close + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &612968659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612968656} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &612968660 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 612968656} + m_CullTransparentMesh: 0 +--- !u!1 &648954875 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 648954878} + - component: {fileID: 648954877} + - component: {fileID: 648954876} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &648954876 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648954875} + m_Enabled: 1 +--- !u!20 &648954877 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648954875} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &648954878 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 648954875} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &668348811 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 668348812} + - component: {fileID: 668348814} + - component: {fileID: 668348813} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &668348812 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668348811} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1976395495} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 324.04028, y: 36.4041} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &668348813 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668348811} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Third Popup +--- !u!222 &668348814 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668348811} + m_CullTransparentMesh: 0 +--- !u!1 &854852038 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 854852039} + - component: {fileID: 854852042} + - component: {fileID: 854852041} + - component: {fileID: 854852040} + m_Layer: 5 + m_Name: Close Button + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &854852039 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 854852038} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1796699346} + m_Father: {fileID: 39917112} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -104.4} + m_SizeDelta: {x: 80, y: 33.202057} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &854852040 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 854852038} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 854852041} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 39917115} + m_MethodName: Close + m_Mode: 1 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 +--- !u!114 &854852041 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 854852038} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &854852042 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 854852038} + m_CullTransparentMesh: 0 +--- !u!1 &1265532430 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1265532431} + - component: {fileID: 1265532433} + - component: {fileID: 1265532432} + - component: {fileID: 1265532434} + m_Layer: 5 + m_Name: 'SecondPopup ' + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1265532431 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1265532430} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1892493390} + - {fileID: 117838405} + m_Father: {fileID: 503701280} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -0.000030517578, y: 0} + m_SizeDelta: {x: -435.30905, y: -198.01656} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1265532432 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1265532430} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.12152922, g: 1, b: 0, a: 0.69411767} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1265532433 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1265532430} + m_CullTransparentMesh: 0 +--- !u!114 &1265532434 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1265532430} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7aad7754c7316194fbcef0c515cfd3d6, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1717216349 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1717216351} + - component: {fileID: 1717216350} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1717216350 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1717216349} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1717216351 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1717216349} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1796699345 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1796699346} + - component: {fileID: 1796699348} + - component: {fileID: 1796699347} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1796699346 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1796699345} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 854852039} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1796699347 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1796699345} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Close +--- !u!222 &1796699348 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1796699345} + m_CullTransparentMesh: 0 +--- !u!1 &1813885560 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1813885561} + - component: {fileID: 1813885562} + m_Layer: 0 + m_Name: GameController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1813885561 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1813885560} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -6.939781, y: -4.2541914, z: -3.756424} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1813885562 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1813885560} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fab6d57a6720db047b51ffb337d7974e, type: 3} + m_Name: + m_EditorClassIdentifier: + firstPopUp: {fileID: 39917115} + secondPopup: {fileID: 1265532434} + thirdPopup: {fileID: 1976395498} +--- !u!1 &1892493389 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1892493390} + - component: {fileID: 1892493392} + - component: {fileID: 1892493391} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1892493390 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1892493389} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1265532431} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 324.04028, y: 36.4041} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1892493391 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1892493389} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Second Popup +--- !u!222 &1892493392 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1892493389} + m_CullTransparentMesh: 0 +--- !u!1 &1953702263 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1953702264} + - component: {fileID: 1953702266} + - component: {fileID: 1953702265} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1953702264 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1953702263} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 39917112} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 324.04028, y: 36.4041} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1953702265 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1953702263} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: First Popup +--- !u!222 &1953702266 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1953702263} + m_CullTransparentMesh: 0 +--- !u!1 &1976395494 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1976395495} + - component: {fileID: 1976395497} + - component: {fileID: 1976395496} + - component: {fileID: 1976395498} + m_Layer: 5 + m_Name: ThirdPopup + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1976395495 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1976395494} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 668348812} + - {fileID: 612968657} + m_Father: {fileID: 503701280} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -0.000030517578, y: 0} + m_SizeDelta: {x: -435.30905, y: -198.01656} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1976395496 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1976395494} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0, g: 0.5415592, b: 1, a: 0.69411767} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1976395497 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1976395494} + m_CullTransparentMesh: 0 +--- !u!114 &1976395498 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1976395494} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7aad7754c7316194fbcef0c515cfd3d6, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &2046382974 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2046382975} + - component: {fileID: 2046382977} + - component: {fileID: 2046382976} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2046382975 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2046382974} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 117838405} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2046382976 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2046382974} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 14 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 10 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Close +--- !u!222 &2046382977 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2046382974} + m_CullTransparentMesh: 0 diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueueScene.unity.meta b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueueScene.unity.meta new file mode 100644 index 0000000..589437b --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/CommandQueueScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2508b7e936b89c44f9dab72413fdd7dd +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands.meta b/Assets/Patterns/14. Command Queue (Event Queue)/Commands.meta new file mode 100644 index 0000000..e3dd585 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51358a28e180084499754f600e481533 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands/FirstCmd.cs b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/FirstCmd.cs new file mode 100644 index 0000000..74058d3 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/FirstCmd.cs @@ -0,0 +1,36 @@ +using System; + +namespace CommandQueuePattern +{ + public class FirstCmd : ICommand + { + private readonly GameController _owner; + + public Action OnFinished { get; set; } + + public FirstCmd(GameController owner) + { + _owner = owner; + } + + public void Execute() + { + // activate gameobject + _owner.firstPopUp.gameObject.SetActive(true); + + // listen to its onClose event + _owner.firstPopUp.onClose += OnClose; + } + + private void OnClose() + { + _owner.firstPopUp.onClose -= OnClose; + + // deactivate gameobject + _owner.firstPopUp.gameObject.SetActive(false); + + // rise the OnFinished event to say we're done with this command + OnFinished?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands/FirstCmd.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/FirstCmd.cs.meta new file mode 100644 index 0000000..add79ff --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/FirstCmd.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c3e5ee159ede7d49b285f3ac9cb04d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands/SecondCmd.cs b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/SecondCmd.cs new file mode 100644 index 0000000..0e5770a --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/SecondCmd.cs @@ -0,0 +1,36 @@ +using System; + +namespace CommandQueuePattern +{ + public class SecondCmd : ICommand + { + private readonly GameController _owner; + + public SecondCmd(GameController owner) + { + _owner = owner; + } + + public Action OnFinished { get; set; } + + public void Execute() + { + // activate gameobject + _owner.secondPopup.gameObject.SetActive(true); + + // listen to its onClose event + _owner.secondPopup.onClose += OnClose; + } + + private void OnClose() + { + _owner.secondPopup.onClose -= OnClose; + + // deactivate gameobject + _owner.secondPopup.gameObject.SetActive(false); + + // rise the OnFinished event to say we're done with this command + OnFinished?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands/SecondCmd.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/SecondCmd.cs.meta new file mode 100644 index 0000000..64771c2 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/SecondCmd.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ad7d9eb551366d46a22781d5200cf80 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands/ThirdCmd.cs b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/ThirdCmd.cs new file mode 100644 index 0000000..291163c --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/ThirdCmd.cs @@ -0,0 +1,36 @@ +using System; + +namespace CommandQueuePattern +{ + public class ThirdCmd : ICommand + { + private readonly GameController _owner; + + public Action OnFinished { get; set; } + + public ThirdCmd(GameController owner) + { + _owner = owner; + } + + public void Execute() + { + // activate gameobject + _owner.thirdPopup.gameObject.SetActive(true); + + // listen to its onClose event + _owner.thirdPopup.onClose += OnClose; + } + + private void OnClose() + { + _owner.thirdPopup.onClose -= OnClose; + + // deactivate gameobject + _owner.thirdPopup.gameObject.SetActive(false); + + // rise the OnFinished event to say we're done with this command + OnFinished?.Invoke(); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Commands/ThirdCmd.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/ThirdCmd.cs.meta new file mode 100644 index 0000000..0e839af --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Commands/ThirdCmd.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 94367edfe739ac2438cb7e32f881b859 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/GameController.cs b/Assets/Patterns/14. Command Queue (Event Queue)/GameController.cs new file mode 100644 index 0000000..038fd02 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/GameController.cs @@ -0,0 +1,32 @@ +using System.Collections; +using UnityEngine; + +namespace CommandQueuePattern +{ + public class GameController : MonoBehaviour + { + public Popup firstPopUp, secondPopup, thirdPopup; + + private CommandQueue _commandQueue; + + private void Start() + { + // create a command queue + _commandQueue = new CommandQueue(); + + // add commands after a period of time + StartCoroutine(StartCommandsCr()); + } + + private IEnumerator StartCommandsCr() + { + // wait for 2 seconds + yield return new WaitForSeconds(2f); + + // add commands + _commandQueue.Enqueue(new FirstCmd(this)); + _commandQueue.Enqueue(new SecondCmd(this)); + _commandQueue.Enqueue(new ThirdCmd(this)); + } + } +} diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/GameController.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/GameController.cs.meta new file mode 100644 index 0000000..dc83ea7 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/GameController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fab6d57a6720db047b51ffb337d7974e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/ICommand.cs b/Assets/Patterns/14. Command Queue (Event Queue)/ICommand.cs new file mode 100644 index 0000000..19816c5 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/ICommand.cs @@ -0,0 +1,11 @@ +using System; + +namespace CommandQueuePattern +{ + public interface ICommand + { + Action OnFinished { get; set; } + + void Execute(); + } +} \ No newline at end of file diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/ICommand.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/ICommand.cs.meta new file mode 100644 index 0000000..39a26ac --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/ICommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56eaf97de9299bb4daf746cbf0b4504e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Popup.cs b/Assets/Patterns/14. Command Queue (Event Queue)/Popup.cs new file mode 100644 index 0000000..d450109 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Popup.cs @@ -0,0 +1,15 @@ +using System; +using UnityEngine; + +namespace CommandQueuePattern +{ + public class Popup : MonoBehaviour + { + public Action onClose; + + public void Close() + { + onClose?.Invoke(); + } + } +} diff --git a/Assets/Patterns/14. Command Queue (Event Queue)/Popup.cs.meta b/Assets/Patterns/14. Command Queue (Event Queue)/Popup.cs.meta new file mode 100644 index 0000000..9134ae3 --- /dev/null +++ b/Assets/Patterns/14. Command Queue (Event Queue)/Popup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7aad7754c7316194fbcef0c515cfd3d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation.meta b/Assets/Patterns/15. Service Locator/Another Implementation.meta new file mode 100644 index 0000000..b7146c6 --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 26dc8a89f0c03e946ab5c825e982ec1e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/GameController.cs b/Assets/Patterns/15. Service Locator/Another Implementation/GameController.cs new file mode 100644 index 0000000..0a2c8ec --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/GameController.cs @@ -0,0 +1,18 @@ +namespace ServiceLocatorPattern +{ + using UnityEngine; + + public class GameController : MonoBehaviour + { + private void Start() + { + var firstService = ServiceLocator.Resolve(); + var secondService = ServiceLocator.Resolve(); + var thirdService = ServiceLocator.Resolve(); + + firstService?.SayHi(); + secondService?.SimpleMethod(); + thirdService?.Foo(); + } + } +} diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/GameController.cs.meta b/Assets/Patterns/15. Service Locator/Another Implementation/GameController.cs.meta new file mode 100644 index 0000000..c51fd2b --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/GameController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8b083eac1ecd2745b4b2eb8b2d3d470 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocator.cs b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocator.cs new file mode 100644 index 0000000..994c91d --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocator.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Linq; + +namespace ServiceLocatorPattern +{ + public static class ServiceLocator + { + private static readonly HashSet _registeredObjects; + + static ServiceLocator() + { + _registeredObjects = new HashSet(); + } + + public static void Register(T obj) where T : class + { + _registeredObjects.Add(obj); + } + + public static void Unregister(T obj) where T : class + { + _registeredObjects.Remove(obj); + } + + public static T Resolve() where T : class + { + var obj = _registeredObjects.SingleOrDefault(x => x is T); + if (obj != null) + return obj as T; + + return null; + } + } +} diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocator.cs.meta b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocator.cs.meta new file mode 100644 index 0000000..1abd54d --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e6f18119d4fe0d48b650f4b701c6708 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocatorScene.unity b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocatorScene.unity new file mode 100644 index 0000000..08cfad8 --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocatorScene.unity @@ -0,0 +1,470 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &138225925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 138225928} + - component: {fileID: 138225927} + - component: {fileID: 138225926} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &138225926 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 138225925} + m_Enabled: 1 +--- !u!20 &138225927 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 138225925} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &138225928 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 138225925} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &325266288 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 325266289} + - component: {fileID: 325266290} + m_Layer: 0 + m_Name: Second Service + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &325266289 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 325266288} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 214.25294, y: -411.10437, z: -183.65768} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &325266290 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 325266288} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1df5c99439826bd48a3d81f94978aca4, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &865490952 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 865490954} + - component: {fileID: 865490953} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &865490953 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 865490952} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &865490954 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 865490952} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1027150828 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1027150829} + - component: {fileID: 1027150830} + m_Layer: 0 + m_Name: GameController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1027150829 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027150828} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 214.25294, y: -411.10437, z: -183.65768} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1027150830 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1027150828} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b8b083eac1ecd2745b4b2eb8b2d3d470, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1432518748 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1432518749} + - component: {fileID: 1432518750} + m_Layer: 0 + m_Name: First Service + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1432518749 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1432518748} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 214.25294, y: -411.10437, z: -183.65768} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1432518750 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1432518748} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 44d086f170cf84a4b95c0e2a8b703ba5, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &1761968133 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1761968134} + - component: {fileID: 1761968135} + m_Layer: 0 + m_Name: Third Service + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1761968134 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1761968133} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 214.25294, y: -411.10437, z: -183.65768} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1761968135 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1761968133} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 23e3d2944fa834948972e81b26ffc4fa, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocatorScene.unity.meta b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocatorScene.unity.meta new file mode 100644 index 0000000..f503427 --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/ServiceLocatorScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1e9d4c7e4d3ed4e4da7f2248a4cf22b9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services.meta b/Assets/Patterns/15. Service Locator/Another Implementation/Services.meta new file mode 100644 index 0000000..e65a95a --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c50f12adc46877f4c8ea7cc2d873d35c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services/FirstService.cs b/Assets/Patterns/15. Service Locator/Another Implementation/Services/FirstService.cs new file mode 100644 index 0000000..5ad1715 --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services/FirstService.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace ServiceLocatorPattern +{ + public class FirstService : MonoBehaviour + { + private void Awake() + { + ServiceLocator.Register(this); + } + + private void OnDestroy() + { + ServiceLocator.Unregister(this); + } + + public void SayHi() + { + Debug.Log("Hi, this is the " + nameof(FirstService)); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services/FirstService.cs.meta b/Assets/Patterns/15. Service Locator/Another Implementation/Services/FirstService.cs.meta new file mode 100644 index 0000000..2ec8e33 --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services/FirstService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44d086f170cf84a4b95c0e2a8b703ba5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services/SecondService.cs b/Assets/Patterns/15. Service Locator/Another Implementation/Services/SecondService.cs new file mode 100644 index 0000000..8e02932 --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services/SecondService.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace ServiceLocatorPattern +{ + public class SecondService : MonoBehaviour + { + private void Awake() + { + ServiceLocator.Register(this); + } + + private void OnDestroy() + { + ServiceLocator.Unregister(this); + } + + public void SimpleMethod() + { + Debug.Log("Hey, this is just a simple method from " + nameof(SecondService)); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services/SecondService.cs.meta b/Assets/Patterns/15. Service Locator/Another Implementation/Services/SecondService.cs.meta new file mode 100644 index 0000000..0433c8c --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services/SecondService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1df5c99439826bd48a3d81f94978aca4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services/ThirdService.cs b/Assets/Patterns/15. Service Locator/Another Implementation/Services/ThirdService.cs new file mode 100644 index 0000000..94442aa --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services/ThirdService.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace ServiceLocatorPattern +{ + public class ThirdService : MonoBehaviour + { + private void Awake() + { + ServiceLocator.Register(this); + } + + private void OnDestroy() + { + ServiceLocator.Unregister(this); + } + + public void Foo() + { + Debug.Log("This is Foo method from " + nameof(ThirdService)); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/15. Service Locator/Another Implementation/Services/ThirdService.cs.meta b/Assets/Patterns/15. Service Locator/Another Implementation/Services/ThirdService.cs.meta new file mode 100644 index 0000000..290b6ae --- /dev/null +++ b/Assets/Patterns/15. Service Locator/Another Implementation/Services/ThirdService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23e3d2944fa834948972e81b26ffc4fa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/17. Dirty Flag.meta b/Assets/Patterns/17. Dirty Flag.meta new file mode 100644 index 0000000..960a28c --- /dev/null +++ b/Assets/Patterns/17. Dirty Flag.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77c9e989ac92a844bb175089b867aa1e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/17. Dirty Flag/Unsaved changes.meta b/Assets/Patterns/17. Dirty Flag/Unsaved changes.meta new file mode 100644 index 0000000..114ddaf --- /dev/null +++ b/Assets/Patterns/17. Dirty Flag/Unsaved changes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a0788c2ac06d1164a805996f0c3b38be +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/17. Dirty Flag/Unsaved changes/Unsaved Changes.unity b/Assets/Patterns/17. Dirty Flag/Unsaved changes/Unsaved Changes.unity new file mode 100644 index 0000000..3d579ee --- /dev/null +++ b/Assets/Patterns/17. Dirty Flag/Unsaved changes/Unsaved Changes.unity @@ -0,0 +1,445 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657844, g: 0.49641222, b: 0.57481694, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &862736635 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 862736639} + - component: {fileID: 862736638} + - component: {fileID: 862736637} + - component: {fileID: 862736636} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &862736636 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862736635} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &862736637 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862736635} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &862736638 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862736635} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &862736639 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862736635} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1039853144 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1039853147} + - component: {fileID: 1039853146} + - component: {fileID: 1039853145} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1039853145 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1039853144} + m_Enabled: 1 +--- !u!20 &1039853146 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1039853144} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1039853147 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1039853144} + m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0, y: 10, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0} +--- !u!1 &1504779214 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1504779215} + - component: {fileID: 1504779216} + m_Layer: 0 + m_Name: Controller + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1504779215 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1504779214} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1504779216 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1504779214} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09fde5571358fce43bc9bd2341536d72, type: 3} + m_Name: + m_EditorClassIdentifier: + cubeGO: {fileID: 862736639} +--- !u!1 &1874221320 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1874221322} + - component: {fileID: 1874221321} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1874221321 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874221320} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1874221322 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874221320} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 500, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} diff --git a/Assets/Patterns/17. Dirty Flag/Unsaved changes/Unsaved Changes.unity.meta b/Assets/Patterns/17. Dirty Flag/Unsaved changes/Unsaved Changes.unity.meta new file mode 100644 index 0000000..0b3ca32 --- /dev/null +++ b/Assets/Patterns/17. Dirty Flag/Unsaved changes/Unsaved Changes.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a786ead6dd830e445ac8c90cd2f89db3 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/17. Dirty Flag/Unsaved changes/UnsavedChangesController.cs b/Assets/Patterns/17. Dirty Flag/Unsaved changes/UnsavedChangesController.cs new file mode 100644 index 0000000..870a232 --- /dev/null +++ b/Assets/Patterns/17. Dirty Flag/Unsaved changes/UnsavedChangesController.cs @@ -0,0 +1,60 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class UnsavedChangesController : MonoBehaviour +{ + public Transform cubeGO; + + //This is the Dirty Flag + private bool isSaved = true; + + private readonly float cubeSpeed = 5f; + + + + private void Update() + { + if (Input.GetKey(KeyCode.W)) + { + cubeGO.Translate(cubeSpeed * Time.deltaTime * Vector3.forward); + + isSaved = false; + } + if (Input.GetKey(KeyCode.S)) + { + cubeGO.Translate(cubeSpeed * Time.deltaTime * -Vector3.forward); + + isSaved = false; + } + if (Input.GetKey(KeyCode.A)) + { + cubeGO.Translate(cubeSpeed * Time.deltaTime * -Vector3.right); + + isSaved = false; + } + if (Input.GetKey(KeyCode.D)) + { + cubeGO.Translate(cubeSpeed * Time.deltaTime * Vector3.right); + + isSaved = false; + } + } + + + + private void OnGUI() + { + if (GUILayout.Button("Save")) + { + Debug.Log("Game was saved"); + + isSaved = true; + } + + if (!isSaved) + { + GUILayout.Box("Warning you have unsaved changes"); + } + } +} diff --git a/Assets/Patterns/17. Dirty Flag/Unsaved changes/UnsavedChangesController.cs.meta b/Assets/Patterns/17. Dirty Flag/Unsaved changes/UnsavedChangesController.cs.meta new file mode 100644 index 0000000..1285114 --- /dev/null +++ b/Assets/Patterns/17. Dirty Flag/Unsaved changes/UnsavedChangesController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09fde5571358fce43bc9bd2341536d72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/BulletBase.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/BulletBase.cs new file mode 100644 index 0000000..53cbd4f --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/BulletBase.cs @@ -0,0 +1,36 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace ObjectPool.Gun +{ + //Parent bullet class to avoid code duplication + public class BulletBase : MonoBehaviour + { + private readonly float bulletSpeed = 10f; + + private readonly float deactivationDistance = 30f; + + + + protected void MoveBullet() + { + transform.Translate(bulletSpeed * Time.deltaTime * Vector3.forward); + } + + + + protected bool IsBulletDead() + { + bool isDead = false; + + //The gun is at 0 + if (Vector3.SqrMagnitude(Vector3.zero - transform.position) > deactivationDistance * deactivationDistance) + { + isDead = true; + } + + return isDead; + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/BulletBase.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/BulletBase.cs.meta new file mode 100644 index 0000000..082f19a --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/BulletBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff7490a22b8d5024c9044a74ca383d4f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/GunController.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/GunController.cs similarity index 72% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/GunController.cs rename to Assets/Patterns/18. Object Pool/Gun/Object pools/GunController.cs index 03e65a3..8e97bde 100644 --- a/Assets/Patterns/18. Object Pool/Gun/Scripts/GunController.cs +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/GunController.cs @@ -2,22 +2,29 @@ using System.Collections.Generic; using UnityEngine; + namespace ObjectPool.Gun { public class GunController : MonoBehaviour { - //Pick which object pool you want to use - public BulletObjectPool bulletPool; + //Pick which object pool you want to use by activating it in the hierarchy and drag it to its uncommented slot + + //Simplest possible object pool + //public BulletObjectPoolSimple bulletPool; + //Optimized object pool //public BulletObjectPoolOptimized bulletPool; + //Unity's native object pool + public BulletObjectPoolUnity bulletPool; + //Private - private float rotationSpeed = 60f; + private readonly float rotationSpeed = 60f; private float fireTimer; - private float fireInterval = 0.1f; + private readonly float fireInterval = 0.1f; @@ -35,7 +42,7 @@ void Start() void Update() { - //Rotate gun + //Rotate gun with A and D keys if (Input.GetKey(KeyCode.A)) { transform.Rotate(Vector3.up, -rotationSpeed * Time.deltaTime); @@ -46,17 +53,15 @@ void Update() } - //Fire gun + //Fire gun with spacebar if (Input.GetKey(KeyCode.Space) && fireTimer > fireInterval) { fireTimer = 0f; - GameObject newBullet = GetABullet(); + GameObject newBullet = bulletPool.GetBullet(); if (newBullet != null) { - newBullet.SetActive(true); - newBullet.transform.forward = transform.forward; //Move the bullet to the tip of the gun or it will look strange if we rotate while firing @@ -72,14 +77,5 @@ void Update() //Update the time since we last fired a bullet fireTimer += Time.deltaTime; } - - - - private GameObject GetABullet() - { - GameObject bullet = bulletPool.GetBullet(); - - return bullet; - } } } diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/GunController.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/GunController.cs.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/GunController.cs.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/GunController.cs.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/ObjectPoolBase.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/ObjectPoolBase.cs new file mode 100644 index 0000000..cd59bdd --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/ObjectPoolBase.cs @@ -0,0 +1,17 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace ObjectPool.Gun +{ + //Parent object pool class to avoid code duplication + //You can make a reusable GameObject pool without MonoBehaviour because you can call Object.Instantiate - you just have to pass a prefab GameObject to it on creation. But that could be in a parent class or a pool manager MonoBehaviour. + public class ObjectPoolBase : MonoBehaviour + { + //How many bullets do we start with when the game starts + protected const int INITIAL_POOL_SIZE = 10; + + //Sometimes it can be good to put a limit to how many bullets we can instantiate or we might get millions of them + protected const int MAX_POOL_SIZE = 20; + } +} \ No newline at end of file diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/ObjectPoolBase.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/ObjectPoolBase.cs.meta new file mode 100644 index 0000000..1543cce --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/ObjectPoolBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef6f375cf30597d459c3fc05bd57d66c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Optimized Bullet Prefab.prefab b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/Bullet Prefab Optimized.prefab similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Optimized Bullet Prefab.prefab rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/Bullet Prefab Optimized.prefab diff --git a/Assets/Patterns/18. Object Pool/Gun/Optimized Bullet Prefab.prefab.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/Bullet Prefab Optimized.prefab.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Optimized Bullet Prefab.prefab.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/Bullet Prefab Optimized.prefab.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/BulletObjectPoolOptimized.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/BulletObjectPoolOptimized.cs similarity index 79% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/BulletObjectPoolOptimized.cs rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/BulletObjectPoolOptimized.cs index 800b0d5..cb9dfe7 100644 --- a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/BulletObjectPoolOptimized.cs +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/BulletObjectPoolOptimized.cs @@ -4,27 +4,21 @@ namespace ObjectPool.Gun { - //Has to inherit from MonoBehaviour so we can use Instantiate() - public class BulletObjectPoolOptimized : MonoBehaviour + //This object pool is slightly more complicated to understand but has better performance + public class BulletObjectPoolOptimized : ObjectPoolBase { //The bullet prefab we instantiate public MoveBulletOptimized bulletPrefab; //Store the pooled bullets here - //Instead of GameObject, use MoveBulletOptimized so we dont need a million GetComponent because we need access to that script - private List bullets = new List(); - - //How many bullets do we start with when the game starts - private const int INITIAL_POOL_SIZE = 10; - - //Sometimes it can be good to put a limit to how many bullets we can isntantiate or we might get millions of them - private const int MAX_POOL_SIZE = 20; + private readonly List bullets = new (); //First available bullet, so we don't have to search a list to find it //Instead we create a linked-list where all unused bullets are linked together private MoveBulletOptimized firstAvailable; + private void Start() { if (bulletPrefab == null) @@ -50,10 +44,11 @@ private void Start() } //The last one terminates the linked-list - bullets[bullets.Count - 1].next = null; + bullets[^1].next = null; } + //Generate a single new bullet and put it in the list private void GenerateBullet() { @@ -68,6 +63,7 @@ private void GenerateBullet() } + //A bullet has been deactivated so we need to add it to the linked list public void ConfigureDeactivatedBullet(MoveBulletOptimized deactivatedObj) { @@ -78,6 +74,7 @@ public void ConfigureDeactivatedBullet(MoveBulletOptimized deactivatedObj) } + //Try to get a bullet public GameObject GetBullet() { @@ -90,7 +87,7 @@ public GameObject GetBullet() GenerateBullet(); //The new bullet is last in the list so get it - MoveBulletOptimized lastBullet = bullets[bullets.Count - 1]; + MoveBulletOptimized lastBullet = bullets[^1]; //Add it to the linked list by reusing the method we use for deactivated bullets, so it will now be the first bullet in the linked-list ConfigureDeactivatedBullet(lastBullet); @@ -106,7 +103,11 @@ public GameObject GetBullet() firstAvailable = newBullet.next; - return newBullet.gameObject; + GameObject newBulletGO = newBullet.gameObject; + + newBulletGO.SetActive(true); + + return newBulletGO; } } } diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/BulletObjectPoolOptimized.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/BulletObjectPoolOptimized.cs.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/BulletObjectPoolOptimized.cs.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/BulletObjectPoolOptimized.cs.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/MoveBulletOptimized.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/MoveBulletOptimized.cs similarity index 68% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/MoveBulletOptimized.cs rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/MoveBulletOptimized.cs index c7d827b..e5e6b62 100644 --- a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/MoveBulletOptimized.cs +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/MoveBulletOptimized.cs @@ -4,12 +4,8 @@ namespace ObjectPool.Gun { - public class MoveBulletOptimized : MonoBehaviour + public class MoveBulletOptimized : BulletBase { - private float bulletSpeed = 10f; - - private float deactivationDistance = 30f; - //Needed to optimize object pooling [System.NonSerialized] public MoveBulletOptimized next; //Instead of using this dependency you could use the Observer pattern because other things may happen when the bullet dies @@ -17,11 +13,11 @@ public class MoveBulletOptimized : MonoBehaviour void Update() - { - transform.Translate(Vector3.forward * bulletSpeed * Time.deltaTime); + { + MoveBullet(); //Deactivate the bullet when it's far away - if (Vector3.SqrMagnitude(transform.position) > deactivationDistance * deactivationDistance) + if (IsBulletDead()) { //In the optimized version, we have to tell the object pool that this bullet has been deactivated objectPool.ConfigureDeactivatedBullet(this); diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/MoveBulletOptimized.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/MoveBulletOptimized.cs.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Optimized/MoveBulletOptimized.cs.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Optimized/MoveBulletOptimized.cs.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Slow.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Simple.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Bullet Prefab.prefab b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/Bullet Prefab Simple.prefab similarity index 99% rename from Assets/Patterns/18. Object Pool/Gun/Bullet Prefab.prefab rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/Bullet Prefab Simple.prefab index 2bb05b4..2f5fa8c 100644 --- a/Assets/Patterns/18. Object Pool/Gun/Bullet Prefab.prefab +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/Bullet Prefab Simple.prefab @@ -11,7 +11,7 @@ GameObject: - component: {fileID: 747956090910683963} - component: {fileID: 747956090910683964} m_Layer: 0 - m_Name: Bullet + m_Name: Bullet Prefab Simple m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 diff --git a/Assets/Patterns/18. Object Pool/Gun/Bullet Prefab.prefab.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/Bullet Prefab Simple.prefab.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Bullet Prefab.prefab.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/Bullet Prefab Simple.prefab.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/BulletObjectPool.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/BulletObjectPoolSimple.cs similarity index 58% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/BulletObjectPool.cs rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/BulletObjectPoolSimple.cs index a51828f..6e74b59 100644 --- a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/BulletObjectPool.cs +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/BulletObjectPoolSimple.cs @@ -4,21 +4,16 @@ namespace ObjectPool.Gun { - //Has to inherit from MonoBehaviour so we can use Instantiate() - public class BulletObjectPool : MonoBehaviour + //Simplest possible object pool + public class BulletObjectPoolSimple : ObjectPoolBase { //The bullet prefab we instantiate - public GameObject bulletPrefab; - - //Store the pooled bullets here - private List bullets = new List(); - - //How many bullets do we start with when the game starts - private const int INITIAL_POOL_SIZE = 10; + public MoveBullet bulletPrefab; - //Sometimes it can be good to put a limit to how many bullets we can isntantiate or we might get millions of them - private const int MAX_POOL_SIZE = 20; + //Store the pooled bullets here + private readonly List bullets = new (); + private void Start() { @@ -35,10 +30,11 @@ private void Start() } + //Generate a single new bullet and put it in list private void GenerateBullet() { - GameObject newBullet = Instantiate(bulletPrefab, transform); + GameObject newBullet = Instantiate(bulletPrefab.gameObject, transform); newBullet.SetActive(false); @@ -46,17 +42,18 @@ private void GenerateBullet() } - //Try to get a bullet + + //Get a bullet from the pool public GameObject GetBullet() { //Try to find an inactive bullet - for (int i = 0; i < bullets.Count; i++) + foreach (GameObject bullet in bullets) { - GameObject thisBullet = bullets[i]; - - if (!thisBullet.activeInHierarchy) - { - return thisBullet; + if (!bullet.activeInHierarchy) + { + bullet.SetActive(true); + + return bullet; } } @@ -66,7 +63,9 @@ public GameObject GetBullet() GenerateBullet(); //The new bullet is last in the list so get it - GameObject lastBullet = bullets[bullets.Count - 1]; + GameObject lastBullet = bullets[^1]; + + lastBullet.SetActive(true); return lastBullet; } diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/BulletObjectPool.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/BulletObjectPoolSimple.cs.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/BulletObjectPool.cs.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/BulletObjectPoolSimple.cs.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/MoveBullet.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/MoveBullet.cs new file mode 100644 index 0000000..c8499d2 --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/MoveBullet.cs @@ -0,0 +1,20 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace ObjectPool.Gun +{ + public class MoveBullet : BulletBase + { + void Update() + { + MoveBullet(); + + //Deactivate the bullet when it's far away + if (IsBulletDead()) + { + gameObject.SetActive(false); + } + } + } +} diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/MoveBullet.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/MoveBullet.cs.meta similarity index 100% rename from Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/MoveBullet.cs.meta rename to Assets/Patterns/18. Object Pool/Gun/Object pools/Simple/MoveBullet.cs.meta diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative.meta new file mode 100644 index 0000000..0543a8f --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5f8704ec3d46c524d902721910775a6e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/Bullet Prefab Unity Native.prefab b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/Bullet Prefab Unity Native.prefab new file mode 100644 index 0000000..323dff2 --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/Bullet Prefab Unity Native.prefab @@ -0,0 +1,144 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &747956090910683962 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 747956090910683963} + - component: {fileID: -2170308942933978635} + m_Layer: 0 + m_Name: Bullet Prefab Unity Native + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &747956090910683963 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747956090910683962} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -4.3366795, y: -2.768264, z: -0.27852014} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 747956090950962446} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &-2170308942933978635 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747956090910683962} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a7108424a9ff44d45aa4ee5f7fd5ba79, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &747956090950962445 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 747956090950962446} + - component: {fileID: 747956090950962449} + - component: {fileID: 747956090950962448} + - component: {fileID: 747956090950962447} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &747956090950962446 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747956090950962445} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0.15, y: 0.15, z: 0.15} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 747956090910683963} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!33 &747956090950962449 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747956090950962445} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &747956090950962448 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747956090950962445} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!135 &747956090950962447 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 747956090950962445} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/Bullet Prefab Unity Native.prefab.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/Bullet Prefab Unity Native.prefab.meta new file mode 100644 index 0000000..20cb92b --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/Bullet Prefab Unity Native.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 27c55addebb30864b83d3092b8747516 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/BulletObjectPoolUnity.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/BulletObjectPoolUnity.cs new file mode 100644 index 0000000..6984cb8 --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/BulletObjectPoolUnity.cs @@ -0,0 +1,111 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Pool; + + +namespace ObjectPool.Gun +{ + //Unity has a native object pooling system + //https://docs.unity3d.com/ScriptReference/Pool.IObjectPool_1.html + //Think its still under development so has bugs + public class BulletObjectPoolUnity : ObjectPoolBase + { + //The bullet prefab we instantiate + public MoveBulletUnity bulletPrefab; + + //Unity's native object pool + private ObjectPool allBullets; + + + + private void Start() + { + if (bulletPrefab == null) + { + Debug.LogError("Need a reference to the bullet prefab"); + } + + //Create a new object pool + //You can also create a LinkedPool + allBullets = new ObjectPool( + CreatePooledItem, + OnTakeFromPool, + OnReturnedToPool, + OnDestroyPoolObject, + true, //Collection checks will throw errors if we try to release an item that is already in the pool + INITIAL_POOL_SIZE, + MAX_POOL_SIZE); + } + + + + private void Update() + { + //For some unkown reason if we can create more bullets than MAX_POOL_SIZE. When released they are counted as active but not visible, which might be a bug in Unity because Inactive is the same as MAX_POOL_SIZE so correct? + Debug.Log($"In pool: {allBullets.CountAll}, Active: {allBullets.CountActive}, Inactive: {allBullets.CountInactive}"); + + if (Input.GetKeyDown(KeyCode.K)) + { + //These are doing the same thing for some reason... + //allBullets.Dispose(); + allBullets.Clear(); + } + } + + + + //Add a new item to the pool + private MoveBulletUnity CreatePooledItem() + { + GameObject newBullet = Instantiate(bulletPrefab.gameObject, transform); + + //newBullet.SetActive(false); + + MoveBulletUnity moveBulletScript = newBullet.GetComponent(); + + //The bullet needs a reference to this object pool so we can return it to the pool when it dies + moveBulletScript.objectPool = allBullets; + + return moveBulletScript; + } + + + + //Called when an item is taken from the pool using pool.Get() + private void OnTakeFromPool(MoveBulletUnity bullet) + { + bullet.gameObject.SetActive(true); + } + + + + //Called when an item is returned to the pool using pool.Release() + private void OnReturnedToPool(MoveBulletUnity bullet) + { + bullet.gameObject.SetActive(false); + } + + + + //If the pool capacity is reached then any items returned will be destroyed + private void OnDestroyPoolObject(MoveBulletUnity bullet) + { + Debug.Log("Destroyed pooled object"); + + Destroy(bullet.gameObject); + } + + + + //Get a bullet from the pool + public GameObject GetBullet() + { + //Get an instance from the pool. If the pool is empty then a new instance will be created + //https://docs.unity3d.com/ScriptReference/Pool.IObjectPool_1.html + GameObject newBullet = allBullets.Get().gameObject; + + return newBullet; + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/BulletObjectPoolUnity.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/BulletObjectPoolUnity.cs.meta new file mode 100644 index 0000000..5c6a24c --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/BulletObjectPoolUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b830a0ee49e8224e8eaee518f7cfed3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/MoveBulletUnity.cs b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/MoveBulletUnity.cs new file mode 100644 index 0000000..ba023c2 --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/MoveBulletUnity.cs @@ -0,0 +1,28 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Pool; + +namespace ObjectPool.Gun +{ + public class MoveBulletUnity : BulletBase + { + //Ref to the object pool so we can deactivate dead bullets + public IObjectPool objectPool; + + + + void Update() + { + MoveBullet(); + + //Deactivate the bullet when it's far away + if (IsBulletDead()) + { + //Returns the instance to the pool + //https://docs.unity3d.com/ScriptReference/Pool.IObjectPool_1.html + objectPool.Release(this); + } + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/MoveBulletUnity.cs.meta b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/MoveBulletUnity.cs.meta new file mode 100644 index 0000000..6a419d3 --- /dev/null +++ b/Assets/Patterns/18. Object Pool/Gun/Object pools/UnityNative/MoveBulletUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7108424a9ff44d45aa4ee5f7fd5ba79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/MoveBullet.cs b/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/MoveBullet.cs deleted file mode 100644 index f851285..0000000 --- a/Assets/Patterns/18. Object Pool/Gun/Scripts/Slow/MoveBullet.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace ObjectPool.Gun -{ - public class MoveBullet : MonoBehaviour - { - private float bulletSpeed = 10f; - - private float deactivationDistance = 30f; - - - void Update() - { - transform.Translate(Vector3.forward * bulletSpeed * Time.deltaTime); - - //Deactivate the bullet when it's far away - if (Vector3.SqrMagnitude(transform.position) > deactivationDistance * deactivationDistance) - { - gameObject.SetActive(false); - } - } - } -} diff --git a/Assets/Patterns/18. Object Pool/Gun/object pool gun.unity b/Assets/Patterns/18. Object Pool/Gun/object pool gun.unity index 9807065..7dbfc52 100644 --- a/Assets/Patterns/18. Object Pool/Gun/object pool gun.unity +++ b/Assets/Patterns/18. Object Pool/Gun/object pool gun.unity @@ -43,7 +43,7 @@ RenderSettings: --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 11 + serializedVersion: 12 m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 @@ -54,7 +54,7 @@ LightmapSettings: m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: - serializedVersion: 10 + serializedVersion: 12 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 @@ -62,6 +62,7 @@ LightmapSettings: m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 @@ -76,10 +77,16 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 - m_PVRFilteringMode: 1 + m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 @@ -87,9 +94,11 @@ LightmapSettings: m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ShowResolutionOverlay: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} - m_UseShadowmask: 1 + m_LightingSettings: {fileID: 244224820} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 @@ -109,6 +118,8 @@ NavMeshSettings: manualTileSize: 0 tileSize: 256 accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} @@ -141,6 +152,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: - {fileID: 243783919} m_Father: {fileID: 761632166} @@ -170,9 +182,12 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -184,6 +199,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -196,6 +212,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &71555713 MeshFilter: m_ObjectHideFlags: 0 @@ -233,6 +250,7 @@ Transform: m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} m_LocalPosition: {x: 0, y: -0, z: 1} m_LocalScale: {x: 0.2, y: 1, z: 0.2} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 71555710} m_RootOrder: 0 @@ -262,9 +280,12 @@ MeshRenderer: m_CastShadows: 1 m_ReceiveShadows: 1 m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 m_MotionVectors: 1 m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -276,6 +297,7 @@ MeshRenderer: m_ProbeAnchor: {fileID: 0} m_LightProbeVolumeOverride: {fileID: 0} m_ScaleInLightmap: 1 + m_ReceiveGI: 1 m_PreserveUVs: 0 m_IgnoreNormalsForChartDetection: 0 m_ImportantGI: 0 @@ -288,6 +310,7 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} --- !u!33 &243783922 MeshFilter: m_ObjectHideFlags: 0 @@ -296,6 +319,68 @@ MeshFilter: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 243783918} m_Mesh: {fileID: 10206, guid: 0000000000000000e000000000000000, type: 0} +--- !u!850595691 &244224820 +LightingSettings: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Settings.lighting + serializedVersion: 4 + m_GIWorkflowMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_RealtimeEnvironmentLighting: 1 + m_BounceScale: 1 + m_AlbedoBoost: 1 + m_IndirectOutputScale: 1 + m_UsingShadowmask: 1 + m_BakeBackend: 1 + m_LightmapMaxSize: 1024 + m_BakeResolution: 40 + m_Padding: 2 + m_LightmapCompression: 3 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAO: 0 + m_MixedBakeMode: 2 + m_LightmapsBakeMode: 1 + m_FilterMode: 1 + m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_RealtimeResolution: 2 + m_ForceWhiteAlbedo: 0 + m_ForceUpdates: 0 + m_FinalGather: 0 + m_FinalGatherRayCount: 256 + m_FinalGatherFiltering: 1 + m_PVRCulling: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_LightProbeSampleCountMultiplier: 4 + m_PVRBounces: 2 + m_PVRMinBounces: 2 + m_PVREnvironmentMIS: 0 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_PVRTiledBaking: 0 --- !u!1 &362299604 GameObject: m_ObjectHideFlags: 0 @@ -334,9 +419,10 @@ Camera: m_ClearFlags: 1 m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_GateFitMode: 2 m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 @@ -374,6 +460,7 @@ Transform: m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} m_LocalPosition: {x: 0, y: 10, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -419,6 +506,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: -4.3366795, y: -2.768264, z: -0.27852014} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 4 @@ -434,12 +522,12 @@ GameObject: - component: {fileID: 546990865} - component: {fileID: 546990866} m_Layer: 0 - m_Name: Bullet object pool + m_Name: Bullet object pool simple m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!4 &546990865 Transform: m_ObjectHideFlags: 0 @@ -450,6 +538,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: -4.3366795, y: -2.768264, z: -0.27852014} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 3 @@ -466,7 +555,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 1f92528de463b114083bcb4093cacd8a, type: 3} m_Name: m_EditorClassIdentifier: - bulletPrefab: {fileID: 747956090910683962, guid: 993620b09a1d7804a81460b71ed97893, + bulletPrefab: {fileID: 747956090910683964, guid: 993620b09a1d7804a81460b71ed97893, type: 3} --- !u!1 &761632165 GameObject: @@ -495,6 +584,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: - {fileID: 71555710} m_Father: {fileID: 0} @@ -512,7 +602,53 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 8f12dac7db74c904b8c713df5e80a1aa, type: 3} m_Name: m_EditorClassIdentifier: - bulletPool: {fileID: 546990866} + bulletPool: {fileID: 938094604} +--- !u!1 &938094602 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 938094603} + - component: {fileID: 938094604} + m_Layer: 0 + m_Name: Bullet object pool Unity + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &938094603 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938094602} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &938094604 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 938094602} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8b830a0ee49e8224e8eaee518f7cfed3, type: 3} + m_Name: + m_EditorClassIdentifier: + bulletPrefab: {fileID: -2170308942933978635, guid: 27c55addebb30864b83d3092b8747516, + type: 3} --- !u!1 &2069808499 GameObject: m_ObjectHideFlags: 0 @@ -538,12 +674,14 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2069808499} m_Enabled: 1 - serializedVersion: 8 + serializedVersion: 10 m_Type: 1 + m_Shape: 0 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 m_CookieSize: 10 m_Shadows: m_Type: 2 @@ -553,6 +691,24 @@ Light: m_Bias: 0.05 m_NormalBias: 0.4 m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 m_Cookie: {fileID: 0} m_DrawHalo: 0 m_Flare: {fileID: 0} @@ -560,12 +716,16 @@ Light: m_CullingMask: serializedVersion: 2 m_Bits: 4294967295 + m_RenderingLayerMask: 1 m_Lightmapping: 4 m_LightShadowCasterMode: 0 m_AreaSize: {x: 1, y: 1} m_BounceIntensity: 1 m_ColorTemperature: 6570 m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 m_ShadowRadius: 0 m_ShadowAngle: 0 --- !u!4 &2069808501 @@ -578,6 +738,7 @@ Transform: m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 500, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 1 diff --git a/Assets/Patterns/19. Spatial Partition/Grid/Scripts/GameController.cs b/Assets/Patterns/19. Spatial Partition/Grid/Scripts/GameController.cs index 05f6203..57b43fa 100644 --- a/Assets/Patterns/19. Spatial Partition/Grid/Scripts/GameController.cs +++ b/Assets/Patterns/19. Spatial Partition/Grid/Scripts/GameController.cs @@ -1,4 +1,3 @@ -using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -9,8 +8,6 @@ namespace SpatialPartition.Grid public class GameController : MonoBehaviour { //Drags - public GameObject battlefieldObj; - public Unit unitPrefab; public Transform unitParentTrans; @@ -18,28 +15,28 @@ public class GameController : MonoBehaviour //Private private Grid grid; - //The number of units we start with + //The number of units moving on the map private const int NUMBER_OF_UNITS = 100; //To keep track of all units so we can move them private HashSet allUnits = new HashSet(); + //Display the grid with lines + + //Grid material + private Material gridMaterial; + + //Grid mesh + private Mesh gridMesh; + void Start() { grid = new Grid(); - - //Make the battlefield the same size as the grid float battlefieldWidth = Grid.NUM_CELLS * Grid.CELL_SIZE; - battlefieldObj.transform.localScale = new Vector3(battlefieldWidth, 1f, battlefieldWidth); - - //The grid starts at origo, so we need to change position as well - battlefieldObj.transform.position = new Vector3(battlefieldWidth * 0.5f, 0f, battlefieldWidth * 0.5f); - - //Add units within the grid at random positions for (int i = 0; i < NUMBER_OF_UNITS; i++) { @@ -70,5 +67,75 @@ void Update() //Units attack each other grid.HandleMelee(); } + + + + private void LateUpdate() + { + //Display the grid with lines + if (gridMaterial == null) + { + gridMaterial = new Material(Shader.Find("Unlit/Color")); + + gridMaterial.color = Color.black; + } + + if (grid == null) + { + return; + } + + if (gridMesh == null) + { + gridMesh = InitGridMesh(); + } + + //Display the mesh + Graphics.DrawMesh(gridMesh, Vector3.zero, Quaternion.identity, gridMaterial, 0, Camera.main, 0); + } + + + + private Mesh InitGridMesh() + { + //Generate the vertices + List lineVertices = new (); + + float battlefieldWidth = Grid.NUM_CELLS * Grid.CELL_SIZE; + + Vector3 linePosX = Vector3.zero; + Vector3 linePosY = Vector3.zero; + + for (int x = 0; x <= Grid.NUM_CELLS; x++) + { + lineVertices.Add(linePosX); + lineVertices.Add(linePosX + Vector3.right * battlefieldWidth); + + lineVertices.Add(linePosY); + lineVertices.Add(linePosY + Vector3.forward * battlefieldWidth); + + linePosX += Vector3.forward * Grid.CELL_SIZE; + linePosY += Vector3.right * Grid.CELL_SIZE; + } + + + //Generate the indices + List indices = new (); + + for (int i = 0; i < lineVertices.Count; i++) + { + indices.Add(i); + } + + + //Generate the mesh + Mesh gridMesh = new (); + + gridMesh.SetVertices(lineVertices); + gridMesh.SetIndices(indices, MeshTopology.Lines, 0); + + + return gridMesh; + } } } diff --git a/Assets/Patterns/19. Spatial Partition/Grid/Unit.prefab b/Assets/Patterns/19. Spatial Partition/Grid/Unit prefab.prefab similarity index 99% rename from Assets/Patterns/19. Spatial Partition/Grid/Unit.prefab rename to Assets/Patterns/19. Spatial Partition/Grid/Unit prefab.prefab index b3a2983..2fd62d8 100644 --- a/Assets/Patterns/19. Spatial Partition/Grid/Unit.prefab +++ b/Assets/Patterns/19. Spatial Partition/Grid/Unit prefab.prefab @@ -11,7 +11,7 @@ GameObject: - component: {fileID: 6404582697255075594} - component: {fileID: 6404582697255075593} m_Layer: 0 - m_Name: Unit + m_Name: Unit prefab m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 diff --git a/Assets/Patterns/19. Spatial Partition/Grid/Unit.prefab.meta b/Assets/Patterns/19. Spatial Partition/Grid/Unit prefab.prefab.meta similarity index 100% rename from Assets/Patterns/19. Spatial Partition/Grid/Unit.prefab.meta rename to Assets/Patterns/19. Spatial Partition/Grid/Unit prefab.prefab.meta diff --git a/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partition.unity b/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partition.unity index 9dcc4de..1e80432 100644 --- a/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partition.unity +++ b/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partition.unity @@ -43,7 +43,7 @@ RenderSettings: --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 11 + serializedVersion: 12 m_GIWorkflowMode: 0 m_GISettings: serializedVersion: 2 @@ -54,7 +54,7 @@ LightmapSettings: m_EnableBakedLightmaps: 1 m_EnableRealtimeLightmaps: 1 m_LightmapEditorSettings: - serializedVersion: 10 + serializedVersion: 12 m_Resolution: 2 m_BakeResolution: 40 m_AtlasSize: 1024 @@ -62,6 +62,7 @@ LightmapSettings: m_AOMaxDistance: 1 m_CompAOExponent: 1 m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 m_Padding: 2 m_LightmapParameters: {fileID: 0} m_LightmapsBakeMode: 1 @@ -76,10 +77,16 @@ LightmapSettings: m_PVRDirectSampleCount: 32 m_PVRSampleCount: 500 m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 m_PVRFilterTypeDirect: 0 m_PVRFilterTypeIndirect: 0 m_PVRFilterTypeAO: 0 - m_PVRFilteringMode: 1 + m_PVREnvironmentMIS: 0 m_PVRCulling: 1 m_PVRFilteringGaussRadiusDirect: 1 m_PVRFilteringGaussRadiusIndirect: 5 @@ -87,9 +94,12 @@ LightmapSettings: m_PVRFilteringAtrousPositionSigmaDirect: 0.5 m_PVRFilteringAtrousPositionSigmaIndirect: 2 m_PVRFilteringAtrousPositionSigmaAO: 1 - m_ShowResolutionOverlay: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} - m_UseShadowmask: 1 + m_LightingSettings: {fileID: 4890085278179872738, guid: e997a83e1f1b5d64baa705f6789eaa95, + type: 2} --- !u!196 &4 NavMeshSettings: serializedVersion: 2 @@ -109,86 +119,11 @@ NavMeshSettings: manualTileSize: 0 tileSize: 256 accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 debug: m_Flags: 0 m_NavMeshData: {fileID: 0} ---- !u!1 &401042762 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 401042766} - - component: {fileID: 401042765} - - component: {fileID: 401042764} - m_Layer: 0 - m_Name: Battlefield - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!23 &401042764 -MeshRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 401042762} - m_Enabled: 1 - m_CastShadows: 1 - m_ReceiveShadows: 1 - m_DynamicOccludee: 1 - m_MotionVectors: 1 - m_LightProbeUsage: 1 - m_ReflectionProbeUsage: 1 - m_RenderingLayerMask: 1 - m_RendererPriority: 0 - m_Materials: - - {fileID: 2100000, guid: ea86c1b73dd97f04f9da616aff12971d, type: 2} - m_StaticBatchInfo: - firstSubMesh: 0 - subMeshCount: 0 - m_StaticBatchRoot: {fileID: 0} - m_ProbeAnchor: {fileID: 0} - m_LightProbeVolumeOverride: {fileID: 0} - m_ScaleInLightmap: 1 - m_PreserveUVs: 0 - m_IgnoreNormalsForChartDetection: 0 - m_ImportantGI: 0 - m_StitchLightmapSeams: 0 - m_SelectedEditorRenderState: 3 - m_MinimumChartSize: 4 - m_AutoUVMaxDistance: 0.5 - m_AutoUVMaxAngle: 89 - m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 - m_SortingOrder: 0 ---- !u!33 &401042765 -MeshFilter: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 401042762} - m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} ---- !u!4 &401042766 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 401042762} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 3 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &826587778 GameObject: m_ObjectHideFlags: 0 @@ -199,7 +134,7 @@ GameObject: m_Component: - component: {fileID: 826587779} m_Layer: 0 - m_Name: Units + m_Name: Units parent m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -215,9 +150,10 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_RootOrder: 4 + m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &1033359570 GameObject: @@ -244,12 +180,14 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1033359570} m_Enabled: 1 - serializedVersion: 8 + serializedVersion: 10 m_Type: 1 + m_Shape: 0 m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} m_Intensity: 1 m_Range: 10 m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 m_CookieSize: 10 m_Shadows: m_Type: 2 @@ -259,6 +197,24 @@ Light: m_Bias: 0.05 m_NormalBias: 0.4 m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 m_Cookie: {fileID: 0} m_DrawHalo: 0 m_Flare: {fileID: 0} @@ -266,12 +222,16 @@ Light: m_CullingMask: serializedVersion: 2 m_Bits: 4294967295 + m_RenderingLayerMask: 1 m_Lightmapping: 4 m_LightShadowCasterMode: 0 m_AreaSize: {x: 1, y: 1} m_BounceIntensity: 1 m_ColorTemperature: 6570 m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 m_ShadowRadius: 0 m_ShadowAngle: 0 --- !u!4 &1033359572 @@ -284,6 +244,7 @@ Transform: m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} m_LocalPosition: {x: 0, y: 500, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 1 @@ -326,9 +287,10 @@ Camera: m_ClearFlags: 1 m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 m_SensorSize: {x: 36, y: 24} m_LensShift: {x: 0, y: 0} - m_GateFitMode: 2 m_FocalLength: 50 m_NormalizedViewPortRect: serializedVersion: 2 @@ -366,6 +328,7 @@ Transform: m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068} m_LocalPosition: {x: 25, y: 765, z: 25} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -397,6 +360,7 @@ Transform: m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} m_RootOrder: 2 @@ -413,7 +377,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a5b106aed7d115048a91fdfcbb84005a, type: 3} m_Name: m_EditorClassIdentifier: - battlefieldObj: {fileID: 401042762} unitPrefab: {fileID: 6404582697255075593, guid: c2075d714081c9944b2ae26c74b36e85, type: 3} unitParentTrans: {fileID: 826587779} diff --git a/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partitionSettings.lighting b/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partitionSettings.lighting new file mode 100644 index 0000000..2d2c6a7 --- /dev/null +++ b/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partitionSettings.lighting @@ -0,0 +1,64 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!850595691 &4890085278179872738 +LightingSettings: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: grid spatial partitionSettings + serializedVersion: 4 + m_GIWorkflowMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_RealtimeEnvironmentLighting: 1 + m_BounceScale: 1 + m_AlbedoBoost: 1 + m_IndirectOutputScale: 1 + m_UsingShadowmask: 1 + m_BakeBackend: 1 + m_LightmapMaxSize: 1024 + m_BakeResolution: 40 + m_Padding: 2 + m_LightmapCompression: 3 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAO: 0 + m_MixedBakeMode: 2 + m_LightmapsBakeMode: 1 + m_FilterMode: 1 + m_LightmapParameters: {fileID: 15204, guid: 0000000000000000f000000000000000, type: 0} + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_RealtimeResolution: 2 + m_ForceWhiteAlbedo: 0 + m_ForceUpdates: 0 + m_FinalGather: 0 + m_FinalGatherRayCount: 256 + m_FinalGatherFiltering: 1 + m_PVRCulling: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_LightProbeSampleCountMultiplier: 4 + m_PVRBounces: 2 + m_PVRMinBounces: 2 + m_PVREnvironmentMIS: 0 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_PVRTiledBaking: 0 diff --git a/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partitionSettings.lighting.meta b/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partitionSettings.lighting.meta new file mode 100644 index 0000000..4875a10 --- /dev/null +++ b/Assets/Patterns/19. Spatial Partition/Grid/grid spatial partitionSettings.lighting.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e997a83e1f1b5d64baa705f6789eaa95 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 4890085278179872738 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory.meta b/Assets/Patterns/21. Factory/Sound Factory.meta new file mode 100644 index 0000000..a3c1027 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74b5bebe48ff3b04bb892f299115cbd0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.meta new file mode 100644 index 0000000..8d6c8fc --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b7341156904afd459d215608bc29669 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.unity b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.unity new file mode 100644 index 0000000..2c0e560 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.unity @@ -0,0 +1,347 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657844, g: 0.49641222, b: 0.57481694, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &342860415 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 342860418} + - component: {fileID: 342860417} + - component: {fileID: 342860416} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &342860416 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 342860415} + m_Enabled: 1 +--- !u!20 &342860417 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 342860415} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &342860418 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 342860415} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &639523981 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 639523983} + - component: {fileID: 639523982} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &639523982 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 639523981} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &639523983 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 639523981} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 500, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &668650341 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 668650343} + - component: {fileID: 668650342} + m_Layer: 0 + m_Name: Controller + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &668650342 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668650341} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b3a1e2bdd8cc40047a19e88376287061, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &668650343 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 668650341} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.unity.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.unity.meta new file mode 100644 index 0000000..bf20bf8 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: bdc9e85ada39fc2488dc080ea5146a0b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemFactory.cs b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemFactory.cs new file mode 100644 index 0000000..e307d97 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemFactory.cs @@ -0,0 +1,41 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Factory.SoundFactory +{ + public class SoundSystemFactory + { + public enum SoundSystemType + { + SoundSoftware, + SoundHardware, + SoundSomethingElse + }; + + + + public static ISoundSystem CreateSoundSystem(SoundSystemType type) + { + ISoundSystem soundSystem; + + switch (type) + { + case SoundSystemType.SoundSoftware: + soundSystem = new SoundSystemSoftware(); + break; + case SoundSystemType.SoundHardware: + soundSystem = new SoundSystemHardware(); + break; + case SoundSystemType.SoundSomethingElse: + soundSystem = new SoundSystemOther(); + break; + default: + soundSystem = null; + break; + } + + return soundSystem; + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemFactory.cs.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemFactory.cs.meta new file mode 100644 index 0000000..8016a05 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ea46278d7b45a841a7eadfd61a7a8db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS.meta new file mode 100644 index 0000000..e0450e2 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c44bfa19f4ff4aa4191e769e0575e42b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/ISoundSystem.cs b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/ISoundSystem.cs new file mode 100644 index 0000000..8965c2c --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/ISoundSystem.cs @@ -0,0 +1,14 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Factory.SoundFactory +{ + public interface ISoundSystem + { + public bool PlaySound(int soundId); + + public bool StopSound(int soundId); + + } +} \ No newline at end of file diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/ISoundSystem.cs.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/ISoundSystem.cs.meta new file mode 100644 index 0000000..958be2a --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/ISoundSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f9bb6afc44034d418456572cf8e3648 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemHardware.cs b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemHardware.cs new file mode 100644 index 0000000..7cf383f --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemHardware.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Factory.SoundFactory +{ + public class SoundSystemHardware : ISoundSystem + { + public bool PlaySound(int soundId) + { + Debug.Log($"Played the sound with id {soundId} on the hardware"); + + return true; + } + + public bool StopSound(int soundId) + { + Debug.Log($"Stopped the sound with id {soundId} on the hardware"); + + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemHardware.cs.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemHardware.cs.meta new file mode 100644 index 0000000..e5d10d8 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemHardware.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cee45bef4f0457c488e4637103cfeed2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemOther.cs b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemOther.cs new file mode 100644 index 0000000..3ae24f6 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemOther.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Factory.SoundFactory +{ + public class SoundSystemOther : ISoundSystem + { + public bool PlaySound(int soundId) + { + Debug.Log($"Played the sound with id {soundId} on some other system"); + + return true; + } + + public bool StopSound(int soundId) + { + Debug.Log($"Stopped the sound with id {soundId} on some other system"); + + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemOther.cs.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemOther.cs.meta new file mode 100644 index 0000000..829efe4 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemOther.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f7e9f3a97b30194cafe32968f099bd5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemSoftware.cs b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemSoftware.cs new file mode 100644 index 0000000..a6a15bd --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemSoftware.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Factory.SoundFactory +{ + public class SoundSystemSoftware : ISoundSystem + { + public bool PlaySound(int soundId) + { + Debug.Log($"Played the sound with id {soundId} on the software"); + + return true; + } + + public bool StopSound(int soundId) + { + Debug.Log($"Stopped the sound with id {soundId} on the software"); + + return true; + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemSoftware.cs.meta b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemSoftware.cs.meta new file mode 100644 index 0000000..d161f9e --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/Sound Factory/SoundSystemS/SoundSystemSoftware.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac71d05d035d3fe418df0b24bf9cc6d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/21. Factory/Sound Factory/SoundFactoryController.cs b/Assets/Patterns/21. Factory/Sound Factory/SoundFactoryController.cs new file mode 100644 index 0000000..cc18043 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/SoundFactoryController.cs @@ -0,0 +1,28 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Factory.SoundFactory; + + +//Example of Factory programming pattern from "Game Programming Gems 2:" 1.3 Programming with abstract interfaces +public class SoundFactoryController : MonoBehaviour +{ + private void Start() + { + ISoundSystem soundSystemSoftware = SoundSystemFactory.CreateSoundSystem(SoundSystemFactory.SoundSystemType.SoundSoftware); + + soundSystemSoftware.PlaySound(1); + + ISoundSystem soundSystemHardware = SoundSystemFactory.CreateSoundSystem(SoundSystemFactory.SoundSystemType.SoundHardware); + + soundSystemHardware.PlaySound(2); + + ISoundSystem soundSystemOther = SoundSystemFactory.CreateSoundSystem(SoundSystemFactory.SoundSystemType.SoundSomethingElse); + + soundSystemOther.PlaySound(3); + + soundSystemSoftware.StopSound(1); + soundSystemHardware.StopSound(2); + soundSystemOther.StopSound(3); + } +} diff --git a/Assets/Patterns/21. Factory/Sound Factory/SoundFactoryController.cs.meta b/Assets/Patterns/21. Factory/Sound Factory/SoundFactoryController.cs.meta new file mode 100644 index 0000000..fdcbce3 --- /dev/null +++ b/Assets/Patterns/21. Factory/Sound Factory/SoundFactoryController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3a1e2bdd8cc40047a19e88376287061 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade.meta b/Assets/Patterns/22. Facade.meta new file mode 100644 index 0000000..bed15f4 --- /dev/null +++ b/Assets/Patterns/22. Facade.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 696fda268bb811f4da353a0398a362f8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers.meta b/Assets/Patterns/22. Facade/Random numbers.meta new file mode 100644 index 0000000..1fc342e --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39e763d53a8a7144498854ba5348f936 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade.meta b/Assets/Patterns/22. Facade/Random numbers/Facade.meta new file mode 100644 index 0000000..b03ca28 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e4db7356e2325a44900d6c52a8cfc4f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberFacade.cs b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberFacade.cs new file mode 100644 index 0000000..83ad720 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberFacade.cs @@ -0,0 +1,43 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Facade.RandomNumbers +{ + public class RandomNumberFacade + { + private static IRandomNumberGenerator rng; + + + static RandomNumberFacade() + { + //The only line of code you need to change if you want to test different random number generators + //rng = new RandomNumbersNative(); + rng = new RandomNumbersUnity(); + } + + + public static void InitSeed(int seed) + { + rng.InitSeed(seed); + } + + + public static float GetRandom01() + { + return rng.GetRandom01(); + } + + + public static float GetRandom(float min, float max) + { + return rng.GetRandom(min, max); + } + + + public static int GetRandomInt(int min, int max) + { + return rng.GetRandomInt(min, max); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberFacade.cs.meta b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberFacade.cs.meta new file mode 100644 index 0000000..66ab0da --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberFacade.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50e552fc33acdef48a542838e1f7cebc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators.meta b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators.meta new file mode 100644 index 0000000..f06d5ae --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f0ffc37fc25416f48bb81d8c9137f0d7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/IRandomNumberGenerator.cs b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/IRandomNumberGenerator.cs new file mode 100644 index 0000000..431a29c --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/IRandomNumberGenerator.cs @@ -0,0 +1,18 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Facade.RandomNumbers +{ + //This is the Adapter pattern to easier work with the Facade + public interface IRandomNumberGenerator + { + public void InitSeed(int seed); + + public float GetRandom01(); + + public float GetRandom(float min, float max); + + public int GetRandomInt(int min, int max); + } +} \ No newline at end of file diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/IRandomNumberGenerator.cs.meta b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/IRandomNumberGenerator.cs.meta new file mode 100644 index 0000000..ffd9ae0 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/IRandomNumberGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ae23077a0a61a74989d92806d610a30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersNative.cs b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersNative.cs new file mode 100644 index 0000000..aba027b --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersNative.cs @@ -0,0 +1,37 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Facade.RandomNumbers +{ + //Generate random numbers by using C#'s System.Random + public class RandomNumbersNative : IRandomNumberGenerator + { + private System.Random rng; + + public RandomNumbersNative() + { + rng = new System.Random(); + } + + public float GetRandom(float min, float max) + { + return (float)((rng.NextDouble() * (max - min)) + min); + } + + public float GetRandom01() + { + return (float)rng.NextDouble(); + } + + public int GetRandomInt(int min, int max) + { + return rng.Next(min, max); + } + + public void InitSeed(int seed) + { + rng = new System.Random(seed); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersNative.cs.meta b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersNative.cs.meta new file mode 100644 index 0000000..164da74 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersNative.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c613d195d3b90748b9c797f521c32bd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersUnity.cs b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersUnity.cs new file mode 100644 index 0000000..225def1 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersUnity.cs @@ -0,0 +1,30 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace Facade.RandomNumbers +{ + //Geerate random numbers by using Unity's Random.Range + public class RandomNumbersUnity : IRandomNumberGenerator + { + public float GetRandom(float min, float max) + { + return Random.Range(min, max); + } + + public float GetRandom01() + { + return Random.Range(0f, 1f); + } + + public int GetRandomInt(int min, int max) + { + return Random.Range(min, max); + } + + public void InitSeed(int seed) + { + Random.InitState(seed); + } + } +} \ No newline at end of file diff --git a/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersUnity.cs.meta b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersUnity.cs.meta new file mode 100644 index 0000000..f664757 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/Facade/RandomNumberGenerators/RandomNumbersUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0180d38100d299a4bb2743d779b71ea7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/RandomNumbersController.cs b/Assets/Patterns/22. Facade/Random numbers/RandomNumbersController.cs new file mode 100644 index 0000000..00a0e20 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/RandomNumbersController.cs @@ -0,0 +1,38 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using Facade.RandomNumbers; + +//Example of the Facade programming pattern +//To implement the Facade I had to use the Adapter pattern, so you get that as well as a bonus +public class RandomNumbersController : MonoBehaviour +{ + private void Start() + { + RandomNumberFacade.InitSeed(0); + + Debug.Log("Float: 0 -> 1"); + + for (int i = 0; i < 5; i++) + { + Debug.Log(RandomNumberFacade.GetRandom01()); + } + + Debug.Log("Float: -1 -> 2"); + + for (int i = 0; i < 10; i++) + { + Debug.Log(RandomNumberFacade.GetRandom(-1f, 2f)); + } + + Debug.Log("Integer: -10 -> 20"); + + for (int i = 0; i < 10; i++) + { + Debug.Log(RandomNumberFacade.GetRandomInt(-10, 21)); + } + } + + + +} diff --git a/Assets/Patterns/22. Facade/Random numbers/RandomNumbersController.cs.meta b/Assets/Patterns/22. Facade/Random numbers/RandomNumbersController.cs.meta new file mode 100644 index 0000000..90c07bb --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/RandomNumbersController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 798f9c44c3fda5f499346528b20608e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Facade/Random numbers/random numbers.unity b/Assets/Patterns/22. Facade/Random numbers/random numbers.unity new file mode 100644 index 0000000..a2d8245 --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/random numbers.unity @@ -0,0 +1,347 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657844, g: 0.49641222, b: 0.57481694, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &714423619 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 714423621} + - component: {fileID: 714423620} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &714423620 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 714423619} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &714423621 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 714423619} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 500, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1028895537 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1028895539} + - component: {fileID: 1028895538} + m_Layer: 0 + m_Name: Controller + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1028895538 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1028895537} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 798f9c44c3fda5f499346528b20608e8, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &1028895539 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1028895537} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1728729388 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1728729391} + - component: {fileID: 1728729390} + - component: {fileID: 1728729389} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1728729389 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1728729388} + m_Enabled: 1 +--- !u!20 &1728729390 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1728729388} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1728729391 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1728729388} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Patterns/22. Facade/Random numbers/random numbers.unity.meta b/Assets/Patterns/22. Facade/Random numbers/random numbers.unity.meta new file mode 100644 index 0000000..67f0fce --- /dev/null +++ b/Assets/Patterns/22. Facade/Random numbers/random numbers.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 33f0b3673d073bc4286a0b6843d430e6 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Patterns/22. Template.meta b/Assets/Patterns/23. Template.meta similarity index 100% rename from Assets/Patterns/22. Template.meta rename to Assets/Patterns/23. Template.meta diff --git a/Assets/Patterns/22. Template/Assemble cars.meta b/Assets/Patterns/23. Template/Assemble cars.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars.meta rename to Assets/Patterns/23. Template/Assemble cars.meta diff --git a/Assets/Patterns/22. Template/Assemble cars/AssembleCarsController.cs b/Assets/Patterns/23. Template/Assemble cars/AssembleCarsController.cs similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/AssembleCarsController.cs rename to Assets/Patterns/23. Template/Assemble cars/AssembleCarsController.cs diff --git a/Assets/Patterns/22. Template/Assemble cars/AssembleCarsController.cs.meta b/Assets/Patterns/23. Template/Assemble cars/AssembleCarsController.cs.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/AssembleCarsController.cs.meta rename to Assets/Patterns/23. Template/Assemble cars/AssembleCarsController.cs.meta diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line.meta b/Assets/Patterns/23. Template/Assemble cars/Assembly line.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line.meta rename to Assets/Patterns/23. Template/Assemble cars/Assembly line.meta diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleCybertruck.cs b/Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleCybertruck.cs similarity index 93% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleCybertruck.cs rename to Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleCybertruck.cs index 955ca77..2a8cc31 100644 --- a/Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleCybertruck.cs +++ b/Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleCybertruck.cs @@ -26,7 +26,7 @@ protected override void GetWheels() Debug.Log("Get Cybertruck wheels"); } - protected override bool CanManuFactureCar() + protected override bool CanManufactureCar() { Debug.Log("Sorry but the Cybertruck is still a prototype so we can't manufacture it!"); diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleCybertruck.cs.meta b/Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleCybertruck.cs.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleCybertruck.cs.meta rename to Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleCybertruck.cs.meta diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleModelS.cs b/Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleModelS.cs similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleModelS.cs rename to Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleModelS.cs diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleModelS.cs.meta b/Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleModelS.cs.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line/AssembleModelS.cs.meta rename to Assets/Patterns/23. Template/Assemble cars/Assembly line/AssembleModelS.cs.meta diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line/_AssemblyLine.cs b/Assets/Patterns/23. Template/Assemble cars/Assembly line/_AssemblyLine.cs similarity index 95% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line/_AssemblyLine.cs rename to Assets/Patterns/23. Template/Assemble cars/Assembly line/_AssemblyLine.cs index 045254d..081ca72 100644 --- a/Assets/Patterns/22. Template/Assemble cars/Assembly line/_AssemblyLine.cs +++ b/Assets/Patterns/23. Template/Assemble cars/Assembly line/_AssemblyLine.cs @@ -15,7 +15,7 @@ public void AssembleCar(List carExtras = null) { InitAssemblyProcess(); - if (!CanManuFactureCar()) + if (!CanManufactureCar()) { return; } @@ -76,7 +76,7 @@ protected void GetCarExtras(List carExtras) //...and hooks which is a method the child can override if needed - protected virtual bool CanManuFactureCar() + protected virtual bool CanManufactureCar() { return true; } diff --git a/Assets/Patterns/22. Template/Assemble cars/Assembly line/_AssemblyLine.cs.meta b/Assets/Patterns/23. Template/Assemble cars/Assembly line/_AssemblyLine.cs.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/Assembly line/_AssemblyLine.cs.meta rename to Assets/Patterns/23. Template/Assemble cars/Assembly line/_AssemblyLine.cs.meta diff --git a/Assets/Patterns/22. Template/Assemble cars/assemble-cars.unity b/Assets/Patterns/23. Template/Assemble cars/assemble-cars.unity similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/assemble-cars.unity rename to Assets/Patterns/23. Template/Assemble cars/assemble-cars.unity diff --git a/Assets/Patterns/22. Template/Assemble cars/assemble-cars.unity.meta b/Assets/Patterns/23. Template/Assemble cars/assemble-cars.unity.meta similarity index 100% rename from Assets/Patterns/22. Template/Assemble cars/assemble-cars.unity.meta rename to Assets/Patterns/23. Template/Assemble cars/assemble-cars.unity.meta diff --git a/Assets/Patterns/3. Observer/Different events/DifferentEventAlternatives.cs b/Assets/Patterns/3. Observer/Different events/DifferentEventAlternatives.cs index ef5a861..c62077c 100644 --- a/Assets/Patterns/3. Observer/Different events/DifferentEventAlternatives.cs +++ b/Assets/Patterns/3. Observer/Different events/DifferentEventAlternatives.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; +using UnityEngine.Serialization; namespace Observer.DifferentEvents { @@ -27,7 +28,7 @@ public class DifferentEventAlternatives : MonoBehaviour //Unity built-in UnityEvent //Requires that we are "using UnityEngine.Events;" - public UnityEvent coolUnityEvent = new UnityEvent(); + [FormerlySerializedAs("CoolUnityEvent")] public UnityEvent coolUnityEvent = new UnityEvent(); //If you have parameters you have to create a new event class that inherits from UnityEvent public MyCustomUnityEvent coolCustomUnityEvent = new MyCustomUnityEvent(); //There's also something called UnityAction @@ -49,26 +50,31 @@ public class DifferentEventAlternatives : MonoBehaviour //Custom delegate with the same parameters as built-in EventHandler public delegate void MyEventHandler(object sender, EventArgs e); //Custom delegate with no parameters + + public MyEventHandler myEventHandler; + public delegate void MyEventHandlerEmpty(); //The event belonging to the custom delegate - public event MyEventHandlerEmpty MyCoolCustomEvent; + public event MyEventHandlerEmpty myCoolCustomEvent; void Start() { - //MyCoolEvent += DisplayStuff; + myCoolEvent += DisplayStuff; - //MyCoolEventWithParameters += DisplayStuffCustom; + myCoolEventWithParameters += DisplayStuffCustomArgs; - //MyCoolEventAction += DisplayStuffCustomBig; + myCoolEventAction += DisplayStuffCustomParameters; - //CoolUnityEvent.AddListener(DisplayStuffEmpty); + coolUnityEvent.AddListener(DisplayStuffEmpty); coolCustomUnityEvent.AddListener(DisplayStuffCustomParameters); - //MyCoolCustomEvent += DisplayStuffEmpty; + myCoolCustomEvent += DisplayStuffEmpty; + + myEventHandler += DisplayStuff; } @@ -78,20 +84,20 @@ void Update() if (Input.GetKeyDown(KeyCode.Space)) { //Built-in - //myCoolEvent?.Invoke(this, null); + myCoolEvent?.Invoke(this, null); - //MyCoolEventWithParameters?.Invoke(this, new MyName("InsertFunnyName")); + myCoolEventWithParameters?.Invoke(this, new MyName("InsertFunnyName")); - //MyCoolEventAction?.Invoke(new MyName("InsertFunnyName"), new MyAge(5)); + myCoolEventAction?.Invoke(new MyName("InsertFunnyName"), new MyAge(5)); - //CoolUnityEvent?.Invoke(); + coolUnityEvent?.Invoke(); coolCustomUnityEvent?.Invoke(new MyName("InsertFunnyName"), new MyAge(5)); //Custom - //MyCoolCustomEvent?.Invoke(this, null); + myEventHandler?.Invoke(this, null); - //MyCoolCustomEvent?.Invoke(); + myCoolCustomEvent?.Invoke(); } } diff --git a/Assets/Patterns/4. Prototype/Monster spawner/Scripts/SpawnController.cs b/Assets/Patterns/4. Prototype/Monster spawner/Scripts/SpawnController.cs index bad4652..55b036b 100644 --- a/Assets/Patterns/4. Prototype/Monster spawner/Scripts/SpawnController.cs +++ b/Assets/Patterns/4. Prototype/Monster spawner/Scripts/SpawnController.cs @@ -42,11 +42,11 @@ void Update() newGhost.Talk(); - //Spawner randomSpawner = monsterSpawners[Random.Range(0, monsterSpawners.Length)]; + Spawner randomSpawner = monsterSpawners[Random.Range(0, monsterSpawners.Length)]; - //_Monster randomMonster = randomSpawner.SpawnMonster(); + _Monster randomMonster = randomSpawner.SpawnMonster(); - //randomMonster.Talk(); + randomMonster.Talk(); //We can't use Unity's built-in Instantiate method because those objects have to inherit from Object diff --git a/Assets/Patterns/5. Singleton/Scripts/GameController.cs b/Assets/Patterns/5. Singleton/Scripts/GameController.cs index f6215d9..e6aab30 100644 --- a/Assets/Patterns/5. Singleton/Scripts/GameController.cs +++ b/Assets/Patterns/5. Singleton/Scripts/GameController.cs @@ -11,7 +11,7 @@ void Start() { TestCSharpSingleton(); - //TestUnitySingleton(); + TestUnitySingleton(); } diff --git a/Assets/Patterns/5. Singleton/Scripts/SingletonUnity.cs b/Assets/Patterns/5. Singleton/Scripts/SingletonUnity.cs index b73e8bf..aca0501 100644 --- a/Assets/Patterns/5. Singleton/Scripts/SingletonUnity.cs +++ b/Assets/Patterns/5. Singleton/Scripts/SingletonUnity.cs @@ -1,5 +1,3 @@ -using System.Collections; -using System.Collections.Generic; using UnityEngine; // @@ -13,14 +11,10 @@ public class SingletonUnity : MonoBehaviour { //A static variable which holds a reference to the single created instance private static SingletonUnity instance = null; - - - + //For testing that we only call the constructor once private float randomNumber; - - - + //A public static means of getting the reference to the single created instance, creating one if necessary public static SingletonUnity Instance { @@ -28,36 +22,20 @@ public static SingletonUnity Instance { if (instance == null) { - //If a script in Unity inherits from MonoBehaviour, we can't use the new keyword to create a new Singleton as we did before - //So you have to manually add this script to a gameobject in the scene - //But because we inherit from MonoBehaviour whem might have accidentally added several of them to the scene, which will cause trouble, so we have to make sure we have just one! - - //Find all singletons of this type in the scene - SingletonUnity[] allSingletonsInScene = GameObject.FindObjectsOfType(); + // Find singleton of this type in the scene + var instance = GameObject.FindObjectOfType(); - if (allSingletonsInScene != null && allSingletonsInScene.Length > 0) + // If there is no singleton object in the scene, we have to add one + if (instance == null) { - //Destroy all but one singleton - if (allSingletonsInScene.Length > 1) - { - Debug.LogWarning($"You have more than one SingletonUnity in the scene!"); - - for (int i = 1; i < allSingletonsInScene.Length; i++) - { - Destroy(allSingletonsInScene[i].gameObject); - } - } - - //Now we should have just one singleton in the scene, so pick it - instance = allSingletonsInScene[0]; + GameObject obj = new GameObject("Unity Singleton"); + instance = obj.AddComponent(); //Init the singleton instance.FakeConstructor(); - } - //We have no singletons in the scene - else - { - Debug.LogError($"You need to add the script SingletonUnity to a gameobject in the scene!"); + + // The singleton object shouldn't be destroyed when we switch between scenes + DontDestroyOnLoad(obj); } } @@ -65,6 +43,25 @@ public static SingletonUnity Instance } } + void Awake() + { + if (instance == null) + { + instance = this; + + // Init the singleton + instance.FakeConstructor(); + + // The singleton object shouldn't be destroyed when we switch between scenes + DontDestroyOnLoad(this.gameObject); + } + // because we inherit from MonoBehaviour whem might have accidentally added several of them to the scene, + // which will cause trouble, so we have to make sure we have just one! + else + { + Destroy(gameObject); + } + } //Because this script inherits from MonoBehaviour, we cant use a constructor, so we have to invent our own diff --git a/Assets/Patterns/7. Double Buffer/Cave/Cave mat.mat b/Assets/Patterns/7. Double Buffer/Cave/Cave mat.mat index 1847db3..40d5ad2 100644 --- a/Assets/Patterns/7. Double Buffer/Cave/Cave mat.mat +++ b/Assets/Patterns/7. Double Buffer/Cave/Cave mat.mat @@ -75,3 +75,4 @@ Material: m_Colors: - _Color: {r: 1, g: 1, b: 1, a: 1} - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + m_BuildTextureStacks: [] diff --git a/Assets/Patterns/9. Update/Custom Update method/Scripts/GameController.cs b/Assets/Patterns/9. Update/Custom Update method/Scripts/GameController.cs index a737caa..f5dc36c 100644 --- a/Assets/Patterns/9. Update/Custom Update method/Scripts/GameController.cs +++ b/Assets/Patterns/9. Update/Custom Update method/Scripts/GameController.cs @@ -63,7 +63,7 @@ public static void RegisterUpdateableObject(IUpdateable obj) //Unregister public static void UnregisterUpdateableObject(IUpdateable obj) { - if (!updateableObjects.Contains(obj)) + if (updateableObjects.Contains(obj)) { updateableObjects.Remove(obj); } diff --git a/Packages/manifest.json b/Packages/manifest.json index 9ac52f1..a498c9e 100644 --- a/Packages/manifest.json +++ b/Packages/manifest.json @@ -2,11 +2,13 @@ "dependencies": { "com.unity.2d.sprite": "1.0.0", "com.unity.2d.tilemap": "1.0.0", - "com.unity.ide.rider": "1.1.4", - "com.unity.ide.vscode": "1.2.3", - "com.unity.test-framework": "1.1.19", - "com.unity.textmeshpro": "2.0.1", - "com.unity.timeline": "1.2.6", + "com.unity.ai.navigation": "1.1.5", + "com.unity.ide.rider": "3.0.28", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.33", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.7.6", "com.unity.ugui": "1.0.0", "com.unity.modules.ai": "1.0.0", "com.unity.modules.androidjni": "1.0.0", diff --git a/Packages/packages-lock.json b/Packages/packages-lock.json index a19ae12..ed57cc3 100644 --- a/Packages/packages-lock.json +++ b/Packages/packages-lock.json @@ -10,44 +10,65 @@ "version": "1.0.0", "depth": 0, "source": "builtin", - "dependencies": {} + "dependencies": { + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.uielements": "1.0.0" + } + }, + "com.unity.ai.navigation": { + "version": "1.1.5", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.ai": "1.0.0" + }, + "url": "https://packages.unity.com/" }, "com.unity.ext.nunit": { - "version": "1.0.5", + "version": "1.0.6", "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com/" }, "com.unity.ide.rider": { - "version": "1.1.4", + "version": "3.0.28", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com/" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.22", "depth": 0, "source": "registry", "dependencies": { - "com.unity.test-framework": "1.1.1" + "com.unity.test-framework": "1.1.9" }, "url": "https://packages.unity.com/" }, "com.unity.ide.vscode": { - "version": "1.2.3", + "version": "1.2.5", "depth": 0, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com/" }, "com.unity.test-framework": { - "version": "1.1.19", + "version": "1.1.33", "depth": 0, "source": "registry", "dependencies": { - "com.unity.ext.nunit": "1.0.5", + "com.unity.ext.nunit": "1.0.6", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" }, "url": "https://packages.unity.com/" }, "com.unity.textmeshpro": { - "version": "2.0.1", + "version": "3.0.6", "depth": 0, "source": "registry", "dependencies": { @@ -56,10 +77,15 @@ "url": "https://packages.unity.com/" }, "com.unity.timeline": { - "version": "1.2.6", + "version": "1.7.6", "depth": 0, "source": "registry", - "dependencies": {}, + "dependencies": { + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, "url": "https://packages.unity.com/" }, "com.unity.ugui": { @@ -204,6 +230,7 @@ "depth": 0, "source": "builtin", "dependencies": { + "com.unity.modules.ui": "1.0.0", "com.unity.modules.imgui": "1.0.0", "com.unity.modules.jsonserialize": "1.0.0" } diff --git a/ProjectSettings/MemorySettings.asset b/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/ProjectSettings/PackageManagerSettings.asset b/ProjectSettings/PackageManagerSettings.asset index ca9e773..be4a797 100644 --- a/ProjectSettings/PackageManagerSettings.asset +++ b/ProjectSettings/PackageManagerSettings.asset @@ -9,9 +9,12 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 13960, guid: 0000000000000000e000000000000000, type: 0} + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} m_Name: m_EditorClassIdentifier: + m_EnablePreviewPackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 m_ScopedRegistriesSettingsExpanded: 1 oneTimeWarningShown: 0 m_Registries: @@ -20,6 +23,7 @@ MonoBehaviour: m_Url: https://packages.unity.com m_Scopes: [] m_IsDefault: 1 + m_Capabilities: 7 m_UserSelectedRegistryName: m_UserAddingNewScopedRegistry: 0 m_RegistryInfoDraft: @@ -30,6 +34,7 @@ MonoBehaviour: m_Url: m_Scopes: [] m_IsDefault: 0 + m_Capabilities: 0 m_Modified: 0 m_Name: m_Url: diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset index c014d9a..c77cc84 100644 --- a/ProjectSettings/ProjectSettings.asset +++ b/ProjectSettings/ProjectSettings.asset @@ -3,7 +3,7 @@ --- !u!129 &1 PlayerSettings: m_ObjectHideFlags: 0 - serializedVersion: 18 + serializedVersion: 23 productGUID: 187355f5b086cdd42a3be6ad96be1b27 AndroidProfiler: 0 AndroidFilterTouchesWhenObscured: 0 @@ -49,10 +49,11 @@ PlayerSettings: m_StereoRenderingPath: 0 m_ActiveColorSpace: 0 m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 m_StackTraceTypes: 010000000100000001000000010000000100000001000000 iosShowActivityIndicatorOnLoading: -1 androidShowActivityIndicatorOnLoading: -1 - displayResolutionDialog: 1 iosUseCustomAppBackgroundBehavior: 0 iosAllowHTTPDownload: 1 allowedAutorotateToPortrait: 1 @@ -65,7 +66,14 @@ PlayerSettings: disableDepthAndStencilBuffers: 0 androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 0 + androidUseSwappy: 0 androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 defaultIsNativeResolution: 1 macRetinaSupport: 1 runInBackground: 1 @@ -79,11 +87,11 @@ PlayerSettings: usePlayerLog: 1 bakeCollisionMeshes: 0 forceSingleInstance: 0 + useFlipModelSwapchain: 1 resizableWindow: 0 useMacAppStoreValidation: 0 macAppStoreCategory: public.app-category.games gpuSkinning: 1 - graphicsJobs: 0 xboxPIXTextureCapture: 0 xboxEnableAvatar: 0 xboxEnableKinect: 0 @@ -91,7 +99,6 @@ PlayerSettings: xboxEnableFitness: 0 visibleInBackground: 1 allowFullscreenSwitch: 1 - graphicsJobMode: 0 fullscreenMode: 1 xboxSpeechDB: 0 xboxEnableHeadOrientation: 0 @@ -104,6 +111,7 @@ PlayerSettings: xboxOneMonoLoggingLevel: 0 xboxOneLoggingLevel: 1 xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 xboxOnePresentImmediateThreshold: 0 switchQueueCommandMemory: 0 switchQueueControlMemory: 16384 @@ -111,7 +119,15 @@ PlayerSettings: switchNVNShaderPoolsGranularity: 33554432 switchNVNDefaultPoolsGranularity: 16777216 switchNVNOtherPoolsGranularity: 16777216 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 m_SupportedAspectRatios: 4:3: 1 5:4: 1 @@ -125,40 +141,27 @@ PlayerSettings: m_HolographicPauseOnTrackingLoss: 1 xboxOneDisableKinectGpuReservation: 1 xboxOneEnable7thCore: 1 - isWsaHolographicRemotingEnabled: 0 vrSettings: - cardboard: - depthFormat: 0 - enableTransitionView: 0 - daydream: - depthFormat: 0 - useSustainedPerformanceMode: 0 - enableVideoLayer: 0 - useProtectedVideoMemory: 0 - minimumSupportedHeadTracking: 0 - maximumSupportedHeadTracking: 1 - hololens: - depthFormat: 1 - depthBufferSharingEnabled: 1 - oculus: - sharedDepthBuffer: 1 - dashSupport: 1 - lowOverheadMode: 0 - protectedContext: 0 - v2Signing: 0 enable360StereoCapture: 0 - protectGraphicsMemory: 0 + isWsaHolographicRemotingEnabled: 0 enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 useHDRDisplay: 0 + D3DHDRBitDepth: 0 m_ColorGamuts: 00000000 targetPixelDensity: 30 resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 androidSupportedAspectRatio: 1 androidMaxAspectRatio: 2.1 applicationIdentifier: {} - buildNumber: {} + buildNumber: + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 16 + AndroidMinSdkVersion: 22 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 aotOptions: @@ -173,28 +176,16 @@ PlayerSettings: StripUnusedMeshComponents: 1 VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 - iOSTargetOSVersionString: 9.0 + iOSTargetOSVersionString: 11.0 tvOSSdkVersion: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 9.0 + tvOSTargetOSVersionString: 11.0 uIPrerenderedIcon: 0 uIRequiresPersistentWiFi: 0 uIRequiresFullScreen: 1 uIStatusBarHidden: 1 uIExitOnSuspend: 0 uIStatusBarStyle: 0 - iPhoneSplashScreen: {fileID: 0} - iPhoneHighResSplashScreen: {fileID: 0} - iPhoneTallHighResSplashScreen: {fileID: 0} - iPhone47inSplashScreen: {fileID: 0} - iPhone55inPortraitSplashScreen: {fileID: 0} - iPhone55inLandscapeSplashScreen: {fileID: 0} - iPhone58inPortraitSplashScreen: {fileID: 0} - iPhone58inLandscapeSplashScreen: {fileID: 0} - iPadPortraitSplashScreen: {fileID: 0} - iPadHighResPortraitSplashScreen: {fileID: 0} - iPadLandscapeSplashScreen: {fileID: 0} - iPadHighResLandscapeSplashScreen: {fileID: 0} appleTVSplashScreen: {fileID: 0} appleTVSplashScreen2x: {fileID: 0} tvOSSmallIconLayers: [] @@ -222,15 +213,17 @@ PlayerSettings: iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 iOSLaunchScreeniPadCustomXibPath: - iOSUseLaunchScreenStoryboard: 0 iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] + macOSURLSchemes: [] iOSBackgroundModes: 0 iOSMetalForceHardShadows: 0 metalEditorSupport: 1 metalAPIValidation: 1 iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 appleDeveloperTeamID: iOSManualSigningProvisioningProfileID: tvOSManualSigningProvisioningProfileID: @@ -240,10 +233,19 @@ PlayerSettings: iOSRequireARKit: 0 iOSAutomaticallyDetectAndAddCapabilities: 1 appleEnableProMotion: 0 + shaderPrecisionModel: 0 clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea templatePackageId: com.unity.template.3d@1.3.0 templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomProguardFile: 0 AndroidTargetArchitectures: 5 + AndroidTargetDevices: 0 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} AndroidKeystoreName: @@ -254,14 +256,112 @@ PlayerSettings: AndroidEnableTango: 0 androidEnableBanner: 1 androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 m_AndroidBanners: - width: 320 height: 180 banner: {fileID: 0} androidGamepadSupportLevel: 0 - resolutionDialogBanner: {fileID: 0} + chromeosInputEmulation: 1 + AndroidMinifyWithR8: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 m_BuildTargetIcons: [] - m_BuildTargetPlatformIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: m_BuildTargetBatching: - m_BuildTarget: Standalone m_StaticBatching: 1 @@ -278,16 +378,58 @@ PlayerSettings: - m_BuildTarget: WebGL m_StaticBatching: 0 m_DynamicBatching: 0 + m_BuildTargetGraphicsJobs: + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 0 + - m_BuildTarget: PS5Player + m_GraphicsJobs: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 0 + - m_BuildTarget: GameCoreXboxOneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: GameCoreScarlettSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: CloudRendering + m_GraphicsJobs: 0 + - m_BuildTarget: EmbeddedLinux + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 m_BuildTargetGraphicsAPIs: - m_BuildTarget: AndroidPlayer m_APIs: 0b00000008000000 - m_Automatic: 1 + m_Automatic: 0 - m_BuildTarget: iOSSupport m_APIs: 10000000 m_Automatic: 1 - m_BuildTarget: AppleTVSupport m_APIs: 10000000 - m_Automatic: 0 + m_Automatic: 1 - m_BuildTarget: WebGLSupport m_APIs: 0b000000 m_Automatic: 1 @@ -297,9 +439,9 @@ PlayerSettings: m_Devices: - Oculus - OpenVR - m_BuildTargetEnableVuforiaSettings: [] openGLRequireES31: 0 openGLRequireES31AEP: 0 + openGLRequireES32: 0 m_TemplateCustomTags: {} mobileMTRendering: Android: 1 @@ -307,6 +449,8 @@ PlayerSettings: tvOS: 1 m_BuildTargetGroupLightmapEncodingQuality: [] m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: [] playModeTestRunnerEnabled: 0 runPlayModeTestAsEditModeTest: 0 actionOnDotNetUnhandledException: 1 @@ -316,12 +460,16 @@ PlayerSettings: cameraUsageDescription: locationUsageDescription: microphoneUsageDescription: + bluetoothUsageDescription: + switchNMETAOverride: switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 switchScreenResolutionBehavior: 2 switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 switchNSODependencies: switchTitleNames_0: @@ -339,6 +487,7 @@ PlayerSettings: switchTitleNames_12: switchTitleNames_13: switchTitleNames_14: + switchTitleNames_15: switchPublisherNames_0: switchPublisherNames_1: switchPublisherNames_2: @@ -354,6 +503,7 @@ PlayerSettings: switchPublisherNames_12: switchPublisherNames_13: switchPublisherNames_14: + switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} @@ -369,6 +519,7 @@ PlayerSettings: switchIcons_12: {fileID: 0} switchIcons_13: {fileID: 0} switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} switchSmallIcons_0: {fileID: 0} switchSmallIcons_1: {fileID: 0} switchSmallIcons_2: {fileID: 0} @@ -384,6 +535,7 @@ PlayerSettings: switchSmallIcons_12: {fileID: 0} switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} switchManualHTML: switchAccessibleURLs: switchLegalInformation: @@ -446,6 +598,11 @@ PlayerSettings: switchSocketInitializeEnabled: 1 switchNetworkInterfaceManagerInitializeEnabled: 1 switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 ps4NPAgeRating: 12 ps4NPTitleSecret: ps4NPTrophyPackPath: @@ -472,6 +629,7 @@ PlayerSettings: ps4ShareFilePath: ps4ShareOverlayImagePath: ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: ps4NPtitleDatPath: ps4RemotePlayKeyAssignment: -1 ps4RemotePlayKeyMappingDir: @@ -484,6 +642,7 @@ PlayerSettings: ps4DownloadDataSize: 0 ps4GarlicHeapSize: 2048 ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ ps4pnSessions: 1 ps4pnPresence: 1 @@ -496,6 +655,7 @@ PlayerSettings: ps4UseResolutionFallback: 0 ps4ReprojectionSupport: 0 ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 ps4SocialScreenEnabled: 0 ps4ScriptOptimizationLevel: 0 ps4Audio3dVirtualSpeakerCount: 14 @@ -512,11 +672,16 @@ PlayerSettings: ps4disableAutoHideSplash: 0 ps4videoRecordingFeaturesUsed: 0 ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 spritePackerPolicy: webGLMemorySize: 256 webGLExceptionSupport: 1 @@ -529,17 +694,26 @@ PlayerSettings: webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 webGLLinkerTarget: 1 webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 scriptingDefineSymbols: {} + additionalCompilerArguments: {} platformArchitecture: {} scriptingBackend: {} il2cppCompilerConfiguration: {} managedStrippingLevel: {} incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 allowUnsafeCode: 0 + useDeterministicCompilation: 1 + enableRoslynAnalyzers: 1 additionalIl2CppArgs: scriptingRuntimeVersion: 1 + gcIncremental: 1 + assemblyVersionValidation: 1 + gcWBarrierValidation: 0 apiCompatibilityLevelPerPlatform: {} m_RenderingPath: 1 m_MobileRenderingPath: 1 @@ -570,7 +744,7 @@ PlayerSettings: metroFTAName: metroFTAFileTypes: [] metroProtocolName: - metroCompilationOverrides: 1 + vcxProjDefaultLanguage: XboxOneProductId: XboxOneUpdateKey: XboxOneSandboxId: @@ -589,18 +763,16 @@ PlayerSettings: XboxOneCapability: [] XboxOneGameRating: {} XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 XboxOneEnableGPUVariability: 1 XboxOneSockets: {} XboxOneSplashScreen: {fileID: 0} XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 - xboxOneScriptCompiler: 1 XboxOneOverrideIdentityName: - vrEditorSettings: - daydream: - daydreamIconForeground: {fileID: 0} - daydreamIconBackground: {fileID: 0} + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} cloudServicesEnabled: UNet: 1 luminIcon: @@ -609,24 +781,20 @@ PlayerSettings: m_PortalFolderPath: luminCert: m_CertPath: - m_PrivateKeyPath: + m_SignPackage: 1 luminIsChannelApp: 0 luminVersion: m_VersionCode: 1 m_VersionName: - facebookSdkVersion: 7.9.4 - facebookAppId: - facebookCookies: 1 - facebookLogging: 1 - facebookStatus: 1 - facebookXfbml: 0 - facebookFrictionlessRequests: 1 apiCompatibilityLevel: 6 + activeInputHandler: 0 cloudProjectId: framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] projectName: organizationId: cloudEnabled: 0 - enableNativePlatformBackendsForNewInputSystem: 0 - disableOldInputManagerSupport: 0 legacyClampBlendShapeWeights: 0 + playerDataPath: + forceSRGBBlit: 1 + virtualTexturingSupportEnabled: 0 diff --git a/ProjectSettings/ProjectVersion.txt b/ProjectSettings/ProjectVersion.txt index 88062e3..e08682f 100644 --- a/ProjectSettings/ProjectVersion.txt +++ b/ProjectSettings/ProjectVersion.txt @@ -1,2 +1,2 @@ -m_EditorVersion: 2019.4.17f1 -m_EditorVersionWithRevision: 2019.4.17f1 (667c8606c536) +m_EditorVersion: 2022.3.32f1 +m_EditorVersionWithRevision: 2022.3.32f1 (c8300dc0a3fa) diff --git a/ProjectSettings/SceneTemplateSettings.json b/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..6f3e60f --- /dev/null +++ b/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,167 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "ignore": false, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/ProjectSettings/VersionControlSettings.asset b/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/README.md b/README.md index b074ad0..1ce9be7 100644 --- a/README.md +++ b/README.md @@ -1,562 +1,60 @@ # Game programming patterns in Unity -A collection of programming patterns in Unity, mainly from the book [Game Programming Patterns](http://gameprogrammingpatterns.com). These are very useful to better organize your Unity project as the game grows. You don't have to use them - you should see them as tools in your toolbox. Some patterns, such as Update, Game Loop, Component, are already been built-in into Unity so you are already using them! +Here you can find a collection of programming (design) patterns in Unity, mainly from the book [Game Programming Patterns](http://gameprogrammingpatterns.com). These are very useful to better organize your Unity project as it grows because they capture best practices and solutions to commonly occuring problems. You don't have to use them - you should see them as tools in your toolbox. You can also experiment with how they are implemented to fit your specific needs. Some patterns, such as Update, Game Loop, Component, are already built-in into Unity so you are already using them! Programming patterns can be divided into the following groups: 1. **Architectural patterns.** One example is the MVC (Model-View-Controller). 2. **Design patterns.** Are more specific than architectural patterns, such as the Singleton. -3. **Anti-patterns.** Are a collection of patterns that many programmers are using to solve problems even though they shouldn't use them because they are ineffective solutions to a problem. One example is a "God object," most likely called GameController where you collect everything you might need to make the game work. The problem with such as class is that it will grow in size, which will make it more difficult to maintain, and it will also be difficult to debug because the code doesn't belong together. +3. **Anti-patterns.** Are a collection of patterns programmers are using to solve problems even though they shouldn't use them because they are ineffective solutions. One example is a "God object," most likely called GameController where you collect everything you might need to make the game work. The problem with such as class is that it will grow in size, which will make it more difficult to maintain, and it will also be difficult to debug because the code doesn't belong together. Patterns from the book Game Programming Patterns: -1. [Command](#1-command) -2. [Flyweight](#2-flyweight) -3. [Observer](#3-observer) -4. [Prototype](#4-prototype) -5. [Singleton](#5-singleton) -6. [State](#6-state) -7. [Double Buffer](#7-double-buffer) -8. [Game Loop](#8-game-loop) -9. [Update Method](#9-update-method) -10. [Bytecode](#10-bytecode) -11. [Subclass Sandbox](#11-subclass-sandbox) -12. [Type Object](#12-type-object) -13. [Component](#13-component) -14. [Event Queue](#14-event-queue) -15. [Service Locator](#15-service-locator) -16. [Data Locality](#16-data-locality) -17. [Dirty Flag](#17-dirty-flag) -18. [Object Pool](#18-object-pool) -19. [Spatial Partition](#19-spatial-partition) +1. [Command](_text/1-command.md) +2. [Flyweight](_text/2-flyweight.md) +3. [Observer](_text/3-observer.md) +4. [Prototype](_text/4-prototype.md) +5. [Singleton](_text/5-singleton.md) +6. [State](_text/6-state.md) +7. [Double Buffer](_text/7-double-buffer.md) +8. [Game Loop](_text/8-game-loop.md) +9. [Update Method](_text/9-update-method.md) +10. [Bytecode](_text/10-bytecode.md) +11. [Subclass Sandbox](_text/11-subclass-sandbox.md) +12. [Type Object](_text/12-type-object.md) +13. [Component](_text/13-component.md) +14. [Event Queue](_text/14-event-queue.md) +15. [Service Locator](_text/15-service-locator.md) +16. [Data Locality](_text/16-data-locality.md) +17. [Dirty Flag](_text/17-dirty-flag.md) +18. [Object Pool](_text/18-object-pool.md) +19. [Spatial Partition](_text/19-spatial-partition.md) Other patterns: -20. [Decorator](#20-decorator) -21. [Factory](#21-factory) -22. [Facade](#22-facade) -23. [Template](#23-template) +20. [Decorator](_text/20-decorator.md) +21. [Factory](_text/21-factory.md) +22. [Facade](_text/22-facade.md) +23. [Template](_text/23-template.md) +Note that these are not all patterns out there. I recently read a book called "Machine Learning Design Patterns" which includes even more design patterns with a focus on machine learning problems. But I will continue adding patterns as I find them and if they are related to game development. -# Patterns from the book Game Programming Patterns -## 1. Command -In you game you have many commands, such as play sound, throw cake, etc. It can be useful to wrap them in a Command object. Now the Command object doesn't have to care about how the command is executed. +# Sources and Read More -**How to implement?** +- [Game Programming Patterns](http://gameprogrammingpatterns.com) +- [Game Development Patterns with Unity 2021](https://www.amazon.com/Game-Development-Patterns-Unity-2021/dp/1800200811) +- [Head First Design Patterns](https://www.amazon.com/Head-First-Design-Patterns-Brain-Friendly/dp/0596007124) +- [Game Programming Gems](https://www.amazon.com/Game-Programming-Gems-CD/dp/1584500492) +- [Game Programming Gems 2](https://www.amazon.com/Game-Programming-Gems-GAME-PROGRAMMING/dp/1584500549) +- [Refactoring Guru](https://refactoring.guru/design-patterns) +- [Design Patterns in C# With Real-Time Examples](https://dotnettutorials.net/course/dot-net-design-patterns/) +- [Level up your code with game programming patterns](https://resources.unity.com/games/level-up-your-code-with-game-programming-patterns) -* You have a base class called Command which has a method that a child can implement called Execute. In each child class, you put in the Execute method what will actually happen when you run (execute) that command. -**When is it useful?** -* To make it easier to rebind keys. Example of this is available in the code section. +# Special Thanks -* To make it easier to make a replay system. When you play the game, you store in some data structure which button you pressed each update. When you want to replay what has happened, you just iterate through each command while running the game. Example of this is available in the code section. - -* To make it easier to make an undo and redo system. Is similar to the replay system, but in each command you also have a method called Undo() where you do the opposite of what the command is doing. Example of this is available in the code section. - -**Related patterns** - -* [Subclass Sandbox](#11-subclass-sandbox). You may end up with many child-command-classes. To easier handle the code, you can define high-level methods in the parent like in the Subclass Sandbox pattern. - - - -## 2. Flyweight - -This pattern is useful if you have many objects. Even though a single object takes up little memory – instantiating many of them can cause trouble. - -**How to implement?** - -* Separate the data that’s not specific to a single instance of that object and can be shared across all of them. You can do that by creating a new class and put the shared data in it. Then each object that should share data gets a reference to a single instance of that "storage" class. - -**When is it useful?** - -* If you make Minecraft and have a million cubes in the scene. All cubes can share the same texture if you put all textures that belongs to each cube type (grass, stone, sand, etc) into a [texture atlas](https://en.wikipedia.org/wiki/Texture_atlas). - -**Related patterns** - -* [Type object](#12-type-object). The main difference is that in Type object you don't need to have the exact same data and you can also have behavior. - - - -## 3. Observer - -Many things are constantly happening in your game. These things are called events (and sometimes messages). The difference between event and message is that an event has happened while a message is something that will happen. So this pattern is all about what will happen after an event has happened. Which methods should be called after you killed an enemy to update score, show death animation, etc? These methods should subscribe to the event. - -**How to implement?** - -This pattern is so popular that C# has implemented it for you. Unity also has its own implementation. So your alternatives are: - -* EventHandler -* Action -* UnityEvent -* Your own implementation by using a delegate - -I've implemented all these in the code, so if you don't understand the difference take a look there. - -**When is it useful?** - -* This pattern is really useful if you want to avoid spaghetti code by making classes independent of each other, also known as decoupling. The best part of events is that the part that's triggering the event doesn't care which methods are attached to the event. There might be zero methods. So if an event is triggered but nothing is happening we can easier find where the bug might be. - -* If you really want to decouple your code, then you still have a problem. To subscribe to the event you need a reference to the script where the event is defined. Another way is to create an Event Manager, which is a global class that takes care of all events. Unity has its own tutorial on how to implement that: [Creating a Simple Messaging System](https://www.youtube.com/watch?v=0AqG1fDhPT8). - -* Another way to decouple the code is to make the event static. An example of a static event is available in the code. - -**Related patterns** - -* [Event queue](#14-event-queue). The biggest problem with Observer is that it will trigger all methods that subscribe to the event. So if five methods subscribe, then five methods will be triggered. But what if 10 enemies are killed at the same time, then 50 methods will be triggered at the same time, which may freeze your game. This is when you should use the Event queue, which is basically the same as the Observer, but you put the events in a queue and you trigger as many as you can without freezing the game. - -* Model-View-Controller (MVC). The MVC is an architectural pattern, and to implement it you can use the Observer. - - - -## 4. Prototype - -In your game you have a game object. Now you want to duplicate that object to create another object. This pattern allows you to create as many duplicates of an object as you want. - -**How to implement?** - -* This is a pattern that already exists in Unity in the form of the [Instantiate-method](https://docs.unity3d.com/ScriptReference/Object.Instantiate.html). But it assumes that the object you want to duplicate inherits from Object, which is a class in UnityEngine. - -* You could also make you own implementation. But then you have to ask yourself: do you do a deep clone (a copy of the structure and the elements in the structure) or a shallow clone (a copy of the structure not the elements in the structure)? Maybe the Flyweight pattern can give you the answer? - -**When is it useful?** - -* If you have a gun that fires bullets. You add one bullet prefab to the script. Each time you fire the gun you need a new bullet because you don't want to use the original bullet, so you call Unity's Instantiate-method and you get a duplicate of the original bullet. - -**Related patterns** - -* [Factory](#21-factory). In the Factory you are generally generating new objects - not copies of already existing objects (which may include position and other states). You can put the Prototype inside of the Factory so you have one class where you create all objects instead of having the creation in multiple classes which might be troublesome if you want to change something. - -* [Object pool](#18-object-pool). If you Instantiate and destroy many game objects, it will affect the performance of the game. To solve that problem you can use the Object pool pattern. - - - -## 5. Singleton - -In your game you might have a class that saves the game for you. It's really important that you have just one instance of this class, or you might save different versions of the game if each instance includes different data. It should also be easy to access this save game class from where you need it. You can use the Singleton pattern to accomplish this. - -**How to implement?** - -* In C#. Make the instance static and provide a public static means of getting the reference to the single created instance. If the instance hasn't been created yet, create it. The constructor should be private and have no parameters. You can find this implemented in the code section. - -* If your Singleton has to be thread safe, things will get more complicated. This is a good tutorial on the topic of more advanced Singleton patterns: [Implementing the Singleton Pattern in C#](https://csharpindepth.com/articles/singleton). - -* In C# but the class also inherits from MonoBehaviour. If you want the Singleton to also inherit from MonoBehaviour (because you need some of that functionality) things will get slightly more complicated. The problem now is that you can accidentally add several Singletons to the project. So you have to make sure you destroy all except one of the objects. Neither can you use a constructor, because MonoBehaviour doesn't allow it, so you have to implement your own constructor. You can find this implemented in the code section. - -**When is it not useful?** - -* According to the book, you should avoid this pattern because global objects may cause trouble. If you need to use this pattern, then it should be for manager classes, such as GameController, SaveGame, etc. - -* A problem if you use the MonoBehaviour version is that if you call the Singleton object from another object's OnDestroy method when you quit the game, the Singleton might have already been destroyed. - -**What are some alternatives?** - -You tend to use the Singleton pattern because you want an easy access to that script. But if Singletons are so bad, what are some alternatives? - -* **No class at all.** Most Singeltons are helpers, and in many cases you can remove the manager and put the help-code in the class the manager manages. - -* **Static class.** This is basically the [Service Locator pattern](#15-service-locator). - -* **Unity's built-in Find() and SendMessage().** But these are so slow they should be avoided. If you have to use them, use them only once to get a reference to the script in the Start method. - -* **Assign references to pre-existing objects.** This means dragging the object (on which the script that used to be a singleton is attached) to public variables exposed in the Editor. The problem now is that this may become very complicated, and if you change a reference you often have to again drag them to wherever it's needed, which may be many locations if you have many objects. - -* **A global event system.** This is basically the [Observer pattern](#3-observer). You still need a Singleton for this global system, but you can remove all other Singletons. - -* **Dependency Injection.** This means that you inject the reference to the object (that used to be a singleton) in for example the constructor belonging to the class that need a reference to that object. There are also [Dependency Injection frameworks](https://www.youtube.com/watch?v=6tn8pMQuxEk) to make this process easier. - -* **One Singleton.** Have just one Singleton class and all managers that used to be Singletons are collected in this class. If you need the SaveGame object, you type GameController.Instance.getSaveGameManager(). - - - -## 6. State - -Your game can be in a number of states. For example, the main character can have the following states: jump, walk, run, etc. Now you want an easy way to switch between the states. This pattern is also known as a **state machine**, and if you have a finite amount of states you get a **finite state machine (FSM)**. - -**How to implement?** - -* You could use an enum that keeps track of each state and then a switch statement. - -* The problem with the switch statement is that it tends to become complicated the more states you add. A better way is to define an object for each state and then you switch between the objects as you switch states. - -**When is it useful?** - -* When you have too many nested if-statements, such as in a menu system. In the code, you can see an example of a menu system that uses this pattern. - -* Unity is using this pattern in the animation engine. - -* When you make a turn-based combat system: [How to Code a Simple State Machine](https://www.youtube.com/watch?v=G1bd75R10m4). - -* If you are making a GTA-style game. You have one state for driving, one for when the character is not in a vehicle, another state for flying, etc. Then you can also add state-of-states. For example, in the state class where the character is not in a vehicle, you can have several sub-states, such as holding nothing, holding grenade, holding pistol, etc. - -**Related patterns** - -* [Type Object](#12-type-object). In both cases you have a main object and then you add another object to define something. The difference is that in State you switch the other object, while in Type Object that object remains the same. So if the object in Type Object can be switched you get the State pattern. - - - -## 7. Double Buffer - -You have two buffers: you update #1 with new data while you are not allowed to modify #2 because #2 is holding old data from previous update, which you might want to display on the screen or use when updating #1. When you have finished updating #1, you swap them, so #2 is now including fresh data and you can start updating #1 which is now including old data. - -**How to implement?** - -* You can have two arrays. You write to one of them, and when the calculations are finished you swap the pointer to the arrays. - -**When is it useful?** - -* To display stuff on the screen. This is already built-in into you computer which uses two buffers to display stuff on the screen. It reads from #2 while #1 is being updated with new data. When #1 is finished updating, the buffers are switched, so now you will see the newly updated data on the screen. It would look strange if you used just one buffer because then one part of the screen would display old data and one new data in some kind of horrible mix. - -* To generate motion blur. The current buffer is blended with a bit of the previous buffer. - -* Cellular Automation. In games it's common that you store data in a grid (which is a 2d array). To calculate new data you combine data from the cells, such as the maximum value of the current cell and surrounding cells. But where are you storing the data for the cell you just calculated? You can't store it in the cell because that will screw up the calculations for neighboring cells because you always want to use old data when doing the calculations. So you use two grids: #2 holds the old data and #1 is using #2 to update itself. When the calculations are finished, you swap them. - - * Cave-generation. This is the example I've included in the code. - - * [Water](http://www.jgallant.com/2d-liquid-simulator-with-cellular-automaton-in-unity/). You simulate movement of water on a grid. - - * [Forest fire](https://www.habrador.com/p/forest-fire/). You store in each cell the amount of burning material in that cell, then you simulate heat to ignite the material. When there's no more material to burn, the heat disappears. - - - -## 8. Game Loop - -The game loop is the core of all games. It's basically an infinite while loop that keeps updating until you stop it. But the problem with such a while loop is that it updates faster on faster computers than it is on slower computers. This will be very problematic if you have some object that travels with some speed, then it will travel faster on the faster computer and the player will maybe not even understand what's going on. To solve this problem you need to take time into account by using the following: - -* Fixed time step. You determine you want the game to run at 30 frames-per-second (FPS). Now you know how long one while loop should take (1/30 = 0.03333 seconds). If the while loop is faster than that, you simply pause it at the end until 0.03333 seconds has passed. If it's slower, you should optimize your game. - -* Variable (fluid) time step. You measure how many seconds has passed since the last frame. You then pass this time to the update method, so the game world can take bigger steps if the computer is slow and smaller steps if the computer is fast. - -**How to implement?** - -* This pattern has already been implemented in Unity, which is actually using both versions of the while loop: - - * Fixed time step: Time.fixedDeltaTime. This version is used for physics calculations where you should use a constant step to make more accurate calculations. - - * Variable time step: [Time.deltaTime](https://docs.unity3d.com/ScriptReference/Time-deltaTime.html), which Unity defines as "The completion time in seconds since the last frame." - -* The game loop is also checking for input before anything else. This is why in Unity you can type "if (Input.GetKey(KeyCode.A))" because the game loop has already checked (before the update method) if the A key has been pressed and stored that information in some data structure. - -**When is it useful?** - -* When you have a bullet that should move with a constant speed. So you determine a bulletSpeed and in the update method you multiply the speed with Time.deltaTime so the bullet travels with the same speed no matter how fast the computer is. - - - -## 9. Update Method - -The update method will process one frame of behavior. Each object that needs it should have its own update method because it would be difficult to combine everything in the game loop's update method. So each object that has a update method should be stored in some data structure, such as a list, and then you iterate over each one in the main update method. - -**How to implement?** - -* This pattern has already been implemented in Unity, in the form of the Update() method, which you can use if your script inherits from MonoBehaviour. Then Unity processes each Update one-by-one in the main Update method. - -* You could instead of using Unity's update method, implement your custom update method. You store all the scripts that uses this custom update method in a list. Then in some script, like a GameController, you iterate through this list in Unity's update method while calling each custom update method one-by-one. This may make it easier to for example pause your game by simply not iterating through that list when the game is paused. I've given an example of this in the code section. - - - -## 10. Bytecode - -What if other people want to help you with your game, but these people have no coding skillz. A solution is to invent a simpler programming language everyone can learn, and then you integrate it with your game. - -**How to implement?** - -* The programmers with no skillz write their code in a .txt-file. You read that file, loop through each row, and then use a switch statement to translate the code from your programming language to C#. - -**When is it useful?** - -* If you want to add modding support. - -* If you don't want to hard-code behaviour. - - - -## 11. Subclass Sandbox - -You have similar objects but they have different behavior. Create those behaviors in the child class by combining methods defined in the parent class. - -**How to implement?** - -* Define several protected methods in the parent class and how they are implemented. In the child class, you call the methods you need to get the behavior you want. - -**When is it useful?** - -* When your child classes share behavior and the parent class can provide these behaviors. For example if you are using superpowers and the child class can combine these superpowers. This is an example from the book so you can find the code in the code section. - -**Related patterns** - -* [Update Method](#9-update-method). The Update Method is often implemented as a Sandbox method. - -* [Type Object](#12-type-object). Instead of defining all methods in the parent you could give the child a reference to an object that defines these methods. - -* [Template](#23-template). Is the opposite of the Subclass sandbox pattern. In the Subclass Sandbox you implement the methods in the parent class, while in Template you implement the methods in the child class. - - - -## 12. Type Object - -You have an object and now you want to change its type (such as behavior or some data) by giving it a reference to an object that defines the type, thus the name Type Object. Another way could be to use class inheritance to define a child class which includes to code for the type, but that's not always possible because different children may be of the same type. - -**How to implement?** - -* The Type Objects should share the same interface (or parent) to make it easier for the main class to reference the object. - -**When is it useful?** - -* When you can't (or don't want to) use class inehritance. Let's say you make a game with animals. You have a base class which is parent to all animals, and then as children to that class you add birds, fish, and mammals. In the bird class you define a flying behavior, which is all fine until you add an ostrich, which can't fly. In that case you have to inherit from the bird class and create new children that can fly and can't fly. But what about bats, which is a mammal that can fly? You don't want to add flying behavior in two separate classes! A better way is to define a flying and a non-flying type in a separate class, so both ostriches remain on the ground and bats can fly. - -**Related patterns** - -* [State](#6-state). In both cases you have a main object and then you add another object to define something. The difference is that in State you switch the other object, while in Type Object that object remains the same. So if the type can be switched you get the State pattern. - -* [Subclass Sandbox](#11-subclass-sandbox). You could define all types in the parent class and then combine them in the child class. - -* [Component](#13-component). The difference is that the Component is not always coupled with something else on the game object – it’s living its own life. In Unity you can add colliders, scripts, mesh renderers and they don’t need to know about each other to function. Type Object, however, is about adding a behavior to an existing class, so the type can't live on its own. - - - -## 13. Component - -When making a big game you should start thinking in components. A component is similar to your computer mouse, which you can attach to whatever computer you want through a USB port and it works fine. So a component is an object that's independent of other objects, making it reusable, and you can attach the component to several other objects if you want those objects to get the behavior described by the component. But in reality, some components have to communicate with each other, so they can't be entirely independent of each other: The mouse is communicating with the computer, but it's not communicating with the printer. - -**How to implement?** - -* In Unity you can attach components to GameObjects, such as colliders, mesh renderers, your own scripts, so it's already built-in. It's up to you to make the custom scripts you attach as reusable as possible. - -**When is it useful?** - -* Because Unity's FPS counter is not to be trusted, you can have a custom FPS counter that you re-use throughout all projects. Just add the script to the project and attach it to some GameObject and it works fine independently of everything else going on in the game. - -* When making a car game you can put physics in one script, such as drag and rolling resistance, becuse physics will always affect the car and the physics calculations are the same for all cars. This component will not be completely independent because it will need some data from the car, such as current speed, but as said before that's fine. - -**Related patterns** - -* [Type Object](#12-type-object). The difference is that the Component is not always coupled with something else on the game object – it’s living its own life. In Unity you can add colliders, scripts, mesh renderers and they don’t need to know about each other to function. Type Object, however, is about adding a behavior to an existing class, so the type can't live on its own. - - - -## 14. Event Queue - -This pattern is almost the same as the [Observer](#3-observer) pattern. The only difference is that you wait until a later time to process each event. This may be useful if you have many events that may be activated at the same time which will freeze the game - this pattern will spread them out. - -**How to implement?** - -Combine the [Command](#1-command) pattern with a C#'s built-in queue, which is why this pattern is sometimes known as a **Command Queue**. In the Update method you pick the first Command in the queue and run it while measuring time. To measure time you can use System.Diagnostics.Stopwatch. If you have time to spare, you run the next Command, and so on until you are out of time. How much time you can spend on the Event Queue each update depends on the game, so you have to experiment. - -**When is it useful?** - -* When you after an event will load an asset. This may take time, so if you want to play a sound when clicking a button, the game may freeze because it has to load the sound. A better way is to play the sound some frames after the click. - -* When you after an event will play a sound effect. What if 100 enemies die at the same time and each time an enemy dies you play a death-sound. Now 100 sounds will play at the same time. If you put the events in a queue, you can check if a sound is already playing and then ignore the event. You can also merge the events that are the same, so you have only one of each event type in the queue. - -* If you are making a strategy game, you can put orders in the queue that the player wants a certain unit to do: 1. build wall, 2. collect food, 3. attack creature. Now the player doesn't have to wait for a unit to finish one task. You can also put waypoints in the queue to make a unit patrol between waypoints. The AI can also put commands in a queue to for example determine which units should attack. - -* When making a speech system. Each character has its own queue with audio it wants to say. To know which character should speak, you can go through all queues. If the player presses Escape because the player doesn't want to listen to the talk, you simply clear all queues. - - - -## 15. Service Locator - -When making your game you use many standardized methods to for example generate random numbers. These are called services and should be accessible from everywhere (globally) but still be independet from your game's main code. - -**How to implement?** - -* Put each service in a static class. The static class should be in its own folder and have its own namespace to make sure you are not mixing the services with your main code. - -* A slightly more complicated way is to use a service locator that provides access to a service provider. To make sure no other methods than the ones you need are exposed to the outside world, the service provider should limit which methods it can provide access to. - -* Unity has implemented this pattern in the form of the GetComponent() method. - -**When is it useful?** - -* Several services are already built-in into Unity, such as Random.Range() to get a random number, Mathf.PI to get pi, and Debug.Log() to display something in the console. - -* In the game you may have different audio objects depending on if the game is running on a console or on a PC. This is the same example as in the book so you can find the code for it in the code section. - -**Related patterns** - -* [Singleton](#5-singleton). Both provide a global access to an object. So the problems with the Singleton also applies to this pattern. - -* [Facade](#22-facade). Is very similar, and you can use Facade in combination with Service Locator. - - - -## 16. Data Locality - -Have you done all otpimizations you can possible do? Is the game still too slow? Then this pattern may help you. It can make your game faster by accelerating memory access. - -**How to implement?** - -* You have to arrange data to take advantage of CPU caching. The basic idea is that you should organize your data structures so that the things you're processing are next to each other in memory. This is a big topic and can't be summarized here, so you should read about it in the book. - -* This Unity article suggest that you should use struct instead of class because they are more cache friendly [How to Write Faster Code Than 90% of Programmers](https://jacksondunstan.com/articles/3860). - -* Unity has implemented this pattern in their [Data-Oriented Technology Stack (DOTS)](https://unity.com/dots). - -* A good Unity tutorial on the topic is: [Unity Memory Profiler: Where Are You Wasting Your Game's Memory?](https://thegamedev.guru/unity-memory/profiler-part-1/) and [Part 2](https://thegamedev.guru/unity-memory/profiler-part-2/). - -**When is it useful?** - -* According to the book, this pattern should be used when everything else has failed. It's a waste of time to optimize code that doesn't need to be optimized - and it may also make the code more complicated to understand. You also have to make sure that cache misses is the reason your code is slow, so you have to first measure it. - - - -## 17. Dirty Flag - -This pattern is useful if something has changed in your game, and if so you have to run a costly operation. A Dirty Flag is used to tell that something has changed but the costly operation hasn't been activated. - -**How to implement?** - -* The dirty flag is just a simple boolean, which is set to true if something has changed. - -**When is it useful?** - -* Saving your game can be a costly operation. If something in your game has changed that also needs to be saved, you set a Dirty Flag in the save game object to true. Now if the player wants to quit the game, you can easily tell the player that there are unsaved changes. - -* If you ever done some editor scripting in Unity, you know that you can use SetDirty() to mark an object as dirty or you can even mark the entire scene as dirty. Now Unity will understand that you have changed something and those changes should be saved when you save your scene. - -* Unity is using it in the physics system. A RigidBody doesn't have to be updated unless a force is applied to it. If the RigidBody is sleeping (not moving), a Dirty Flag is used so the physics system can ignore it. - - - -## 18. Object Pool - -If you constantly create and destroy objects, the performance of your game will suffer. A better way is to create the objects once in the beginning and deactivate them. When you need an object, you pick one of the deactivate objects and activate it. When you don't need the object anymore, you deactivate it instead of destroying it. - -**How to implement?** - -* Create a class called object pool. Give it an object prefab and instantiate the number of objects you think you will need. Store them in a list. When you need an object you search through the list for a deactivated object and returns the first you find. If you realize you need more objects than the objects you started with, you have a few choises: - - * You can instantiate more objects during gameplay. But make sure you don't instantiate too many objects because it will be a waste of memory. You could later remove the "extra" objects you added. - - * Find one of the objects that's active but the player will not notice if it suddeny disappears so you can use it. - - * Ignore that you have no more objects, which may be fine. If the screen is filled with explosions, the player will not notice a new explosion is missing. - -* If the objects you pool reference another object which is destroyed, then it's important to clear this reference when the object in the pool is deactivated. Otherwise the garbage collector will not be able to do its work on the destroyed object because it's still referenced by a living object. - -* One problem with storing objects in a list and search the list to find an avilable object is that the list may be very long, so it's a waste of time. Another way is to store the objects in the pool in a linked-list. - -**When is it useful?** - -* The most common example is when you fire bullets from a gun, then you will need many bullets. I've given an example of this in the code section. You can find two versions: the optimized version which uses a linked-list, and the slow version which has to search a list to find an available bullet. - -* Unity is using this pattern in their particle system. In the particle settings you can set max number of particles, which can be useful so you don't accidentally instantiate millions of particles. - -**Related patterns** - -* [Data Locality](#16-data-locality). In this pattern we pack objects of the same type together in memory. It will help the CPU cache to be full as the game iterates over those objects, which is what the Data Locality patterns is about. - - - -## 19. Spatial Partition - -If you have many objects in your game, store the objects in a data structure that organizes the objects by their positions. This should make it faster to for example find the closest object to some other object. - -**How to implement?** - -This is a common pattern, so you have several choices: - -* **Grid.** Divide the area into a grid and store in the data structure in which cell each object is located. This is the example from the book, so you can find the code for it in the code section. - -* **Trie.** Is actually called [Trie](https://en.wikipedia.org/wiki/Trie) and not Tree! - * [Quadtree (2d space)](https://en.wikipedia.org/wiki/Quadtree). Divide the square area into 4 cells. But if too many objects are in the same cell, divide that cell into 4 new cells. Continue until there are not "too many objects in the same cell." A good tutorial can be found here: [Coding Challenge #98.1: Quadtree - Part 1](https://www.youtube.com/watch?v=OJxEcs0w_kE). - * [Octree (3d space)](https://en.wikipedia.org/wiki/Octree). Is similar to Quadtree, but instead of cells you use cubes, so divide a cube volume into 8 cubes, and then split each cube into 8 new cubes until not "too many objects are in the same cube." - -* **Binary search trees.** The name is binary, so the difference between Tree is that you split the groups into 2 smaller groups, and then you split one of the smaller groups into 2 smaller groups, and so on. - * [Binary space partition (BSP)](https://en.wikipedia.org/wiki/Binary_space_partitioning). You use a plane to split a group into 2 new groups. And then you use another plane to split the new group into 2 new groups, and so on until you are finished. - * [k-d trees](https://en.wikipedia.org/wiki/K-d_tree). In this case it has to be points that you split into smaller, and smaller groups. - * [Bounding volume hierarchy](https://en.wikipedia.org/wiki/Bounding_volume_hierarchy). You pick a bounding volume (or area in 2d space), such as a rectangle. The size of the first rectangle is determined so all objects fit within it. Then you split the rectangle into two new rectangles, and so on. - -A problem is if the objects move. If so you have to update the data structure or it will not be valid anymore. These data stuctures are also using more memory. So you have to measure that putting the objects in a data strcuture is faster than just searching for the closest object. - -**When is it useful?** - -* Find the closest object to a character. This can be a really slow process if you have hundreds of objects around the character. And if you have soldiers fighting soldiers, you have to make that seach for each soldier. A better way is to divide the search-area so you don't have to search thorough all objects - just the ones closest to you. - -* To increase the performance of collision detection and raytracing. - - - -# Other patterns - - - -## 20. Decorator - -You have some class you want to add some behaviors to in a flexible way without modifying the original class. - -**How to implement?** - -* You have a class and now you create several "decorator" classes that modifies some of the behaviors in the class you want to modify. The decorator class should wrap he class it wants to modify. The decorator class can in turn wrap itself to add other behaviors. This might be easier than the alternative to create child classes. - -**When is it useful?** - -* If you have an order system where people order several products at the same time but pay at a later time. An example of this can be found in the code section where you order Tesla cars with modifications. Yes you could store each order in a list, but a better way is to store them in objects linked to each other. Instead of iterating through each object to find the price, you can just ask the "last" object to get the price of the entire chain. - -**Related patterns** - -* [Subclass Sandbox](#11-subclass-sandbox). You may end up with many child-classes. To easier handle the code, you can define high-level methods in the parent like in the Subclass Sandbox pattern. - - - -## 21. Factory - -Sometimes it's useful to collect all methods on how to create new objects in their own class. - -**How to implement?** - -If you are creating several different factories, then they should inherit from some parent abstract class. And the products you create should also inherit from some parent abstract class, so you can handle them as their parent without caring which child product that actually came out from the factory. - -**When is it useful?** - -* If you've implemented the [Decorator](#20-decorator) then you can decorate the objects in a procedural way by using the Factory pattern. An example of this is in the code where you manufacture the Tesla cars you ordered in the Decorator pattern example. - -**Related patterns** - -* [Prototype](#4-prototype). The Prototype pattern is generally used if you want to make a copy an existing object, while the Factory pattern is generating new objects. But some argue you can put the Prototype pattern inside of the Factory pattern. - - - -## 22. Facade - -When you have several classes and want to make it simpler to access methods in those classes. - -**How to implement?** - -Create a new script that includes methods which accesses the needed methods in the classes you want a simple access to. - -**When is it useful?** - -* In games it's common to write standardized code libraries, such as a library for the AI, which includes pathfinding, etc. These tend to include massive amounts of methods in subfolders. To make it easier for yourself you create a script that includes access to the most important methods you need, such as get a path. An example of this can't be found here but in another open source library I have: [Computational geometry](https://github.com/Habrador/Computational-geometry). For example, there are multiple methods on how to generate a Delaunay triangulation. To simplify the access to those methods I wrote a class called _Delaunay, which accesses each Delaunay method in a simple way. Otherwise you would have to first go into the Delaunay folder and figure out which class is doing what and which method you should use to generate the needed triangulation. - -**Related patterns** - -* [Service Locator](#15-service-locator). Is very similar but the Service Locator is not necessarily consisting of several classes - the service we want to get might consist of a single class. But the Service Locator can use the Facade Pattern if needed. - - - -## 23. Template - -You have objects that uses the same overall algorithm, but the objects implement some steps in the algorithm in a different way. - -**How to implement?** - -Define a template method in the parent class which consists of calling several methods. In the child class, you override the methods that are specific for the child class. - -**When is it useful?** - -* When your child classes share behavior and the parent class can provide these behaviors. The example in the code shows how to assemble Tesla cars. While each car consists of different parts the process of assembling a car is the same. - -**Related patterns** - -* [Subclass Sandbox](#11-subclass-sandbox). Is the opposite of the Template pattern. In the Subclass Sandbox you implement the methods in the parent class, while in Template you implement the methods in the child class. - - - -# Socials - -* Visit my [Portfolio](https://www.habrador.com) - -* Follow me on [Twitter](https://twitter.com/eriknordeus) \ No newline at end of file +- **[masoudarvishian](https://github.com/masoudarvishian)** for implementing Event Queue pattern, Service Locator pattern, and bug fixing. +- **[VladimirMirMir](https://github.com/VladimirMirMir)** for bug fixing. +- **[JayadevHaddadi](https://github.com/JayadevHaddadi)** for fixing event code. diff --git a/_images/programming-patterns-logo-original.jpg b/_images/programming-patterns-logo-original.jpg new file mode 100644 index 0000000..5fbef69 Binary files /dev/null and b/_images/programming-patterns-logo-original.jpg differ diff --git a/_images/programming-patterns-logo.png b/_images/programming-patterns-logo.png new file mode 100644 index 0000000..7005c74 Binary files /dev/null and b/_images/programming-patterns-logo.png differ diff --git a/_text/1-command.md b/_text/1-command.md new file mode 100644 index 0000000..cca9c46 --- /dev/null +++ b/_text/1-command.md @@ -0,0 +1,34 @@ +# 1. Command + +In you game you have many commands, such as play sound, throw cake, etc. It can be useful to wrap them in a command object. Now the command object doesn't have to care about how the command is executed. + +**How to implement?** + +You have a base class called Command which has a method that a child can implement called Execute. In each child class, you put in the Execute method what will actually happen when you run (execute) that command. + +**When is it useful?** + +- To rebind keys. Example of this is available in the code section. + +- To make a replay system. When you play the game, you store in some data structure which button you pressed each update. When you want to replay what has happened, you just iterate through each command while running the game. Example of this is available in the code section. + +- To make an undo and redo system. Is similar to the replay system, but in each command you also have a method called Undo() where you do the opposite of what the command is doing. Example of this is available in the code section. + +- To encapsulate AI behaviors and actions. Each AI behavior can be represented as a command, making it easier to control and update AI actions during gameplay. + +- To define the sequence of actions to be executed during events or cutscenes in games. + +- To manage and apply different abilities, power-ups, or effects during gameplay. + +- To manage event handling by encapsulating event-specific actions as commands and executing them when the corresponding events occur. + +- To simplify network communication In multiplayer games. Game commands can be serialized and sent over the network to synchronize actions among different players. + +**Related patterns** + +- **Subclass Sandbox.** You may end up with many child-command-classes. To easier handle the code, you can define high-level methods in the parent. + +- **Memento.** With this pattern you can also return to a previous state. + + +## [Back](../) \ No newline at end of file diff --git a/_text/10-bytecode.md b/_text/10-bytecode.md new file mode 100644 index 0000000..c09ab7b --- /dev/null +++ b/_text/10-bytecode.md @@ -0,0 +1,20 @@ +# 10. Bytecode + +What if other people want to help you with your game, but these people have no coding skillz. A solution is to invent a simpler programming language everyone can learn, and then you integrate it with your game. + +**How to implement?** + +The programmers with no skillz write their code in a .txt-file. You read that file, loop through each row, and then use a switch statement to translate the code from your programming language to C#. + +**When is it useful?** + +- To add modding support. + +- To avoid hard-coded behaviour. + +- To handle cutscenes and dialogue systems. Scripted sequences or dialogue interactions can be expressed in bytecode, allowing for easier management and execution of these sequences during gameplay. + +- To manage and execute the conditions and actions required to unlock achievements or track player progress. + + +## [Back](../) \ No newline at end of file diff --git a/_text/11-subclass-sandbox.md b/_text/11-subclass-sandbox.md new file mode 100644 index 0000000..f4ab9d3 --- /dev/null +++ b/_text/11-subclass-sandbox.md @@ -0,0 +1,22 @@ +# 11. Subclass Sandbox + +You have similar objects but they have different behavior. Create those behaviors in the child class by combining methods defined in the parent class. + +**How to implement?** + +Define several protected methods in the parent class and how they are implemented. In the child class, you call the methods you need to get the behavior you want. + +**When is it useful?** + +- When your child classes share behavior and the parent class can provide these behaviors. For example if you are using superpowers and the child class can combine these superpowers. This is an example from the book so you can find the code in the code section. + +**Related patterns** + +- **Update Method.** The Update Method is often implemented as a Sandbox method. + +- **Type Object.** Instead of defining all methods in the parent you could give the child a reference to an object that defines these methods. + +- **Template.** Here you override the methods in the parent class. + + +## [Back](../) \ No newline at end of file diff --git a/_text/12-type-object.md b/_text/12-type-object.md new file mode 100644 index 0000000..842bffa --- /dev/null +++ b/_text/12-type-object.md @@ -0,0 +1,28 @@ +# 12. Type Object + +You have an object and now you want to change its type (such as behavior or some data) by giving it a reference to an object that defines the type, thus the name Type Object. Another way could be to use class inheritance to define a child class which includes to code for the type, but that's not always possible because different children may be of the same type. + +**How to implement?** + +The Type Objects should share the same interface (or parent) to make it easier for the main class to reference the object. + +**When is it useful?** + +- When you can't (or don't want to) use class inheritance. Let's say you make a game with animals. You have a base class which is parent to all animals, and then as children to that class you add birds, fish, and mammals. In the bird class you define a flying behavior, which is all fine until you add an ostrich, which can't fly. In that case you have to inherit from the bird class and create new children that can fly and can't fly. But what about bats, which is a mammal that can fly? You don't want to add flying behavior in two separate classes! A better way is to define a flying and a non-flying type in a separate class, so both ostriches remain on the ground and bats can fly. + +- In game event systems, the Type Object can be used to define event types as objects. This allows for dynamic registration and handling of different event types during runtime, making the event system more versatile and adaptable. + +- Can be used to manage game configuration and settings. By representing different configuration options or settings as objects, you can dynamically switch between different configurations. + +- If you need to switching type at runtime. + +**Related patterns** + +- **State.** In both cases you have a main object and then you add another object to define something. The difference is that in State you switch the other object, while in Type Object that object remains the same. So if the type can be switched you get the State pattern. + +- **Subclass Sandbox.** You could define all types in the parent class and then combine them in the child class. + +- **Component.** The difference is that the Component is not always coupled with something else on the game object – it’s living its own life. In Unity you can add colliders, scripts, mesh renderers and they don’t need to know about each other to function. Type Object, however, is about adding a behavior to an existing class, so the type can't live on its own. + + +## [Back](../) diff --git a/_text/13-component.md b/_text/13-component.md new file mode 100644 index 0000000..09bff6a --- /dev/null +++ b/_text/13-component.md @@ -0,0 +1,20 @@ +# 13. Component + +When making a big game you should start thinking in components. A component is similar to your computer mouse, which you can attach to whatever computer you want through a USB port and it works fine. So a component is an object that's independent of other objects, making it reusable, and you can attach the component to several other objects if you want those objects to get the behavior described by the component. But in reality, some components have to communicate with each other, so they can't be entirely independent of each other: The mouse is communicating with the computer, but it's not communicating with the printer. + +**How to implement?** + +In Unity you can attach components to GameObjects, such as colliders, mesh renderers, your own scripts, so it's already built-in. It's up to you to make the custom scripts you attach as reusable as possible. + +**When is it useful?** + +- Because Unity's FPS counter is not to be trusted, you can have a custom FPS counter that you re-use throughout all projects. Just add the script to the project and attach it to some GameObject and it works fine independently of everything else going on in the game. + +- When making a car game you can put physics in one script, such as drag and rolling resistance, becuse physics will always affect the car and the physics calculations are the same for all cars. This component will not be completely independent because it will need some data from the car, such as current speed, but as said before that's fine. + +**Related patterns** + +- **Type Object.** The difference is that the Component is not always coupled with something else on the game object – it’s living its own life. In Unity you can add colliders, scripts, mesh renderers and they don’t need to know about each other to function. Type Object, however, is about adding a behavior to an existing class, so the type can't live on its own. + + +## [Back](../) \ No newline at end of file diff --git a/_text/14-event-queue.md b/_text/14-event-queue.md new file mode 100644 index 0000000..832d95b --- /dev/null +++ b/_text/14-event-queue.md @@ -0,0 +1,26 @@ +# 14. Event Queue + +You have some events but you can wait until later to process each event. This may be useful if you have many events that may be activated at the same time which will freeze the game because this pattern will spread them out over some time period. + +**How to implement?** + +Combine the Command pattern with C#'s built-in queue, which is why this pattern is sometimes known as a **Command Queue**. In the Update method you pick the first Command in the queue and run it while measuring time. To measure time you can use System.Diagnostics.Stopwatch. If you have time to spare, you run the next Command, and so on until you are out of time. How much time you can spend on the Event Queue each update depends on the game, so you have to experiment. + +**When is it useful?** + +- When you after an event will load an asset. This may take time, so if you want to play a sound when clicking a button, the game may freeze because it has to load the sound. A better way is to play the sound some frames after the click. + +- When you after an event will play a sound effect. What if 100 enemies die at the same time and each time an enemy dies you play a death-sound. Now 100 sounds will play at the same time. If you put the events in a queue, you can check if a sound is already playing and then ignore the event. You can also merge the events that are the same, so you have only one of each event type in the queue. + +- If you are making a strategy game, you can put orders in the queue that the player wants a certain unit to do: 1. build wall, 2. collect food, 3. attack creature. Now the player doesn't have to wait for a unit to finish one task. You can also put waypoints in the queue to make a unit patrol between waypoints. The AI can also put commands in a queue to for example determine which units should attack. + +- When making a speech system. Each character has its own queue with audio it wants to say. To know which character should speak, you can go through all queues. If the player presses Escape because the player doesn't want to listen to the talk, you simply clear all queues. + +**Related patterns** + +- **Event Bus.** Similar to Event Queue but there's no delay. + +- **Observer.** You use the Observer pattern to implement the Event Queue. + + +## [Back](../) \ No newline at end of file diff --git a/_text/15-service-locator.md b/_text/15-service-locator.md new file mode 100644 index 0000000..6116446 --- /dev/null +++ b/_text/15-service-locator.md @@ -0,0 +1,34 @@ +# 15. Service Locator + +When making your game you use many standardized methods to for example generate random numbers. These are called services and should be accessible from everywhere (globally) but still be independet from your game's main code. The pattern allows services to be easily replaced or extended without affecting the existing code that relies on them. + +**How to implement?** + +Put each service in a static class. The static class should be in its own folder and have its own namespace to make sure you are not mixing the services with your main code. + +Use a Service Locator that provides access to a service provider. To make sure no other methods than the ones you need are exposed to the outside world, the service provider should limit which methods it can provide access to. + +Unity has implemented this pattern in the form of the GetComponent() method. + +**When is it useful?** + +- Several services are already built-in into Unity, such as Random.Range() to get a random number, Mathf.PI to get pi, and Debug.Log() to display something in the console. + +- In the game you may have different audio objects depending on if the game is running on a console or PC. This is the same example as in the book so you can find the code for it in the code section. + +- To inject dependencies into game objects or systems - aka dependency injection. Instead of hardcoding the references to specific services, game objects can use the service locator to request and retrieve the required services at runtime. + +- To obtain the input service, abstracting away the underlying input device handling. + +- Objects or systems that need to display localized text can use the service locator to retrieve the appropriate localization service. + +- Objects that need AI functionality can use the service locator to access AI-related services, such as pathfinding or decision-making algorithms. + +**Related patterns** + +- **Singleton.** Both provide a global access to an object. So the problems with the Singleton also applies to this pattern. + +- **Facade.** You can use Facade in combination with Service Locator. + + +## [Back](../) \ No newline at end of file diff --git a/_text/16-data-locality.md b/_text/16-data-locality.md new file mode 100644 index 0000000..071efe1 --- /dev/null +++ b/_text/16-data-locality.md @@ -0,0 +1,20 @@ +# 16. Data Locality + +Have you done all optimizations you can possible do? Is the game still too slow? Then this pattern may help you. It can make your game faster by accelerating memory access. + +**How to implement?** + +You have to arrange data to take advantage of CPU caching. The basic idea is that you should organize your data structures so that the things you're processing are next to each other in memory. This is a big topic and can't be summarized here, so you should read about it in the book "Game Programming Patterns." + +This Unity article suggest that you should use struct instead of class because they are more cache friendly [How to Write Faster Code Than 90% of Programmers](https://jacksondunstan.com/articles/3860). + +Unity has implemented this pattern in their [Data-Oriented Technology Stack (DOTS)](https://unity.com/dots). + +A good Unity tutorial on the topic is: [Unity Memory Profiler: Where Are You Wasting Your Game's Memory?](https://thegamedev.guru/unity-memory/profiler-part-1/) and [Part 2](https://thegamedev.guru/unity-memory/profiler-part-2/). + +**When is it useful?** + +- According to the book "Game Programming Patterns," this pattern should be used when everything else has failed. It's a waste of time to optimize code that doesn't need to be optimized - and it may also make the code more complicated to understand. You also have to make sure that cache misses is the reason your code is slow, so you first have to measure it. + + +## [Back](../) \ No newline at end of file diff --git a/_text/17-dirty-flag.md b/_text/17-dirty-flag.md new file mode 100644 index 0000000..de555ee --- /dev/null +++ b/_text/17-dirty-flag.md @@ -0,0 +1,24 @@ +# 17. Dirty Flag + +This pattern is useful if something has changed in your game and if so you have to run a costly operation. A Dirty Flag is used to tell that something has changed but the costly operation hasn't been activated yet. You can often postpone the costly operation until the result is actually needed. So this pattern allows games to avoid unnecessary computations, updates, and data processing. + +**How to implement?** + +The dirty flag is just a bool. + +**When is it useful?** + +- Saving your game can be a costly operation. If something in your game has changed that also needs to be saved, you set a Dirty Flag in the save game object to true. Now if the player wants to quit the game, you can easily tell the player that there are unsaved changes. An example of this can be found in the code section. + +- When doing editor scripting in Unity, you can use SetDirty() to mark an object as dirty or you can even mark the entire scene as dirty. Now Unity will understand that you have changed something and those changes should be saved when you save your scene. + +- Unity is using it in the physics system. A RigidBody doesn't have to be updated unless a force is applied to it. If the RigidBody is sleeping (not moving), a Dirty Flag is used so the physics system can ignore it. + +- I used this pattern when experimenting with Genetic Algorithms (GA) and the Traveling Salesman Problem (TSP) where you find the shortest path between multiple cities. The GA generates multiple solutions, like 100, to the TSP and then each iteration you evolve 100 better solutions by calculating a cost function, which is the distance between all cities. You can use "tournament selection" to find good solutions from the previous iteration to the next, which is basically picking 3 solutions and returns the solution with the shortest distance between all cities. I realized I didn't have to calculate the cost fuction 100 times each iteration because it's a costly operation. To optimize I only calculate the cost function of the cities being picked by the tournament selection. I kept track of which solution has had its cost fuction calculated by using a bool which is set to false each iteration and then to true if the cost function has been run. + +- In multiplayer games, the Dirty Flag Pattern can be used to track changes in game state for network synchronization. Only data that has been marked as "dirty" needs to be sent across the network, reducing bandwidth usage and improving network performance. + +- Can be used to track changes in the game environment or AI state. The AI system can then prioritize updates and decision-making for objects or AI agents with "dirty" data. + + +## [Back](../) \ No newline at end of file diff --git a/_text/18-object-pool.md b/_text/18-object-pool.md new file mode 100644 index 0000000..bdc25c8 --- /dev/null +++ b/_text/18-object-pool.md @@ -0,0 +1,32 @@ +# 18. Object Pool + +If you constantly create and destroy objects, the performance of your game will suffer. A better way is to create the objects once when you start the game and deactivate them. When you need an object, you pick one of the deactivate objects and activate it. When you don't need the object anymore, you deactivate it instead of destroying it. + +**How to implement?** + +Create a class called object pool. Give it an object prefab and instantiate the number of objects you think you will need. Store them in a list. When you need an object you search through the list for a deactivated object and returns the first you find. If you realize you need more objects than the objects you started with, you have a few choises: + + - You can instantiate more objects during gameplay. But make sure you don't instantiate too many objects because it will be a waste of memory. You could later remove the "extra" objects you added. + + - Pick one of the objects that's active but the player will not notice if it suddeny disappears so you can use it. + + - Ignore that you have no more objects, which may be fine. If the screen is filled with explosions, the player will not notice a new explosion is missing. + +If you search the list to find an avilable object, and the list is very long because you have many pooled objects, you waste time. A better way is to store the objects in the pool in a linked-list. + +This pattern is so popular Unity has implemented their own version of it called [ObjectPool](https://docs.unity3d.com/ScriptReference/Pool.ObjectPool_1.html). Is only available in later versions of Unity. + +**When is it useful?** + +- When you fire bullets from a gun then you will need many bullets. I've given an example of this in the code section. You can find three versions: the optimized version which uses a linked-list, the slow ut simple version which has to search a list, and Unity's native object pool. + +- Unity is using this pattern in their particle system. In the particle settings you can set max number of particles, which can be useful so you don't accidentally instantiate millions of particles. + +**Related patterns** + +- **Data Locality.** In this pattern you pack objects of the same type together in memory. It will help the CPU cache to be full as the game iterates over those objects, which is what the Data Locality patterns is about. + +- **Prototype.** + + +## [Back](../) \ No newline at end of file diff --git a/_text/19-spatial-partition.md b/_text/19-spatial-partition.md new file mode 100644 index 0000000..9305442 --- /dev/null +++ b/_text/19-spatial-partition.md @@ -0,0 +1,33 @@ +# 19. Spatial Partition + +If you have many objects in your game, store the objects in a data structure that organizes the objects by their positions. This should make it faster to for example find which objects are colliding. + +**How to implement?** + +This is a common pattern, so you have several choices: + +- **Grid.** Divide the area into a grid and store in the data structure in which cell each object is located. This is the example from the book, so you can find the code for it in the code section. An alternative implementation can be found here: [Find overlaps among thousands of objects blazing fast](https://github.com/Habrador/Ten-Minute-Physics-Unity) which is implementing "Spatial Hashing" meaning that you are no longer bounded to a fixed grid - you can use a grid of infinite size! + +- **Trie.** Is actually called [Trie](https://en.wikipedia.org/wiki/Trie) and not Tree! + - [Quadtree (2d space)](https://en.wikipedia.org/wiki/Quadtree). Divide the square area into 4 cells. But if too many objects are in the same cell, divide that cell into 4 new cells. Continue until there are not "too many objects in the same cell." A good tutorial can be found here: [Coding Challenge #98.1: Quadtree - Part 1](https://www.youtube.com/watch?v=OJxEcs0w_kE). + - [Octree (3d space)](https://en.wikipedia.org/wiki/Octree). Is similar to Quadtree, but instead of cells you use cubes, so divide a cube volume into 8 cubes, and then split each cube into 8 new cubes and so on. + +- **Binary search trees.** The name is binary, so the difference between Tree is that you split the groups into 2 smaller groups, and then you split one of the smaller groups into 2 smaller groups, and so on. + - [Binary space partition (BSP)](https://en.wikipedia.org/wiki/Binary_space_partitioning). You use a plane to split a group into 2 new groups. And then you use another plane to split the new group into 2 new groups, and so on until you are finished. + - [k-d trees](https://en.wikipedia.org/wiki/K-d_tree). In this case it has to be points that you split into smaller, and smaller groups. + - [Bounding volume hierarchy](https://en.wikipedia.org/wiki/Bounding_volume_hierarchy). You pick a bounding volume (or area in 2d space), such as a rectangle. The size of the first rectangle is determined so all objects fit within it. Then you split the rectangle into two new rectangles, and so on. + +If the objects move you have to update the data structure. These data stuctures are also using more memory meaning you have to measure that putting the objects in a data structure is faster than just searching for the closest object. + +**When is it useful?** + +- Find the closest object to a character. This can be a really slow process if you have hundreds of objects around the character. And if you have soldiers fighting soldiers, you have to make that search for each soldier. A better way is to divide the search-area so you don't have to search thorough all objects - just the ones closest to you. + +- To increase the performance of collision detection and raytracing. + +- To deactivate objects if they are far away from your character to improve performance. This is called culling. You can hide for example trees and AI far away don't have to update themselves. + +- In games with pathfinding, spatial partitioning can help optimize the search for valid paths. By organizing the game world into a navigation grid or spatial data structure, pathfinding algorithms can be restricted to search only within relevant partitions, reducing computation time. + + +## [Back](../) \ No newline at end of file diff --git a/_text/2-flyweight.md b/_text/2-flyweight.md new file mode 100644 index 0000000..77b0556 --- /dev/null +++ b/_text/2-flyweight.md @@ -0,0 +1,26 @@ +# 2. Flyweight + +Even though a single object uses little memory – using many of them can cause trouble, so you need to make the objects lighter by sharing code. + +**How to implement?** + +Separate the data that’s not specific to a single instance of that object and can be shared across all of them. You can do that by creating a new class and put the shared data in it. Then each object that should share data gets a reference to a single instance of that "storage" class. + +**When is it useful?** + +- If you make Minecraft and have a million cubes in the scene. All cubes can share the same texture if you put all textures that belongs to each cube type (grass, stone, sand, etc) into a [texture atlas](https://en.wikipedia.org/wiki/Texture_atlas). + +- If you make a strategy game, all infantry units share the same mesh, texture, animation, maxHealth settings, etc. You only need to create one object with this data and then all infantry units can share that object. Each individual infantry unit only need to keep track of its own position and health. + +- This is implemented in Unity as [sharedMesh](https://docs.unity3d.com/ScriptReference/MeshFilter-sharedMesh.html) and [sharedMaterial](https://docs.unity3d.com/ScriptReference/Renderer-sharedMaterial.html). If you make a change to a sharedMesh then all objects using that mesh will get a new mesh. + +- In an open world game you can use the trees and rocks multiple times by rotating and scaling them - and no-one will see they are the same model. + +- If you make a car game it is enough to use one crash sound - and then change the settings of that sound, such as pitch, to create different crash sounds every time the car crashes. + +**Related patterns** + +- **Type Object.** The main difference is that in Type Object you don't need to have the exact same data and you can also have behavior. + + +## [Back](../) \ No newline at end of file diff --git a/_text/20-decorator.md b/_text/20-decorator.md new file mode 100644 index 0000000..3aa2f0b --- /dev/null +++ b/_text/20-decorator.md @@ -0,0 +1,26 @@ +# 20. Decorator + +You have a class you want to add some behaviors to in a flexible to an object way without modifying the original class. Other objects of the same class are uneffected, so it is used to dynamically extend the functionality of objects at runtime. Overall, the Decorator Pattern is a versatile and flexible design pattern that enables game developers to enhance and customize game objects or systems without modifying their core implementation. + +**How to implement?** + +You have a class and now you create several "decorator" classes that modifies some of the behaviors in the class you want to modify. The decorator class should wrap the class it wants to modify. The decorator class can in turn wrap itself to add other behaviors. This might be easier than the alternative to create child classes. + +**When is it useful?** + +- If you have an order system where people order several products at the same time but pay at a later time. An example of this can be found in the code section where you order Tesla cars with modifications. Yes you could store each order in a list, but a better way is to store them in objects linked to each other. Instead of iterating through each object to find the price, you can just ask the "last" object to get the price of the entire chain. + +- If you ever played Pubg you know you have weapons to which you can attach various attachments you find while playing the game. You can find magazines, sights, silenzers, etc, modifying the weapon's properties. You can use the Decorator pattern to implement this in your game. + +- To implement power-ups that temporarily modify the behavior of game objects. Each power-up can be represented as a decorator that wraps around the original object, adding specific enhancements, such as increased speed, damage boost, or invincibility. + +- To add special effects or animations to UI buttons, panels, or icons. + +- To dynamically adjust the difficulty level of a game. Decorators can be added or removed based on player performance or preferences, altering the game's challenges accordingly. + +**Related patterns** + +- **Subclass Sandbox.** You may end up with many child-classes. To easier handle the code, you can define high-level methods in the parent. + + +## [Back](../) \ No newline at end of file diff --git a/_text/21-factory.md b/_text/21-factory.md new file mode 100644 index 0000000..5c1fc50 --- /dev/null +++ b/_text/21-factory.md @@ -0,0 +1,28 @@ +# 21. Factory + +Collect all methods on how to create new objects in their own class. The factory can also be responsible for the destruction of objects. + +**How to implement?** + +If you are creating several different factories, then they should inherit from some parent abstract class. And the products you create should also inherit from some parent abstract class, so you can handle them as their parent without caring which child product that actually came out from the factory. + +**When is it useful?** + +- If you've implemented the **Decorator** then you can decorate the objects in a procedural way by using the Factory pattern. An example of this is in the code where you manufacture the Tesla cars you ordered in the Decorator pattern example. + +- To play sounds on different devices. An example of this can be found in the code section. + +- For each object you make you have to allocate some memory. By creating all objects in a central area it makes it easier to monitor these allocations. + +- To keep track of all of your Singletons. + +- The Factory Pattern can be used to create game objects, such as characters, enemies, items, obstacles, terrain features, structures, power-ups, collectibles, buttons, particles, etc. + +**Related patterns** + +- **Prototype.** The Prototype pattern is generally used if you want to make a copy of an existing object, while the Factory pattern is generating new objects. But some argue you can put the Prototype pattern inside of the Factory pattern. + +- **Object Pool.** The factory doesn't have to create new objects - it can be a recycling plant if you combine Factory with Object Pool. + + +## [Back](../) \ No newline at end of file diff --git a/_text/22-facade.md b/_text/22-facade.md new file mode 100644 index 0000000..ebc39a8 --- /dev/null +++ b/_text/22-facade.md @@ -0,0 +1,32 @@ +# 22. Facade + +When you have several related classes, such as AI or audio, and want to make it simpler to access methods in those classes. The name Facade comes from [building facades](https://en.wikipedia.org/wiki/Fa%C3%A7ade) - you can only see the exterior of the building, but have no idea how the building looks like inside. You can still access classes in the subsystem if you need to - the Facade is just making it simpler to access the more common classes. + +**How to implement?** + +Create a manager class that provides a single interface to a large collection of related classes. + +**When is it useful?** + +- In games it's common to write standardized code libraries, such as a library for the AI, which includes pathfinding, etc. These tend to include massive amounts of classes. To make it easier for yourself you create a script that includes access to the most important methods you need, such as get a short path. I made an open source library: [Computational geometry](https://github.com/Habrador/Computational-geometry). There are multiple methods on how to generate a Delaunay triangulation. To simplify the access to those methods I wrote a class called _Delaunay, which access each Delaunay method in a simple way. Otherwise you would have to first go into the Delaunay folder and figure out which class is doing what and which method you should use to generate the needed Delaunay triangulation. And if I decided to use another triangulation library I only need to change the facade script. Multiple Facades are allowed, so I also have another Facade for the intersection algorithms. + +- Random numbers are common in games. Should you use Unity's Random.Range or C#'s System.Random.Next? You can use the Facade pattern to easier switch between them. An example of this can be found in the code section. And if you find a third random number library, you can add it and you don't have to make a single change to the code that uses this Facade. + +- Can simplify audio interactions by providing methods for playing, pausing, stopping, and managing different audio sources. + +- Can provide a unified interface to handle keyboard, mouse, and controller inputs, abstracting the complexities of different input devices. + +- Can be used to create a simplified interface for managing game save and load operations. It encapsulates the details of serialization, deserialization, and data storage. + +- For games with physics simulation, a facade can provide a simplified interface for applying forces, detecting collisions, and managing physical interactions. It abstracts away the underlying physics engine complexities. + +**Related patterns** + +- **Service Locator.** The Service Locator is not necessarily consisting of several classes - the service we want to get might consist of a single class. But the Service Locator can use the Facade Pattern. + +- **Singleton.** The facade class is often a Singleton because you need only a single object to manage access to audio or to AI. + +- **Adapter.** This pattern is dealing with how to make code you can't modify work with your system. While Facade creates a new interface to simplify, Adapter adapts an old interface. These patterns are so similar that a book included both in the same chapter. + + +## [Back](../) \ No newline at end of file diff --git a/_text/23-template.md b/_text/23-template.md new file mode 100644 index 0000000..1a45987 --- /dev/null +++ b/_text/23-template.md @@ -0,0 +1,26 @@ +# 23. Template + +You have objects that uses the same overall algorithm, but the objects implement some steps in the algorithm in a different way. + +**How to implement?** + +Define a template method in the parent class which consists of calling several methods. In the child class, you override the methods that are specific for the child class. + +**When is it useful?** + +- When your child classes share behavior and the parent class can provide these behaviors. The example in the code shows how to assemble Tesla cars. While each car consists of different parts the process of assembling a car is the same. + +- To define the behavior of game characters. The common algorithm structure could include actions like movement, attacking, and interacting with the environment. Subclasses representing different character types (e.g., warrior, mage, rogue) can then override specific steps to implement their unique abilities and attributes. + +- In games that involve procedural level generation, the template algorithm can outline the general layout and components of a level, while subclasses can customize the details, such as terrain features, obstacles, and enemy placement. + +- For AI systems, the template algorithm could include steps like evaluating threats, considering objectives, and choosing actions. Different AI agents or enemy types can then provide their own implementations for specific decision-making criteria. + +- The Template Method Pattern can be applied to define the behavior of different game states (e.g., menu, gameplay, cutscene). The template algorithm could specify the transitions and behavior common to all states, while individual state subclasses can implement state-specific logic. + +**Related patterns** + +- **Subclass Sandbox.** Here you combine methods defined in the parent class. + + +## [Back](../) \ No newline at end of file diff --git a/_text/3-observer.md b/_text/3-observer.md new file mode 100644 index 0000000..d3749f9 --- /dev/null +++ b/_text/3-observer.md @@ -0,0 +1,31 @@ +# 3. Observer + +Many things are constantly happening in your game. These things are called events (or messages). The difference between event and message is that an event has happened while a message is something that will happen. So this pattern is all about what will happen after an event has happened. Which methods should be called after you killed an enemy to update score, show death animation, etc? These methods should subscribe to the event. + +**How to implement?** + +This pattern is so popular that C# has implemented it for you. Unity also has its own implementation. Your alternatives are: + +- EventHandler +- Action +- UnityEvent +- Your own implementation by using a delegate + +I've implemented all these in the code, so if you don't understand the difference take a look there. + +**When is it useful?** + +- This pattern is really useful if you want to avoid spaghetti code by making classes independent of each other, also known as decoupling. The best part of events is the part that's triggering the event doesn't care which methods are attached to the event. There might be zero methods. So if an event is triggered but nothing is happening you can easier find where the bug might be. + +- If you really want to decouple your code, then you still have a problem. To subscribe to the event you need a reference to the script where the event is defined. Another way is to create an Event Manager, which is a global class that takes care of all events. Unity has its own tutorial on how to implement that: [Creating a Simple Messaging System](https://www.youtube.com/watch?v=0AqG1fDhPT8). + +- Another way to decouple the code is to make the event static. An example of a static event is available in the code. + +**Related patterns** + +- **Event Queue.** The biggest problem with Observer is that it will trigger all methods subscribing to the event. If five methods subscribe, then five methods will be triggered. But what if 10 enemies are killed at the same time? Then 50 methods will be triggered and it can freeze the game. This is when you should use the Event Queue, which is basically the same as the Observer, but you put the events in a queue and you trigger as many as you can each Update without freezing the game. + +- **Model-View-Controller (MVC).** The MVC is an architectural pattern, and to implement it you can use the Observer pattern. + + +## [Back](../) \ No newline at end of file diff --git a/_text/4-prototype.md b/_text/4-prototype.md new file mode 100644 index 0000000..05afc02 --- /dev/null +++ b/_text/4-prototype.md @@ -0,0 +1,22 @@ +# 4. Prototype + +In your game you have a game object. Now you want to duplicate that object. This pattern allows you to create as many duplicates of an object as you want. + +**How to implement?** + +This is a pattern that already exists in Unity in the form of the [Instantiate-method](https://docs.unity3d.com/ScriptReference/Object.Instantiate.html). But it assumes that the object you want to duplicate inherits from Object, which is a class in UnityEngine. + +You can also make you own implementation. But then you have to ask yourself: do you do a deep clone (a copy of the structure and the elements in the structure) or a shallow clone (a copy of the structure not the elements in the structure)? Maybe the Flyweight pattern can give you the answer? + +**When is it useful?** + +- If you have a gun that fires bullets. You add one bullet prefab to the script. Each time you fire the gun you need a new bullet because you don't want to use the original bullet, so you call Unity's Instantiate-method and you get a duplicate of the original bullet. + +**Related patterns** + +- **Factory.** In the Factory you are generally generating new objects - not copies of already existing objects (which may include position and other states). You can put the Prototype inside of the Factory so you have one class where you create all objects instead of having the creation in multiple classes which might be troublesome if you want to change something. + +- **Object Pool.** If you Instantiate and destroy many game objects it will affect the performance of the game. To solve that problem you can use the Object Pool pattern. + + +## [Back](../) \ No newline at end of file diff --git a/_text/5-singleton.md b/_text/5-singleton.md new file mode 100644 index 0000000..245f0d5 --- /dev/null +++ b/_text/5-singleton.md @@ -0,0 +1,38 @@ +# 5. Singleton + +In your game you might have a class that saves the game for you. It's really important that you have just one instance of this class or you might save different versions of the game if each instance includes different data. It should also be easy to access this save game class from where you need it. You can use the Singleton pattern to accomplish this. + +**How to implement?** + +In C#. Make the instance static and provide a public static means of getting the reference to the single created instance. If the instance hasn't been created yet, create it. The constructor should be private and have no parameters. You can find this implemented in the code section. + +If your Singleton has to be thread safe, things will get more complicated. This is a good tutorial on the topic of more advanced Singleton patterns: [Implementing the Singleton Pattern in C#](https://csharpindepth.com/articles/singleton). + +In C# but the class also inherits from MonoBehaviour. If you want the Singleton to also inherit from MonoBehaviour (because you need some of that functionality) things will get more complicated. The problem now is that you can accidentally add several Singletons to the project. So you have to make sure you destroy all except one of the objects. Neither can you use a constructor, because MonoBehaviour doesn't allow it, so you have to implement your own constructor. You can find this implemented in the code section. + +**When is it not useful?** + +- According to the book "Game Programming Patterns," you should avoid this pattern because global objects can cause trouble. If you need to use this pattern, then it should be for manager classes, such as GameController, SaveGame, etc. The fewer Singletons the better! + +- If you use the MonoBehaviour version, a problem is that if you call the Singleton object from another object's OnDestroy method when you quit the game, the Singleton might have already been destroyed. + +**What are some alternatives?** + +You tend to use the Singleton pattern because you want an easy access to that script. But if Singletons are so bad, what are some alternatives? + +- **No class at all.** Most Singeltons are helpers, and in many cases you can remove the manager and put the help-code in the class the manager manages. + +- **Static class.** This is basically the Service Locator pattern. + +- **Unity's built-in Find() and SendMessage().** But these are so slow they should be avoided. If you have to use them, use them only once to get a reference to the script in the Start method. + +- **Assign references to pre-existing objects.** This means dragging the object (on which the script that used to be a Singleton is attached) to public variables exposed in the Editor. The problem now is that this may become very complicated, and if you change a reference you often have to again drag them to wherever it's needed, which may be many locations if you have many objects. + +- **A global event system.** This is the Observer pattern. You still need a Singleton for this global system, but you can remove all other Singletons. + +- **Dependency Injection.** You inject the reference to the object (that used to be a Singleton) in for example the constructor belonging to the class that need a reference to that object. There's also [Dependency Injection frameworks](https://www.youtube.com/watch?v=6tn8pMQuxEk) to make this process easier. + +- **One Singleton.** Have just one Singleton class and all managers that used to be Singletons are collected in this class. If you need the SaveGame object, you type GameController.Instance.getSaveGameManager(). + + +## [Back](../) \ No newline at end of file diff --git a/_text/6-state.md b/_text/6-state.md new file mode 100644 index 0000000..e12f310 --- /dev/null +++ b/_text/6-state.md @@ -0,0 +1,36 @@ +# 6. State + +Your game can be in a number of states. The main character can have the following states: jump, walk, run, etc. Now you want an easy way to switch between the states. This pattern is also known as a **state machine,** and if you have a finite amount of states you get a **finite state machine (FSM).** + +**How to implement?** + +You could use an enum that keeps track of each state and then a switch statement. The problem with the switch statement is that it becomes complicated the more states you add. A better way is to define an object for each state and then you switch between the objects as you switch states. + +**When is it useful?** + +- When you have too many nested if-statements, such as in a menu system. In the code, you can see an example of a menu system using the State pattern. + +- Unity is using this pattern in the animation engine. + +- When you make a turn-based combat system: [How to Code a Simple State Machine](https://www.youtube.com/watch?v=G1bd75R10m4). + +- If you are making a GTA-style game. You have one state for driving, one for when the character is not in a vehicle, another state for flying, etc. Then you can also add state-of-states. For example, in the state class where the character is not in a vehicle, you can have several sub-states, such as holding nothing, holding grenade, holding pistol, etc. + +- Enemy AI is often using the State pattern. The creepers in Minecraft have three states: move randomly when you are far away, move towards you if you are closer, blow up when you are very close. + +- The game itself can be a number of states: intro video, main menu, main game, mini game, etc. + +- Can be used to manage interactions between different game objects. For example, a door object can have states like open, closed, locked, and unlocked, and its behavior changes depending on its current state. + +**Related patterns** + +- **Type Object.** In both cases you have a main object and then you add another object to define something. The difference is that in State you switch the other object, while in Type Object that object remains the same. So if the object in Type Object can be switched you get the State pattern. + +- **Strategy.** With this pattern you can give an object a new behavior (a new strategy to follow) without taking into account its current state or states coming after the current behavior. + +- **Memento.** Same as state but you can roll back to a previous state. + +- **Behavior Tree.** Is useful if you have many states and want a more complex behavior. + + +## [Back](../) \ No newline at end of file diff --git a/_text/7-double-buffer.md b/_text/7-double-buffer.md new file mode 100644 index 0000000..8dfcdb6 --- /dev/null +++ b/_text/7-double-buffer.md @@ -0,0 +1,24 @@ +# 7. Double Buffer + +You have two buffers: you update #1 with new data while you are not allowed to modify #2 because #2 is holding old data from previous update, which you might want to display on the screen or use when updating #1. When you have finished updating #1, you swap them, so #2 is now including fresh data and you can start updating #1 which is now including old data. + +**How to implement?** + +You can have two arrays. You write to one of them, and when the calculations are finished you swap the pointer to the arrays. + +**When is it useful?** + +- To display stuff on the screen. This is already built-in into you computer which uses two buffers to display stuff on the screen. It reads from #2 while #1 is being updated with new data. When #1 is finished updating, the buffers are switched, so now you will see the newly updated data on the screen. It would look strange if you used just one buffer because then one part of the screen would display old data and one new data in some kind of horrible mix. + +- To generate motion blur. The current buffer is blended with a bit of the previous buffer. + +- Cellular Automata (CA). In games it's common to store data in a grid (which is a 2d array). To calculate new data you combine data from the cells, such as the maximum value of the current cell and surrounding cells. But where are you storing the data for the cell you just calculated? You can't store it in the cell because that will screw up the calculations for neighboring cells because you always want to use old data when doing the calculations. So you use two grids: #2 holds the old data and #1 is using #2 to update itself. When the calculations are finished, you swap them. + + - Cave-generation. This is the example I've included in the code. + + - [Water](http://www.jgallant.com/2d-liquid-simulator-with-cellular-automaton-in-unity/). You simulate movement of water on a grid. + + - [Forest fire](https://www.youtube.com/watch?v=JtGp9eUugFs). You store in each cell the amount of burning material in that cell, then you simulate heat to ignite the material. When there's no more material to burn, the heat disappears. + + +## [Back](../) \ No newline at end of file diff --git a/_text/8-game-loop.md b/_text/8-game-loop.md new file mode 100644 index 0000000..134cd3e --- /dev/null +++ b/_text/8-game-loop.md @@ -0,0 +1,24 @@ +# 8. Game Loop + +The game loop is the core of all games. It's basically an infinite while loop that keeps updating until you stop it. But the problem with such a while loop is that it updates faster on faster computers than it is on slower computers. This will be very problematic if you have some object that travels with some speed, then it will travel faster on the faster computer. To solve this problem you need to take time into account by using the following: + +- Fixed time step. You determine you want the game to run at 30 frames-per-second (FPS). Now you know how long one while loop should take (1/30 = 0.03333 seconds). If the while loop is faster than that, you simply pause it at the end until 0.03333 seconds has passed. If it's slower, you should optimize your game. + +- Variable (fluid) time step. You measure how many seconds has passed since the last frame. You then pass this time to the update method, so the game world can take bigger steps if the computer is slow and smaller steps if the computer is fast. + +**How to implement?** + +This pattern has already been implemented in Unity, which is actually using both versions of the while loop: + +- Fixed time step: Time.fixedDeltaTime. This version is used for physics calculations where you should use a constant step to make more accurate calculations. + +- Variable time step: [Time.deltaTime](https://docs.unity3d.com/ScriptReference/Time-deltaTime.html), which Unity defines as "The completion time in seconds since the last frame." + +The game loop is also checking for input before anything else. This is why in Unity you can type "if (Input.GetKey(KeyCode.A))" because the game loop has already checked (before the update method) if the A key has been pressed and stored that information in some data structure. + +**When is it useful?** + +- When you have a bullet that should move with a constant speed. So you determine a bulletSpeed and in the update method you multiply the speed with Time.deltaTime so the bullet travels with the same speed no matter how fast the computer is. + + +## [Back](../) \ No newline at end of file diff --git a/_text/9-update-method.md b/_text/9-update-method.md new file mode 100644 index 0000000..c0521b0 --- /dev/null +++ b/_text/9-update-method.md @@ -0,0 +1,12 @@ +# 9. Update Method + +The update method will process one frame of behavior. Each object that needs it should have its own update method because it would be difficult to combine everything in the game loop's update method. So each object that has a update method should be stored in some data structure, such as a list, and then you iterate over each one in the main update method. + +**How to implement?** + +This pattern has already been implemented in Unity, in the form of the Update() method, which you can use if your script inherits from MonoBehaviour. Then Unity processes each Update one-by-one in the main Update method. + +You could instead of using Unity's update method, implement your custom update method. You store all the scripts that uses this custom update method in a list. Then in some script, like a GameController, you iterate through this list in Unity's update method while calling each custom update method one-by-one. This may make it easier to for example pause your game by simply not iterating through that list when the game is paused. I've given an example of this in the code section. + + +## [Back](../) \ No newline at end of file