├── .gitignore ├── Assets ├── Materials.meta ├── Materials │ ├── FloorMaterial.mat │ ├── FloorMaterial.mat.meta │ ├── ObstacleMaterial 1.mat │ ├── ObstacleMaterial 1.mat.meta │ ├── VertexMaterial.mat │ └── VertexMaterial.mat.meta ├── Prefabs.meta ├── Prefabs │ ├── Agent.prefab │ ├── Agent.prefab.meta │ ├── DestinationNode.prefab │ ├── DestinationNode.prefab.meta │ ├── InvisibleObstacleBlock.prefab │ ├── InvisibleObstacleBlock.prefab.meta │ ├── ObstacleBlock.prefab │ ├── ObstacleBlock.prefab.meta │ ├── Vertex.prefab │ └── Vertex.prefab.meta ├── Scenes.meta ├── Scenes │ ├── MainScene.unity │ └── MainScene.unity.meta ├── Scripts.meta └── Scripts │ ├── AStarAlgorithm.cs │ ├── AStarAlgorithm.cs.meta │ ├── Agent.cs │ ├── Agent.cs.meta │ ├── AgentGenerator.cs │ ├── AgentGenerator.cs.meta │ ├── CameraScaler.cs │ ├── CameraScaler.cs.meta │ ├── GameTime.cs │ ├── GameTime.cs.meta │ ├── LevelPlatform.cs │ ├── LevelPlatform.cs.meta │ ├── ObstacleGenerator.cs │ ├── ObstacleGenerator.cs.meta │ ├── ReducedVisibilityGraphGenerator.cs │ └── ReducedVisibilityGraphGenerator.cs.meta ├── LICENSE ├── Packages ├── manifest.json └── packages-lock.json ├── ProjectSettings ├── AudioManager.asset ├── ClusterInputManager.asset ├── DynamicsManager.asset ├── EditorBuildSettings.asset ├── EditorSettings.asset ├── GraphicsSettings.asset ├── InputManager.asset ├── NavMeshAreas.asset ├── Physics2DSettings.asset ├── PresetManager.asset ├── ProjectSettings.asset ├── ProjectVersion.txt ├── QualitySettings.asset ├── TagManager.asset ├── TimeManager.asset ├── UnityConnectSettings.asset ├── VFXManager.asset └── XRSettings.asset ├── README.md └── Screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Never ignore Asset meta data 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /Assets/Materials.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e991cc6f32f68e040ac720b99cee827c 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials/FloorMaterial.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: FloorMaterial 11 | m_Shader: {fileID: 2, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _BumpMap: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _DetailAlbedoMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailMask: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailNormalMap: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _EmissionMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _MainTex: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _MetallicGlossMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _OcclusionMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _ParallaxMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | m_Floats: 59 | - _BumpScale: 1 60 | - _Cutoff: 0.5 61 | - _DetailNormalMapScale: 1 62 | - _DstBlend: 0 63 | - _GlossMapScale: 1 64 | - _Glossiness: 0.5 65 | - _GlossyReflections: 1 66 | - _Metallic: 0 67 | - _Mode: 0 68 | - _OcclusionStrength: 1 69 | - _Parallax: 0.02 70 | - _SmoothnessTextureChannel: 0 71 | - _SpecularHighlights: 1 72 | - _SrcBlend: 1 73 | - _UVSec: 0 74 | - _ZWrite: 1 75 | m_Colors: 76 | - _Color: {r: 0.8392157, g: 0.8392157, b: 0.8392157, a: 1} 77 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 78 | -------------------------------------------------------------------------------- /Assets/Materials/FloorMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3708d3a8dfaca2b449b4ca749d1405fb 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials/ObstacleMaterial 1.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: ObstacleMaterial 1 11 | m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _MainTex: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | m_Floats: [] 27 | m_Colors: 28 | - _Color: {r: 0, g: 0, b: 0, a: 1} 29 | -------------------------------------------------------------------------------- /Assets/Materials/ObstacleMaterial 1.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7be61c39298816144b30f16f56b01692 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Materials/VertexMaterial.mat: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!21 &2100000 4 | Material: 5 | serializedVersion: 6 6 | m_ObjectHideFlags: 0 7 | m_CorrespondingSourceObject: {fileID: 0} 8 | m_PrefabInstance: {fileID: 0} 9 | m_PrefabAsset: {fileID: 0} 10 | m_Name: VertexMaterial 11 | m_Shader: {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 12 | m_ShaderKeywords: 13 | m_LightmapFlags: 4 14 | m_EnableInstancingVariants: 0 15 | m_DoubleSidedGI: 0 16 | m_CustomRenderQueue: -1 17 | stringTagMap: {} 18 | disabledShaderPasses: [] 19 | m_SavedProperties: 20 | serializedVersion: 3 21 | m_TexEnvs: 22 | - _BumpMap: 23 | m_Texture: {fileID: 0} 24 | m_Scale: {x: 1, y: 1} 25 | m_Offset: {x: 0, y: 0} 26 | - _DetailAlbedoMap: 27 | m_Texture: {fileID: 0} 28 | m_Scale: {x: 1, y: 1} 29 | m_Offset: {x: 0, y: 0} 30 | - _DetailMask: 31 | m_Texture: {fileID: 0} 32 | m_Scale: {x: 1, y: 1} 33 | m_Offset: {x: 0, y: 0} 34 | - _DetailNormalMap: 35 | m_Texture: {fileID: 0} 36 | m_Scale: {x: 1, y: 1} 37 | m_Offset: {x: 0, y: 0} 38 | - _EmissionMap: 39 | m_Texture: {fileID: 0} 40 | m_Scale: {x: 1, y: 1} 41 | m_Offset: {x: 0, y: 0} 42 | - _MainTex: 43 | m_Texture: {fileID: 0} 44 | m_Scale: {x: 1, y: 1} 45 | m_Offset: {x: 0, y: 0} 46 | - _MetallicGlossMap: 47 | m_Texture: {fileID: 0} 48 | m_Scale: {x: 1, y: 1} 49 | m_Offset: {x: 0, y: 0} 50 | - _OcclusionMap: 51 | m_Texture: {fileID: 0} 52 | m_Scale: {x: 1, y: 1} 53 | m_Offset: {x: 0, y: 0} 54 | - _ParallaxMap: 55 | m_Texture: {fileID: 0} 56 | m_Scale: {x: 1, y: 1} 57 | m_Offset: {x: 0, y: 0} 58 | m_Floats: 59 | - _BumpScale: 1 60 | - _Cutoff: 0.5 61 | - _DetailNormalMapScale: 1 62 | - _DstBlend: 0 63 | - _GlossMapScale: 1 64 | - _Glossiness: 0.5 65 | - _GlossyReflections: 1 66 | - _Metallic: 0 67 | - _Mode: 0 68 | - _OcclusionStrength: 1 69 | - _Parallax: 0.02 70 | - _SmoothnessTextureChannel: 0 71 | - _SpecularHighlights: 1 72 | - _SrcBlend: 1 73 | - _UVSec: 0 74 | - _ZWrite: 1 75 | m_Colors: 76 | - _Color: {r: 0, g: 0.55553794, b: 1, a: 1} 77 | - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} 78 | -------------------------------------------------------------------------------- /Assets/Materials/VertexMaterial.mat.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee5b827cf8724ff4698a0ff83e40b0f7 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 0 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d383f3087dd810f4788fa9c33fa9b88b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Prefabs/Agent.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1137202035794871230 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 1137202035794871226} 12 | - component: {fileID: 1137202035794871229} 13 | - component: {fileID: 1137202035794871228} 14 | - component: {fileID: 1137202035794871231} 15 | - component: {fileID: 3349399905929400432} 16 | m_Layer: 0 17 | m_Name: Agent 18 | m_TagString: Untagged 19 | m_Icon: {fileID: 0} 20 | m_NavMeshLayer: 0 21 | m_StaticEditorFlags: 0 22 | m_IsActive: 1 23 | --- !u!4 &1137202035794871226 24 | Transform: 25 | m_ObjectHideFlags: 0 26 | m_CorrespondingSourceObject: {fileID: 0} 27 | m_PrefabInstance: {fileID: 0} 28 | m_PrefabAsset: {fileID: 0} 29 | m_GameObject: {fileID: 1137202035794871230} 30 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 31 | m_LocalPosition: {x: 0, y: 0, z: 0} 32 | m_LocalScale: {x: 6, y: 6, z: 6} 33 | m_Children: [] 34 | m_Father: {fileID: 0} 35 | m_RootOrder: 0 36 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 37 | --- !u!33 &1137202035794871229 38 | MeshFilter: 39 | m_ObjectHideFlags: 0 40 | m_CorrespondingSourceObject: {fileID: 0} 41 | m_PrefabInstance: {fileID: 0} 42 | m_PrefabAsset: {fileID: 0} 43 | m_GameObject: {fileID: 1137202035794871230} 44 | m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} 45 | --- !u!23 &1137202035794871228 46 | MeshRenderer: 47 | m_ObjectHideFlags: 0 48 | m_CorrespondingSourceObject: {fileID: 0} 49 | m_PrefabInstance: {fileID: 0} 50 | m_PrefabAsset: {fileID: 0} 51 | m_GameObject: {fileID: 1137202035794871230} 52 | m_Enabled: 1 53 | m_CastShadows: 1 54 | m_ReceiveShadows: 1 55 | m_DynamicOccludee: 1 56 | m_MotionVectors: 1 57 | m_LightProbeUsage: 1 58 | m_ReflectionProbeUsage: 1 59 | m_RayTracingMode: 2 60 | m_RenderingLayerMask: 1 61 | m_RendererPriority: 0 62 | m_Materials: 63 | - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} 64 | m_StaticBatchInfo: 65 | firstSubMesh: 0 66 | subMeshCount: 0 67 | m_StaticBatchRoot: {fileID: 0} 68 | m_ProbeAnchor: {fileID: 0} 69 | m_LightProbeVolumeOverride: {fileID: 0} 70 | m_ScaleInLightmap: 1 71 | m_ReceiveGI: 1 72 | m_PreserveUVs: 0 73 | m_IgnoreNormalsForChartDetection: 0 74 | m_ImportantGI: 0 75 | m_StitchLightmapSeams: 1 76 | m_SelectedEditorRenderState: 3 77 | m_MinimumChartSize: 4 78 | m_AutoUVMaxDistance: 0.5 79 | m_AutoUVMaxAngle: 89 80 | m_LightmapParameters: {fileID: 0} 81 | m_SortingLayerID: 0 82 | m_SortingLayer: 0 83 | m_SortingOrder: 0 84 | --- !u!135 &1137202035794871231 85 | SphereCollider: 86 | m_ObjectHideFlags: 0 87 | m_CorrespondingSourceObject: {fileID: 0} 88 | m_PrefabInstance: {fileID: 0} 89 | m_PrefabAsset: {fileID: 0} 90 | m_GameObject: {fileID: 1137202035794871230} 91 | m_Material: {fileID: 0} 92 | m_IsTrigger: 0 93 | m_Enabled: 1 94 | serializedVersion: 2 95 | m_Radius: 0.5 96 | m_Center: {x: 0, y: 0, z: 0} 97 | --- !u!114 &3349399905929400432 98 | MonoBehaviour: 99 | m_ObjectHideFlags: 0 100 | m_CorrespondingSourceObject: {fileID: 0} 101 | m_PrefabInstance: {fileID: 0} 102 | m_PrefabAsset: {fileID: 0} 103 | m_GameObject: {fileID: 1137202035794871230} 104 | m_Enabled: 1 105 | m_EditorHideFlags: 0 106 | m_Script: {fileID: 11500000, guid: 782ef2f3a4da6904498087bc15d4d9a4, type: 3} 107 | m_Name: 108 | m_EditorClassIdentifier: 109 | destinationNodePrefab: {fileID: 2866421121599163525, guid: 9de80ac0f2e57544f8bfd036b714b81e, 110 | type: 3} 111 | lineRendererMaterial: {fileID: 2100000, guid: cf6ad0080ba948e489d6a4ce338561c3, 112 | type: 2} 113 | -------------------------------------------------------------------------------- /Assets/Prefabs/Agent.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1dbff60a207567f44af4795f8be54f80 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Prefabs/DestinationNode.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &2866421121599163525 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 6156489831891860808} 12 | - component: {fileID: 3386047482675471616} 13 | - component: {fileID: 83763422369347251} 14 | - component: {fileID: 5224461143561956751} 15 | m_Layer: 0 16 | m_Name: DestinationNode 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &6156489831891860808 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 2866421121599163525} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: -114, y: 19.9, z: 45.21853} 31 | m_LocalScale: {x: 6, y: 6, z: 6} 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!33 &3386047482675471616 37 | MeshFilter: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 2866421121599163525} 43 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 44 | --- !u!23 &83763422369347251 45 | MeshRenderer: 46 | m_ObjectHideFlags: 0 47 | m_CorrespondingSourceObject: {fileID: 0} 48 | m_PrefabInstance: {fileID: 0} 49 | m_PrefabAsset: {fileID: 0} 50 | m_GameObject: {fileID: 2866421121599163525} 51 | m_Enabled: 1 52 | m_CastShadows: 1 53 | m_ReceiveShadows: 1 54 | m_DynamicOccludee: 1 55 | m_MotionVectors: 1 56 | m_LightProbeUsage: 1 57 | m_ReflectionProbeUsage: 1 58 | m_RayTracingMode: 2 59 | m_RenderingLayerMask: 1 60 | m_RendererPriority: 0 61 | m_Materials: 62 | - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} 63 | m_StaticBatchInfo: 64 | firstSubMesh: 0 65 | subMeshCount: 0 66 | m_StaticBatchRoot: {fileID: 0} 67 | m_ProbeAnchor: {fileID: 0} 68 | m_LightProbeVolumeOverride: {fileID: 0} 69 | m_ScaleInLightmap: 1 70 | m_ReceiveGI: 1 71 | m_PreserveUVs: 0 72 | m_IgnoreNormalsForChartDetection: 0 73 | m_ImportantGI: 0 74 | m_StitchLightmapSeams: 1 75 | m_SelectedEditorRenderState: 3 76 | m_MinimumChartSize: 4 77 | m_AutoUVMaxDistance: 0.5 78 | m_AutoUVMaxAngle: 89 79 | m_LightmapParameters: {fileID: 0} 80 | m_SortingLayerID: 0 81 | m_SortingLayer: 0 82 | m_SortingOrder: 0 83 | --- !u!65 &5224461143561956751 84 | BoxCollider: 85 | m_ObjectHideFlags: 0 86 | m_CorrespondingSourceObject: {fileID: 0} 87 | m_PrefabInstance: {fileID: 0} 88 | m_PrefabAsset: {fileID: 0} 89 | m_GameObject: {fileID: 2866421121599163525} 90 | m_Material: {fileID: 0} 91 | m_IsTrigger: 0 92 | m_Enabled: 1 93 | serializedVersion: 2 94 | m_Size: {x: 1, y: 1, z: 1} 95 | m_Center: {x: 0, y: 0, z: 0} 96 | -------------------------------------------------------------------------------- /Assets/Prefabs/DestinationNode.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9de80ac0f2e57544f8bfd036b714b81e 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Prefabs/InvisibleObstacleBlock.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &5421570492862004167 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 5164197320210644482} 12 | - component: {fileID: 2629221840390291806} 13 | - component: {fileID: 8665854201621143711} 14 | - component: {fileID: 5814292131874331610} 15 | m_Layer: 0 16 | m_Name: InvisibleObstacleBlock 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &5164197320210644482 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 5421570492862004167} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 0, y: 0, z: 0} 31 | m_LocalScale: {x: 19, y: 19, z: 19} 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!33 &2629221840390291806 37 | MeshFilter: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 5421570492862004167} 43 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 44 | --- !u!23 &8665854201621143711 45 | MeshRenderer: 46 | m_ObjectHideFlags: 0 47 | m_CorrespondingSourceObject: {fileID: 0} 48 | m_PrefabInstance: {fileID: 0} 49 | m_PrefabAsset: {fileID: 0} 50 | m_GameObject: {fileID: 5421570492862004167} 51 | m_Enabled: 0 52 | m_CastShadows: 1 53 | m_ReceiveShadows: 1 54 | m_DynamicOccludee: 1 55 | m_MotionVectors: 1 56 | m_LightProbeUsage: 1 57 | m_ReflectionProbeUsage: 1 58 | m_RayTracingMode: 2 59 | m_RenderingLayerMask: 1 60 | m_RendererPriority: 0 61 | m_Materials: 62 | - {fileID: 2100000, guid: 7be61c39298816144b30f16f56b01692, type: 2} 63 | m_StaticBatchInfo: 64 | firstSubMesh: 0 65 | subMeshCount: 0 66 | m_StaticBatchRoot: {fileID: 0} 67 | m_ProbeAnchor: {fileID: 0} 68 | m_LightProbeVolumeOverride: {fileID: 0} 69 | m_ScaleInLightmap: 1 70 | m_ReceiveGI: 1 71 | m_PreserveUVs: 0 72 | m_IgnoreNormalsForChartDetection: 0 73 | m_ImportantGI: 0 74 | m_StitchLightmapSeams: 1 75 | m_SelectedEditorRenderState: 3 76 | m_MinimumChartSize: 4 77 | m_AutoUVMaxDistance: 0.5 78 | m_AutoUVMaxAngle: 89 79 | m_LightmapParameters: {fileID: 0} 80 | m_SortingLayerID: 0 81 | m_SortingLayer: 0 82 | m_SortingOrder: 0 83 | --- !u!65 &5814292131874331610 84 | BoxCollider: 85 | m_ObjectHideFlags: 0 86 | m_CorrespondingSourceObject: {fileID: 0} 87 | m_PrefabInstance: {fileID: 0} 88 | m_PrefabAsset: {fileID: 0} 89 | m_GameObject: {fileID: 5421570492862004167} 90 | m_Material: {fileID: 0} 91 | m_IsTrigger: 0 92 | m_Enabled: 1 93 | serializedVersion: 2 94 | m_Size: {x: 1, y: 1, z: 1} 95 | m_Center: {x: 0, y: 0, z: 0} 96 | -------------------------------------------------------------------------------- /Assets/Prefabs/InvisibleObstacleBlock.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 27f98d23392d8ea44aa750639e5bbf32 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Prefabs/ObstacleBlock.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &5421570492862004167 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 5164197320210644482} 12 | - component: {fileID: 2629221840390291806} 13 | - component: {fileID: 8665854201621143711} 14 | - component: {fileID: 5814292131874331610} 15 | m_Layer: 0 16 | m_Name: ObstacleBlock 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &5164197320210644482 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 5421570492862004167} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 0, y: 0, z: 0} 31 | m_LocalScale: {x: 10, y: 10, z: 10} 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!33 &2629221840390291806 37 | MeshFilter: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 5421570492862004167} 43 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 44 | --- !u!23 &8665854201621143711 45 | MeshRenderer: 46 | m_ObjectHideFlags: 0 47 | m_CorrespondingSourceObject: {fileID: 0} 48 | m_PrefabInstance: {fileID: 0} 49 | m_PrefabAsset: {fileID: 0} 50 | m_GameObject: {fileID: 5421570492862004167} 51 | m_Enabled: 1 52 | m_CastShadows: 1 53 | m_ReceiveShadows: 1 54 | m_DynamicOccludee: 1 55 | m_MotionVectors: 1 56 | m_LightProbeUsage: 1 57 | m_ReflectionProbeUsage: 1 58 | m_RayTracingMode: 2 59 | m_RenderingLayerMask: 1 60 | m_RendererPriority: 0 61 | m_Materials: 62 | - {fileID: 2100000, guid: 7be61c39298816144b30f16f56b01692, type: 2} 63 | m_StaticBatchInfo: 64 | firstSubMesh: 0 65 | subMeshCount: 0 66 | m_StaticBatchRoot: {fileID: 0} 67 | m_ProbeAnchor: {fileID: 0} 68 | m_LightProbeVolumeOverride: {fileID: 0} 69 | m_ScaleInLightmap: 1 70 | m_ReceiveGI: 1 71 | m_PreserveUVs: 0 72 | m_IgnoreNormalsForChartDetection: 0 73 | m_ImportantGI: 0 74 | m_StitchLightmapSeams: 1 75 | m_SelectedEditorRenderState: 3 76 | m_MinimumChartSize: 4 77 | m_AutoUVMaxDistance: 0.5 78 | m_AutoUVMaxAngle: 89 79 | m_LightmapParameters: {fileID: 0} 80 | m_SortingLayerID: 0 81 | m_SortingLayer: 0 82 | m_SortingOrder: 0 83 | --- !u!65 &5814292131874331610 84 | BoxCollider: 85 | m_ObjectHideFlags: 0 86 | m_CorrespondingSourceObject: {fileID: 0} 87 | m_PrefabInstance: {fileID: 0} 88 | m_PrefabAsset: {fileID: 0} 89 | m_GameObject: {fileID: 5421570492862004167} 90 | m_Material: {fileID: 0} 91 | m_IsTrigger: 0 92 | m_Enabled: 1 93 | serializedVersion: 2 94 | m_Size: {x: 1, y: 1, z: 1} 95 | m_Center: {x: 0, y: 0, z: 0} 96 | -------------------------------------------------------------------------------- /Assets/Prefabs/ObstacleBlock.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 235d6ae875950ca45bd26a0fcd3d3781 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Prefabs/Vertex.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &2986103322948217498 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 936096505064621942} 12 | - component: {fileID: 7217637283484426555} 13 | - component: {fileID: 4494090862130028638} 14 | - component: {fileID: 2602971118123785329} 15 | m_Layer: 0 16 | m_Name: Vertex 17 | m_TagString: Untagged 18 | m_Icon: {fileID: 0} 19 | m_NavMeshLayer: 0 20 | m_StaticEditorFlags: 0 21 | m_IsActive: 1 22 | --- !u!4 &936096505064621942 23 | Transform: 24 | m_ObjectHideFlags: 0 25 | m_CorrespondingSourceObject: {fileID: 0} 26 | m_PrefabInstance: {fileID: 0} 27 | m_PrefabAsset: {fileID: 0} 28 | m_GameObject: {fileID: 2986103322948217498} 29 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 30 | m_LocalPosition: {x: 0, y: 0, z: 0} 31 | m_LocalScale: {x: 7, y: 7, z: 7} 32 | m_Children: [] 33 | m_Father: {fileID: 0} 34 | m_RootOrder: 0 35 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 36 | --- !u!33 &7217637283484426555 37 | MeshFilter: 38 | m_ObjectHideFlags: 0 39 | m_CorrespondingSourceObject: {fileID: 0} 40 | m_PrefabInstance: {fileID: 0} 41 | m_PrefabAsset: {fileID: 0} 42 | m_GameObject: {fileID: 2986103322948217498} 43 | m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} 44 | --- !u!23 &4494090862130028638 45 | MeshRenderer: 46 | m_ObjectHideFlags: 0 47 | m_CorrespondingSourceObject: {fileID: 0} 48 | m_PrefabInstance: {fileID: 0} 49 | m_PrefabAsset: {fileID: 0} 50 | m_GameObject: {fileID: 2986103322948217498} 51 | m_Enabled: 1 52 | m_CastShadows: 1 53 | m_ReceiveShadows: 1 54 | m_DynamicOccludee: 1 55 | m_MotionVectors: 1 56 | m_LightProbeUsage: 1 57 | m_ReflectionProbeUsage: 1 58 | m_RayTracingMode: 2 59 | m_RenderingLayerMask: 1 60 | m_RendererPriority: 0 61 | m_Materials: 62 | - {fileID: 2100000, guid: ee5b827cf8724ff4698a0ff83e40b0f7, type: 2} 63 | m_StaticBatchInfo: 64 | firstSubMesh: 0 65 | subMeshCount: 0 66 | m_StaticBatchRoot: {fileID: 0} 67 | m_ProbeAnchor: {fileID: 0} 68 | m_LightProbeVolumeOverride: {fileID: 0} 69 | m_ScaleInLightmap: 1 70 | m_ReceiveGI: 1 71 | m_PreserveUVs: 0 72 | m_IgnoreNormalsForChartDetection: 0 73 | m_ImportantGI: 0 74 | m_StitchLightmapSeams: 1 75 | m_SelectedEditorRenderState: 3 76 | m_MinimumChartSize: 4 77 | m_AutoUVMaxDistance: 0.5 78 | m_AutoUVMaxAngle: 89 79 | m_LightmapParameters: {fileID: 0} 80 | m_SortingLayerID: 0 81 | m_SortingLayer: 0 82 | m_SortingOrder: 0 83 | --- !u!135 &2602971118123785329 84 | SphereCollider: 85 | m_ObjectHideFlags: 0 86 | m_CorrespondingSourceObject: {fileID: 0} 87 | m_PrefabInstance: {fileID: 0} 88 | m_PrefabAsset: {fileID: 0} 89 | m_GameObject: {fileID: 2986103322948217498} 90 | m_Material: {fileID: 0} 91 | m_IsTrigger: 0 92 | m_Enabled: 1 93 | serializedVersion: 2 94 | m_Radius: 0.5 95 | m_Center: {x: 0, y: 0, z: 0} 96 | -------------------------------------------------------------------------------- /Assets/Prefabs/Vertex.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0daa75482a6b1e64f938757bbdf5946e 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Scenes.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b5ff9d7323446d44a9cc8250f739b46b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scenes/MainScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9769ad75eda996244a915e975b64ffb8 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Assets/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f60627cd238598448b815d4ca5f3e5b5 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Assets/Scripts/AStarAlgorithm.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * The contents of this script are transformed from and built upon the pseudocode here https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode 3 | * and released under the CC BY-SA 4.0 License (see https://creativecommons.org/licenses/by-sa/4.0/). 4 | */ 5 | using System.Collections.Generic; 6 | using UnityEngine; 7 | 8 | // This class implements the A* algorithm and is used by the Agent.cs class 9 | public static class AStarAlgorithm 10 | { 11 | /* 12 | * Uses the A* algorithm to find the shortest path from a start vertex to a destination vertex from a list of vertices and a list of edges. 13 | * The shortest path is returned as a list of vertices. 14 | * The parameters startVertex and destinationVertex are indices of the vertices list. The method stores vertices using their indices. 15 | * This implementation of the A* algorithm uses the Euclidean distance as the weight of the edges. 16 | */ 17 | public static List AStar(int startVertex, int destinationVertex, List vertices, List edges) 18 | { 19 | List open = new List(); // The set of discovered vertices that may need to be expanded 20 | List parent = new List(); // For vertex v, parent[v] is the parent of v on the shortest path from the start vertex to the destination vertex 21 | List gScore = new List(); // The list of G scores. gScore[v] is the distance from the start vertex to vertex v 22 | List hScore = new List(); // The list of H scores. hScore[v] is the distance from vertex v to the destination vertex 23 | List fScore = new List(); // The list of F scores. fScore[v] = gScore[v] + hScore[v] 24 | int currentVertex = startVertex; // The vertex the algorithm is currently visiting 25 | 26 | // Initialize the G and F scores with infinite values and the H scores with Euclidean distances 27 | // and initialize the parent list 28 | for (int v = 0; v < vertices.Count; v++) 29 | { 30 | gScore.Add(float.MaxValue); 31 | fScore.Add(float.MaxValue); 32 | hScore.Add(ComputeEuclideanDistance(v, destinationVertex)); 33 | parent.Add(-1); // parent[v] == -1 means that vertex v has no parent 34 | } 35 | 36 | // Add the startVertex to the open list and set its scores 37 | open.Add(startVertex); 38 | gScore[startVertex] = 0; 39 | fScore[startVertex] = hScore[startVertex]; 40 | 41 | // While the open list is not empty 42 | while (open.Count > 0) 43 | { 44 | currentVertex = findLowestFScoreVertexInOpenList(); // Find the vertex in the open list with the lowest F score 45 | 46 | if (currentVertex == destinationVertex) 47 | { // The destination vertex has been reached 48 | return constructPath(currentVertex); // Return a list of vertices as the path 49 | } 50 | 51 | // The destination vertex has not been reached 52 | 53 | open.Remove(currentVertex); // Remove the current vertex from the open list 54 | List neighbors = FindNeighbors(currentVertex); // Find all neighbors of the currentVertex 55 | 56 | // For each neighbor of the currentVertex 57 | foreach (int neighbor in neighbors) 58 | { 59 | float tenative_gScore = gScore[currentVertex] + ComputeEuclideanDistance(currentVertex, neighbor); 60 | if (tenative_gScore < gScore[neighbor]) 61 | { 62 | // The path to the neighbor is better than the previous path 63 | // So, use the path to the neighbor instead of the previous path 64 | parent[neighbor] = currentVertex; // The parent of the neighbor is now the currentVertex 65 | gScore[neighbor] = tenative_gScore; // Compute the neighbor's G score 66 | fScore[neighbor] = gScore[neighbor] + hScore[neighbor]; // Compute the neighbor's H score 67 | 68 | if (!open.Exists(e => e == neighbor)) 69 | { // If the neighbor is not in the open list 70 | open.Add(neighbor); // Add it to the open list 71 | } 72 | } 73 | } 74 | } 75 | 76 | return null; // If we reached the end of the while loop, then a path was not found 77 | 78 | // A helper method that computes and sets the h score of a vertex 79 | void SetScores(int v) 80 | { 81 | gScore[v] = ComputeEuclideanDistance(startVertex, v); 82 | fScore[v] = gScore[v] + hScore[v]; 83 | } 84 | 85 | // A helper method that computes the Euclidean distance between two vertices 86 | float ComputeEuclideanDistance(int v1, int v2) 87 | { 88 | Vector3 vector = vertices[v2] - vertices[v1]; // A vector from v1 to v2 89 | return vector.magnitude; // Return the magnitude of the vector 90 | } 91 | 92 | // Finds the vertex with the lowest F score in the open list 93 | int findLowestFScoreVertexInOpenList() 94 | { 95 | float lowestFScore = float.MaxValue; 96 | int lowestScoreVertex = -1; 97 | 98 | foreach (int v in open) 99 | { 100 | SetScores(v); // Set the scores of v 101 | 102 | if (fScore[v] < lowestFScore) 103 | { 104 | lowestFScore = fScore[v]; 105 | lowestScoreVertex = v; 106 | } 107 | } 108 | 109 | return lowestScoreVertex; 110 | } 111 | 112 | // A helper method to find the neighbors of a vertex 113 | List FindNeighbors(int v) 114 | { 115 | List neighbors = new List(); 116 | 117 | foreach (Vector3[] edge in edges) 118 | { 119 | int v1 = vertices.FindIndex(e => e.x == edge[0].x && e.y == edge[0].y && edge[0].z == e.z); // Find the index of edge[0] in the vertices list 120 | int v2 = vertices.FindIndex(e => e.x == edge[1].x && e.y == edge[1].y && edge[1].z == e.z); // Find the index of edge[1] in the vertices list 121 | 122 | if (v == v1) 123 | { 124 | neighbors.Add(v2); 125 | } 126 | else if (v == v2) 127 | { 128 | neighbors.Add(v1); 129 | } 130 | } 131 | 132 | return neighbors; 133 | } 134 | 135 | // Construct the path as a list of vertex indices 136 | List constructPath(int current) 137 | { 138 | List path = new List(); // The path as a list of vertex indices 139 | path.Add(current); 140 | 141 | // While the currentVertex has a parent 142 | while (parent[current] != -1) 143 | { 144 | current = parent[current]; 145 | path.Add(current); 146 | } 147 | 148 | path.Reverse(); // Reverse the order of the elements in the path 149 | 150 | return path; // Return the path 151 | } 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /Assets/Scripts/AStarAlgorithm.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 53db7f138fef6534f813d70e50ed61c3 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/Agent.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is linked to the Agent gameobject prefab 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | 9 | /* 10 | * This class defines an agent's personal reduced visibility graph (with its start and end positions) 11 | * and handles the agent's motion. The agent repeatedly moves to random destination points. 12 | * The agent's motion is composed of edges on its visibility graph and is determined by performing 13 | * the A* algorithm to find a shortest path from its start vertex to its destination vertex. 14 | */ 15 | public class Agent : MonoBehaviour 16 | { 17 | public GameObject destinationNodePrefab; // The game object prefab that represents the agent's destination, used to instantiate a destination node 18 | 19 | private GameObject destinationNode; // The actual destination node that has been instantiated 20 | private Material lineRendererMaterial; // The material used for line renderers 21 | private static System.Random random = new System.Random(); // Create an instance of the Random class 22 | private List availableGridCoordinates = new List(); // A list of grid coordinates available for a destination node to be placed 23 | 24 | private Vector3 initialStartPosition; // The position where the agent was initially spawned 25 | private Color agentColor; // The color of the agent 26 | private int agentId; // The number that identifies the agent 27 | private Vector3 currentStartVertex; // The agent's current start position 28 | private Vector3 currentDestinationVertex; // The agent's current destination position 29 | private int currentStartVertexIndex; // The index of the currentStartVertex in the vertices list 30 | private int currentDestinationVertexIndex; // The index of the currentDestinationVertex in the vertices list 31 | private List shortestPathToDestination; // The shortest path from the start to destination vertex computed using the A* algorithm, as a list of vertex indices 32 | private int currentIndexOfPath; // The index of the shortestPathToDestination list that represents the vertex that the agent is currently moving to 33 | 34 | // The vertices and edges of the agent's personal reduced visibiliy graph 35 | private List vertices; 36 | private List edges; 37 | private int initialVerticesCount; // The number of elements in verticies when it was first initialized 38 | private int initialEdgesCount; // The number of elements in edges when it was first initialized 39 | 40 | private enum AgentState 41 | { 42 | MOVING_TO_DESTINATION, 43 | CHOOSE_NEW_DESTINATION, 44 | REPLAN_PATH, 45 | WAITING_TO_CHOOSE_NEW_DESTINATION, 46 | WAITING_TO_REPLAN_PATH 47 | } 48 | private AgentState agentState; 49 | private float agentWaitTime = 0.50f; // The amount of seconds an agent should wait before choosing a new destination 50 | 51 | private const float DISTANCE_UNIT = 2f; // The unit of distance by which the agent will move every GameTime.INVTERVAL seconds. Increasing this will increase the speed of the agent. 52 | 53 | private int replanningCounter = 0; // The amount of consecutive times the agent has tried to replan its path to avoid a collision 54 | private const int MAX_NUMBER_OF_REPLANNINGS = 3; // The maximum number of replannings the agent will do before choosing a new destination 55 | 56 | // Start is called before the first frame update 57 | void Start() 58 | { 59 | agentState = AgentState.CHOOSE_NEW_DESTINATION; 60 | gameObject.GetComponent().material.color = agentColor; // Set the color of the agent 61 | currentDestinationVertex = initialStartPosition; 62 | ReducedVisibilityGraphInit(); // Initialize the list of vertices and edges 63 | 64 | // The current start and destination vertices will always be the last two vertices in the vertices list 65 | currentStartVertexIndex = vertices.Count; 66 | currentDestinationVertexIndex = vertices.Count + 1; 67 | 68 | lineRendererMaterial = new Material(Shader.Find("Sprites/Default")); // Create the line renderer material 69 | 70 | PickRandomAvailableGridCoordinates(); // Skip the first available grid coordinate that is picked because it will always be just next to the agent 71 | 72 | /* 73 | * The following variables are initialized by the the AgentGenerator class: 74 | * agentColor 75 | * initialStartPosition 76 | * agentId 77 | * availableGridCoordinates 78 | */ 79 | } 80 | 81 | // Update is called once per frame 82 | private void Update() 83 | { 84 | if (agentState == AgentState.CHOOSE_NEW_DESTINATION) 85 | { // If the agent needs to pick a new destination 86 | 87 | currentStartVertex = currentDestinationVertex; // The previous destination vertex becomes the current start vertex 88 | currentDestinationVertex = PickRandomAvailableGridCoordinates(); // Picks a random destination veretx that is available for an agent to go to 89 | 90 | transform.position = currentStartVertex; // Make sure the agent is actually at its currentStartVertex 91 | 92 | DestroyEdgesOfPath(); // Destroy the lines of the path the agent was previously moving through 93 | ResetReducedVisibilityGraph(); // Reset the list of edges and vertices 94 | 95 | // Add the start and destination vertices to the graph 96 | vertices.Add(currentStartVertex); 97 | vertices.Add(currentDestinationVertex); 98 | 99 | // Add bitangent edges from the start and destination verticies to every other vertex 100 | for (int i = vertices.Count - 2; i < vertices.Count; i++) 101 | { 102 | for (int j = 0; j < vertices.Count; j++) 103 | { 104 | if (j == i || j == vertices.Count - 2 && i == vertices.Count - 1) 105 | { 106 | continue; 107 | } 108 | 109 | Vector3[] edge = new Vector3[] { vertices[i], vertices[j] }; // The current edge 110 | 111 | // If the edge is bitangent, it needs to be added to the graph 112 | if (ReducedVisibilityGraphGenerator.IsEdgeBitangent(edge, LevelPlatform.OBSTACLE_BLOCK_LENGTH)) 113 | { 114 | edges.Add(edge); 115 | } 116 | } 117 | } 118 | 119 | // Find the shortest path from the currentStartVertex to the currentDestinationVertex using the A* algorithm 120 | shortestPathToDestination = AStarAlgorithm.AStar(currentStartVertexIndex, currentDestinationVertexIndex, vertices, edges); 121 | 122 | // If a path to the destination was not found 123 | if (shortestPathToDestination == null) 124 | { 125 | return; // pick another destination node the next time the Update method is called 126 | } 127 | 128 | // Destroy and re-instantiate the destination node 129 | Destroy(destinationNode); 130 | destinationNode = InstantiateDestinationNode(currentDestinationVertex); 131 | 132 | // Indicate that the agent is now moving towards the new destination 133 | agentState = AgentState.MOVING_TO_DESTINATION; 134 | currentIndexOfPath = 1; // The agent is now moving to the second vertex of the shortestPathToDestination list (because it's already at the first) 135 | 136 | // Draw all edges of the agent's path to its current destination 137 | DrawEdgesOfPath(); 138 | } 139 | else if (agentState == AgentState.REPLAN_PATH) 140 | { 141 | // If the agent has exceeded its maximum number of replannings 142 | if (replanningCounter >= MAX_NUMBER_OF_REPLANNINGS) 143 | { 144 | replanningCounter = 0; // Reset the replanning counter 145 | currentDestinationVertex = transform.position; // Set the current destination vertex to the agent's current position 146 | agentState = AgentState.WAITING_TO_CHOOSE_NEW_DESTINATION; // Make it choose a new destination 147 | Invoke("ChangeAgentState", agentWaitTime); // Change the agent state to pick a new destination after some time 148 | return; 149 | } 150 | 151 | // Otherwise 152 | replanningCounter++; // Increment the replanning counter 153 | 154 | /* 155 | * The replanning strategy is to make the agent move back to the previous vertex in its path and return to the vertex 156 | * it was trying to go to 157 | */ 158 | 159 | if (currentIndexOfPath > 0) 160 | { 161 | currentIndexOfPath--; // Make the agent move to the previous vertex 162 | } 163 | else 164 | { 165 | currentIndexOfPath++; // Make the agent move to the next vertex 166 | } 167 | 168 | agentState = AgentState.MOVING_TO_DESTINATION; // Make the agent start following its path again 169 | } 170 | else if (agentState == AgentState.MOVING_TO_DESTINATION) 171 | { // Keep moving to the current vertex of the path 172 | int currentVertexIndex = shortestPathToDestination[currentIndexOfPath]; // Get the vertex index from the shortestPathToDestination list 173 | // If the agent has not reached the current vertex of the path it is moving to 174 | if (!transform.position.Equals(vertices[currentVertexIndex])) 175 | { 176 | if (!MoveToVertex(currentVertexIndex)) // Try to move towards the vertex 177 | { // If the agent did not move towards the vertex because it will collide with another agent 178 | agentState = AgentState.WAITING_TO_REPLAN_PATH; // The path needs to be replanned 179 | float timeToWait = 0.1f + (float)random.NextDouble(); // Pick a random time between 0.1 and 1.1 seconds for the agent to wait before replanning its path 180 | Invoke("ChangeAgentState", timeToWait); 181 | } 182 | } 183 | else 184 | { // Agent has reached the current vertex 185 | if (currentIndexOfPath == shortestPathToDestination.Count - 1) 186 | { // If the agent has reached the destination vertex 187 | agentState = AgentState.WAITING_TO_CHOOSE_NEW_DESTINATION; // Indicate that the destination has been reached 188 | Invoke("ChangeAgentState", agentWaitTime); // Change the agent state to pick a new destination after some time 189 | replanningCounter = 0; // Reset the replanning counter 190 | } 191 | else 192 | { // The agent has not reached the destination vertex 193 | currentIndexOfPath++; // Indicate that the agent is now moving to the vertex at the next index of the path 194 | } 195 | } 196 | } 197 | else 198 | { // agentState is WAITING_TO_CHOOSE_NEW_DESTINATION or WAITING_TO_REPLAN_PATH 199 | // Do nothing 200 | } 201 | } 202 | 203 | private void OnCollisionEnter(Collision collision) 204 | { 205 | Debug.Log("Hey"); 206 | 207 | if (collision.collider.name.Contains("Obstacle Block")) 208 | { 209 | Debug.Log("Hey"); 210 | } 211 | } 212 | 213 | // Initialize the list of verticies and edges of the agent's reduced visibility graph 214 | // as a copy of the lists in the ReducedVisibilityGraphGenerator class 215 | private void ReducedVisibilityGraphInit() 216 | { 217 | vertices = new List(); 218 | edges = new List(); 219 | 220 | // Initialize the list of vertices 221 | foreach (Vector3 vertex in ReducedVisibilityGraphGenerator.vertices) 222 | { 223 | vertices.Add(vertex); 224 | } 225 | 226 | // Initialize the list of edges 227 | foreach (Vector3[] edge in ReducedVisibilityGraphGenerator.edges) 228 | { 229 | Vector3[] newEdge = new Vector3[2]; 230 | newEdge[0] = edge[0]; 231 | newEdge[1] = edge[1]; 232 | edges.Add(newEdge); 233 | } 234 | 235 | // Initialize the count variables 236 | initialVerticesCount = vertices.Count; 237 | initialEdgesCount = edges.Count; 238 | } 239 | 240 | // Resets the list of vertices and edges by removing the two verticies and all of the edges that 241 | // were added to it from the previous start and destination positions 242 | private void ResetReducedVisibilityGraph() 243 | { 244 | // Reset the list of vertices 245 | while (vertices.Count > initialVerticesCount) 246 | { 247 | vertices.RemoveAt(vertices.Count - 1); 248 | } 249 | 250 | // Reset the list of edges 251 | while (edges.Count > initialEdgesCount) 252 | { 253 | edges.RemoveAt(edges.Count - 1); 254 | } 255 | } 256 | 257 | private GameObject InstantiateDestinationNode(Vector3 position) 258 | { 259 | GameObject obj = Instantiate(destinationNodePrefab, position, transform.rotation) as GameObject; 260 | obj.name = "Destination of Agent " + agentId; 261 | obj.GetComponent().material.color = agentColor; // Set the destination node's color to match the agent's color 262 | obj.transform.parent = transform.parent.transform; // Make the destination node a child of this agent's parent 263 | return obj; 264 | } 265 | 266 | // Make the agent move one DISTANCE_UNIT every GameTime.INTERVAl seconds towards the vertex at index vertexIndex, which is vertices[vertexIndex] 267 | // Returns true if the agent moved to the position, false otherwise. The agent will only move to the position if no collision will occur. 268 | private bool MoveToVertex(int vertexIndex) 269 | { 270 | float distanceToMove = DISTANCE_UNIT * GameTime.TimeFactor(); // The amount of distance that the agent will move by to the approach the vertex 271 | 272 | Vector3 agentToVertex = vertices[vertexIndex] - transform.position; // The vector from the agent to the vertex 273 | Vector3 newAgentPosition; // The agent's new position after moving 274 | 275 | // If the agent is within one distanceToMove of the vertex 276 | if (agentToVertex.magnitude <= distanceToMove) 277 | { 278 | newAgentPosition = vertices[vertexIndex]; // Set the position of the agent extacly at the position of the vertex 279 | } 280 | else 281 | { // Make the agent move one distance unit towards the vertex 282 | newAgentPosition = transform.position + distanceToMove * agentToVertex.normalized; 283 | } 284 | 285 | // If a collision will occur once the agent is at its new position 286 | if (WillCollide(newAgentPosition)) 287 | { 288 | return false; // The agent does not move towards the vertex 289 | } 290 | else 291 | { 292 | transform.position = newAgentPosition; // The agent moves 293 | return true; 294 | } 295 | 296 | // Helper method to check if the agent is about to collide with another agent when it is at a particular position 297 | bool WillCollide(Vector3 position) 298 | { 299 | // For each agent generated, other than this agent 300 | foreach (GameObject otherAgent in AgentGenerator.agents) 301 | { 302 | if (otherAgent.GetComponent().agentId == agentId) 303 | { 304 | continue; 305 | } 306 | 307 | Vector3 displacement = otherAgent.transform.position - position; // A displacement vector from position to the other agent's position 308 | 309 | // If the otherAgent is half of an obstacle block length away from this agent 310 | if (displacement.magnitude < LevelPlatform.OBSTACLE_BLOCK_LENGTH / 2f) 311 | { 312 | return true; // A collision is about to occur 313 | } 314 | } 315 | 316 | return false; // No collision is about to occur 317 | } 318 | } 319 | 320 | // Picks a random element from availableGridCoordinates, excluding the one corresponding to the agent's currentStartVertex, and converts it to a Unity position 321 | private Vector3 PickRandomAvailableGridCoordinates() 322 | { 323 | // Find the element and index of the availablGridCoordinates list to exlude 324 | int[] coordinatesToExclude = LevelPlatform.ConvertPositionToCoordinates(new int[] { (int)currentStartVertex.x, (int)currentStartVertex.z }); 325 | 326 | // Remove that element from the list and put it back at the end of the list 327 | availableGridCoordinates.RemoveAll(e => e[0] == coordinatesToExclude[0] && e[1] == coordinatesToExclude[1]); 328 | availableGridCoordinates.Add(coordinatesToExclude); 329 | 330 | // Pick a random element of the list, excluding the last element 331 | int randomIndex = random.Next(0, availableGridCoordinates.Count - 1); 332 | int[] coordinates = availableGridCoordinates[randomIndex]; 333 | int[] position = LevelPlatform.ConvertCoordinatesToPosition(coordinates); 334 | return new Vector3(position[0], ReducedVisibilityGraphGenerator.VERTEX_Y, position[1]); 335 | } 336 | 337 | // Changes the agent state to CHOOSE_NEW_DESTINATION or REPLAN_PATH 338 | private void ChangeAgentState() 339 | { 340 | if (agentState == AgentState.WAITING_TO_CHOOSE_NEW_DESTINATION) 341 | { 342 | agentState = AgentState.CHOOSE_NEW_DESTINATION; 343 | } 344 | else if (agentState == AgentState.WAITING_TO_REPLAN_PATH) 345 | { 346 | agentState = AgentState.REPLAN_PATH; 347 | } 348 | } 349 | 350 | // Draws the edges in the agent's current path to its destination 351 | private void DrawEdgesOfPath() 352 | { 353 | int numVertices = shortestPathToDestination.Count; // The number of vertices in the path to draw 354 | List verticesOfPath = new List(); // A list of all vertices in the path to draw 355 | 356 | // Instantiate verticesOfPath 357 | foreach (int vertexIndex in shortestPathToDestination) 358 | { 359 | verticesOfPath.Add(vertices[vertexIndex]); 360 | } 361 | 362 | // Instantiate the line renderer 363 | LineRenderer lineRenderer = new GameObject("Path: " + currentStartVertex.x + "," + currentStartVertex.z + " to " + currentDestinationVertex.x + "," + currentDestinationVertex.z).AddComponent(); 364 | lineRenderer.startWidth = 2f; 365 | lineRenderer.endWidth = 2f; 366 | lineRenderer.positionCount = numVertices; 367 | lineRenderer.useWorldSpace = true; 368 | lineRenderer.transform.parent = transform.parent; 369 | 370 | // Make the line renderer the same color as the agent 371 | lineRenderer.material = new Material(lineRendererMaterial); 372 | lineRenderer.startColor = agentColor; 373 | lineRenderer.endColor = agentColor; 374 | lineRenderer.material.color = agentColor; 375 | 376 | // Create the line 377 | lineRenderer.SetPositions(verticesOfPath.ToArray()); 378 | } 379 | 380 | // Destroys the edge the agent was previously moving through 381 | private void DestroyEdgesOfPath() 382 | { 383 | if (transform.parent.childCount < 3) 384 | { 385 | return; 386 | } 387 | 388 | GameObject path = transform.parent.GetChild(2).gameObject; 389 | Destroy(path); 390 | } 391 | 392 | // Setter method for availableGridCoordinates 393 | public void SetAvailableGridCoordinates(List coordinates) 394 | { 395 | availableGridCoordinates = coordinates; 396 | } 397 | 398 | // Setter method for initialStartPosition 399 | public void SetInitialStartPosition(Vector3 position) 400 | { 401 | initialStartPosition = position; 402 | } 403 | 404 | // Setter method for agentColor 405 | public void SetAgentColor(Color color) 406 | { 407 | agentColor = color; 408 | } 409 | 410 | // Setter method for agentId 411 | public void SetAgentId(int id) 412 | { 413 | agentId = id; 414 | } 415 | } 416 | -------------------------------------------------------------------------------- /Assets/Scripts/Agent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 782ef2f3a4da6904498087bc15d4d9a4 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/AgentGenerator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is linked to the Agents game object 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | 9 | /* 10 | * This class is used to generate a number of agents 11 | */ 12 | public class AgentGenerator : MonoBehaviour 13 | { 14 | public GameObject agent; // The agent game object 15 | public static List agents = new List(); // A list of all agents generated 16 | 17 | public int numberOfAgents = 1; // The number of agents to generate. It is possible that fewer agents are generated if there are no more grid positions available. 18 | private static List initialAvailableGridCoordinates = new List(); // A list of all grid positions initially available for an agent to start on 19 | private static List currentlyAvailableGridCoordinates = new List(); // A list of all available grid positions that have not yet been used to spawn an agent 20 | private static List distinctColors = new List() { Color.red, Color.green, Color.blue, Color.yellow, Color.magenta, 21 | Color.cyan, Color.black, Color.gray, Color.white }; // A list of distinct colors, one for each agent to generate 22 | private static System.Random random = new System.Random(); // An instance of the Random class 23 | 24 | // Awake is called before any other script's Start() method 25 | // This Awake method is set to execute after the ReducedVisibilityGraphGenerator.cs Awake method in the project settings 26 | void Awake() 27 | { 28 | // Make sure the number of agents is positive 29 | if (numberOfAgents < 0) 30 | { 31 | numberOfAgents = 0; 32 | } 33 | 34 | AvailableGridCoordinatesInit(); // Initialize availableGridCoordinates 35 | DistinctColorsInit(); // Initialize distinctColors 36 | 37 | // Generate the agents at random avaiable grid positions 38 | for (int i = 0; i < numberOfAgents; i++) 39 | { 40 | if (currentlyAvailableGridCoordinates.Count == 0) 41 | { // No more available grid coordinates to place an agent 42 | break; // Stop generating agents 43 | } 44 | 45 | int randomIndex = random.Next(0, currentlyAvailableGridCoordinates.Count); // Pick a random index of availableGridCoordinates 46 | int[] coordinate = currentlyAvailableGridCoordinates[randomIndex]; // The random coordinate chosen 47 | currentlyAvailableGridCoordinates.RemoveAt(randomIndex); // Remove the chosen coordinate from the list 48 | Color color = distinctColors[i % distinctColors.Count]; // Pick a distinct color 49 | InstantiateAgent(coordinate[0], coordinate[1], color, i); // Instantiate the agent at the random coordinate with a distinct color 50 | } 51 | } 52 | 53 | // Initialize the list of initial and currently available grid positions 54 | private void AvailableGridCoordinatesInit() 55 | { 56 | // For each (x, z) coordinates in the grid 57 | for (int x = 0; x < LevelPlatform.grid.GetLength(0); x++) 58 | { 59 | for (int z = 0; z < LevelPlatform.grid.GetLength(1); z++) 60 | { 61 | // If the coordinate is available 62 | if (CoordinateIsAvailable(x, z)) 63 | { 64 | initialAvailableGridCoordinates.Add(new int[] { x, z }); // Add it to the list of initial available grid coordinates 65 | currentlyAvailableGridCoordinates.Add(new int[] { x, z }); // Add it to the list of currently available grid coordinates 66 | } 67 | } 68 | } 69 | 70 | // A helper function to check if a grid coordinate is available 71 | bool CoordinateIsAvailable(int x, int z) 72 | { 73 | // If the coordinate is not a floor, then it is not available 74 | if (LevelPlatform.grid[x, z] != LevelPlatform.CoordinateType.FLOOR) 75 | { 76 | return false; 77 | } 78 | 79 | // If the coordinate is adjacent to a grid coordinate that is not a floor, then it is not available 80 | // This is done to prevent an agent or destination node from being generated right next to the exterior 81 | // or an obstacle because if it is, then there may be no bitangent edges that can reach it 82 | if (LevelPlatform.grid[x + 1, z] != LevelPlatform.CoordinateType.FLOOR || 83 | LevelPlatform.grid[x, z + 1] != LevelPlatform.CoordinateType.FLOOR || 84 | LevelPlatform.grid[x + 1, z + 1] != LevelPlatform.CoordinateType.FLOOR || 85 | LevelPlatform.grid[x - 1, z] != LevelPlatform.CoordinateType.FLOOR || 86 | LevelPlatform.grid[x, z - 1] != LevelPlatform.CoordinateType.FLOOR || 87 | LevelPlatform.grid[x - 1, z - 1] != LevelPlatform.CoordinateType.FLOOR || 88 | LevelPlatform.grid[x + 1, z - 1] != LevelPlatform.CoordinateType.FLOOR || 89 | LevelPlatform.grid[x - 1, z + 1] != LevelPlatform.CoordinateType.FLOOR 90 | ) 91 | { 92 | return false; 93 | } 94 | 95 | return true; // Otherwise, the coordinate is available 96 | } 97 | } 98 | 99 | // Add colors to the list of distinct colors if it does not have 100 | // at least one color for every agent to generate 101 | private void DistinctColorsInit() 102 | { 103 | int n = numberOfAgents; // The number of distinct colors to generate 104 | 105 | if (distinctColors.Count >= n) 106 | { 107 | return; // Do not reinstantiate the list 108 | } 109 | 110 | // A maximum of 360 distinct colors can be generated 111 | if (n > 360) 112 | { 113 | n = 360; 114 | } 115 | 116 | float hue; 117 | float saturation; 118 | float value; 119 | 120 | // Generate a number of colors equal to numberOfAgentsToGenerate 121 | for (int i = 0; i < 360; i += 360 / n) 122 | { 123 | hue = i / 360f; // Compute the hue 124 | saturation = (float)random.NextDouble(); // Compute the saturation 125 | value = (float)random.NextDouble(); // Compute the value 126 | distinctColors.Add(Color.HSVToRGB(hue, saturation, value)); // Convert the HSV to a Color object and add it to the list 127 | } 128 | } 129 | 130 | // Instantiate an agent at grid coordinates (x, z) with a particular color and id 131 | private void InstantiateAgent(int x, int z, Color color, int id) 132 | { 133 | // Create an empty parent object for the agent 134 | GameObject newParent = new GameObject(); 135 | newParent.name = "Agent " + id + " container"; 136 | newParent.transform.parent = transform; 137 | 138 | int[] position = LevelPlatform.ConvertCoordinatesToPosition(new int[] { x, z }); // Get the Unity position 139 | Vector3 vectorPosition = new Vector3(position[0], ReducedVisibilityGraphGenerator.VERTEX_Y, position[1]); 140 | GameObject newAgent = Instantiate(agent, vectorPosition, transform.rotation) as GameObject; // Instatiate agent 141 | newAgent.name = "Agent " + id; 142 | newAgent.transform.parent = newParent.transform; // Make the obstacle block a child of the parent game object created above 143 | newAgent.GetComponent().SetAgentColor(color); // Set the color of the agent 144 | newAgent.GetComponent().SetInitialStartPosition(new Vector3(vectorPosition.x, vectorPosition.y, vectorPosition.z)); // Set the agent's initial start coordinates 145 | newAgent.GetComponent().SetAgentId(id); // Set the agent's id 146 | 147 | // Copy the list of initialAvailableGridCoordinates 148 | List copy = new List(); 149 | 150 | foreach (int[] c in initialAvailableGridCoordinates) 151 | { 152 | copy.Add(c); 153 | } 154 | 155 | newAgent.GetComponent().SetAvailableGridCoordinates(copy); // Set the agent's list of available grid coordinates 156 | 157 | agents.Add(newAgent); // Add the agent to the list of agents 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Assets/Scripts/AgentGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d602333e8dad4db4797ef2be43865b39 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: -5 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/CameraScaler.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is linked to the Main Camera 6 | // The implementation of the UpdateOrthographicCameraSize() method is inspired by this source: https://pressstart.vip/tutorials/2018/06/14/37/understanding-orthographic-size.html 7 | using UnityEngine; 8 | 9 | /* 10 | * The purpose of this class is to scale the size of the Main Camera 11 | * By default, Unity will scale the height of the camera to the match the device's screen height when the height changes, but it will 12 | * not scale the width of the camera to match the device's screen width when the width changes. 13 | * So, this script makes the width and height of the camera scale to match the device's screen width and height whenever the aspect ratio is lower than the indended ratio of 16:10. 14 | */ 15 | public class CameraScaler : MonoBehaviour 16 | { 17 | private Camera cam; // The Main Camera 18 | 19 | private const float BASE_ORTHOGRAPHIC_CAMERA_SIZE = 240f; // The orthographic size of the camera when the device aspect ratio is greater than or equal to the game aspect ratio 20 | private const float GAME_ASPECT_RATIO = 16f / 10f; // The aspect ratio intended for the game (16:10) 21 | private static float currentDeviceAspectRatio = 0f; // The aspect ratio of the device that the game is currently being played on, which may change if the user resizes the game window 22 | private static float currentOrthographicCameraSize = BASE_ORTHOGRAPHIC_CAMERA_SIZE; // The current orthographic camera size, which depends on the device aspect ratio 23 | 24 | // Awake is called before any other script's Start method 25 | void Awake() 26 | { 27 | cam = Camera.main; 28 | UpdateOrthographicCameraSize(); 29 | } 30 | 31 | // Update is called once per frame 32 | void Update() 33 | { 34 | // Update the orthographic camera size if the device's aspect ratio has changed, meaning the user has resized the game window 35 | if ((float)Screen.width / (float)Screen.height != currentDeviceAspectRatio) 36 | { 37 | UpdateOrthographicCameraSize(); 38 | } 39 | } 40 | 41 | // Updates the orthographic camera size according the the device's current aspect ratio 42 | // This allows the game to scale up or down with the width of the screen 43 | private void UpdateOrthographicCameraSize() 44 | { 45 | currentDeviceAspectRatio = (float)Screen.width / (float)Screen.height; // Compute the device's current aspect ratio 46 | 47 | if (currentDeviceAspectRatio >= GAME_ASPECT_RATIO) 48 | { 49 | currentOrthographicCameraSize = BASE_ORTHOGRAPHIC_CAMERA_SIZE; // Keep the size at the base size 50 | } 51 | else 52 | { 53 | currentOrthographicCameraSize = BASE_ORTHOGRAPHIC_CAMERA_SIZE * (GAME_ASPECT_RATIO / currentDeviceAspectRatio); // Scale up/down the size to fit the screen 54 | } 55 | 56 | cam.orthographicSize = currentOrthographicCameraSize; // Set camera size 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Assets/Scripts/CameraScaler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af5f2d4c18c8de349b50f8472f21aacd 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/GameTime.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is not linked to a game object 6 | using UnityEngine; 7 | 8 | /* 9 | * This class defines the constant timestep interval used for the game's physics computations 10 | * The lower the time interval, the faster the game's overall physics motions will appear 11 | * 12 | * The Agent class is defined to make the agent move by a particular distance unit once every INTERVAL amount of time. 13 | * So, by decreasing INTERVAL, the agent will move faster. 14 | */ 15 | public static class GameTime 16 | { 17 | public const float INTERVAL = 0.02f; // 0.02 seconds 18 | public const float RATE = 1 / INTERVAL; // The framerate equivalent to the interval 19 | 20 | /* 21 | * This factor determines by how much an agent should move based on the actual time between frames 22 | * For example, if an agent is set to move by 1 distance unit once every GameTime.INTERVAL (so once every 0.02 seconds) but the time between frames was only 0.01 seconds, 23 | * then the timeFactor() will be 0.01/0.02 = 1/2. So for that single frame, the agent will move by 1/2 of the distance unit in order to keep its motion at 1 distance 24 | * unit every 0.02 seconds. 25 | */ 26 | public static float TimeFactor() 27 | { 28 | return Time.deltaTime * RATE; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Assets/Scripts/GameTime.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f6a7d85cee233914cadece0ada3af589 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/LevelPlatform.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is linked to the LevelPlatform game object 6 | using UnityEngine; 7 | 8 | /* 9 | * This class is used to define the position and boundaries of the LevelPlatform 10 | * and to define a grid for the whole level that contains the coordinates of all possible 11 | * positions on the level to place obstacle blocks and agents. 12 | * 13 | * The MainFloor is the inner rectangle of the LevelPlatform that does not contain the alcoves. 14 | * The alcoves are present around the MainFloor. The grid describes the whole floor, which is the rectangle 15 | * that contains all of the alcoves and the MainFloor. 16 | */ 17 | public class LevelPlatform : MonoBehaviour 18 | { 19 | public const float X = 0f; // The X-position of the LevelPlatform 20 | public const float Y = 0f; // The Y-position of the LevelPlatform 21 | public const float Z = 0f; // The Z-position of the LevelPlatform 22 | 23 | public const float WHOLE_FLOOR_MAX_X = X + 320f; // The maximum x-position of the main floor 24 | public const float WHOLE_FLOOR_MIN_X = X - 340f; // The minimum x-position of the main floor 25 | public const float WHOLE_FLOOR_MAX_Z = Z + 225f; // The maximum z-position of the main floor 26 | public const float WHOLE_FLOOR_MIN_Z = Z - 235f; // The minimum z-position of the main floor 27 | public const float WHOLE_FLOOR_WIDTH = WHOLE_FLOOR_MAX_X - WHOLE_FLOOR_MIN_X; // The width of the main floor 28 | public const float WHOLE_FLOOR_HEIGHT = WHOLE_FLOOR_MAX_Z - WHOLE_FLOOR_MIN_Z; // The height of the main floor 29 | 30 | public const float MAIN_FLOOR_MAX_X = X + 250f; // The maximum x-position of the main floor 31 | public const float MAIN_FLOOR_MIN_X = X - 250f; // The minimum x-position of the main floor 32 | public const float MAIN_FLOOR_MAX_Z = Z + 125f; // The maximum z-position of the main floor 33 | public const float MAIN_FLOOR_MIN_Z = Z - 125f; // The minimum z-position of the main floor 34 | public const float MAIN_FLOOR_WIDTH = MAIN_FLOOR_MAX_X - MAIN_FLOOR_MIN_X; // The width of the main floor 35 | public const float MAIN_FLOOR_HEIGHT = MAIN_FLOOR_MAX_Z - MAIN_FLOOR_MIN_Z; // The height of the main floor 36 | 37 | public const float OBSTACLE_BLOCK_LENGTH = 10f; // The length of one side of an obstacle block 38 | public const float INVISIBLE_OBSTACLE_BLOCK_LENGTH = 19f; // The length of one side of an insivible obstacle block 39 | 40 | /* 41 | * The matrix "grid" is a grid of coordinates which correspond to Unity positions on the rectangle containing the MainFloor and 42 | * all the alcoves. The functions convertPositionCoordinate and convertCoordinateToPosition are used to convert between the grid 43 | * coordinates and the Unity positions. 44 | * 45 | * grid[x, z] stores a integer enum CoordinateType value that corresponds to what is at that coordinate (empty space, floor, obstacle block, obstacle block vertex, alcove vertex, or agent) 46 | */ 47 | public static int[] MAX_GRID_COORDINATES = ConvertPositionToCoordinates(new int[] { (int)WHOLE_FLOOR_MAX_X, (int)WHOLE_FLOOR_MAX_Z }); // The maximum x and z grid coordinates. The minimum x and z coordinates are (0, 0). 48 | public static int[] MAX_MAIN_FLOOR_GRID_COORDINATES = ConvertPositionToCoordinates(new int[] { (int)MAIN_FLOOR_MAX_X, (int)MAIN_FLOOR_MAX_Z }); // The maximum x and z grid coordinates for the MainFloor 49 | public static int[] MIN_MAIN_FLOOR_GRID_COORDINATES = ConvertPositionToCoordinates(new int[] { (int)MAIN_FLOOR_MIN_X, (int)MAIN_FLOOR_MIN_Z }); // The maximum x and z grid coordinates for the MainFloor 50 | public enum CoordinateType 51 | { 52 | EMPTY, 53 | FLOOR, 54 | BLOCK, 55 | BLOCK_VERTEX, 56 | BLOCK_CORNER_VERTEX, 57 | ALCOVE_VERTEX_1, 58 | ALCOVE_VERTEX_2 59 | } 60 | public static CoordinateType[,] grid = new CoordinateType[MAX_GRID_COORDINATES[0] + 1, MAX_GRID_COORDINATES[1] + 1]; 61 | 62 | // Awake is called before any other script's Start() method 63 | // This Awake method is set to execute before the ObstacleGenerator.cs and ReducedVisibilityGraphGenerator.cs Awake method in the project settings 64 | void Awake() 65 | { 66 | transform.position = new Vector3(X, Y, Z); // Set the position of the LevelPlatform 67 | 68 | GridInit(); 69 | } 70 | 71 | // Initializes the grid with the coordinates of the floors and the empty spaces between alcoves 72 | public static void GridInit() 73 | { 74 | 75 | // Helper method that fills in floors in the grid 76 | // given a range in x and a range in z in Unity positions 77 | // It does not fill in floors at the edges of the intervals 78 | // in order to leave a buffer zone around the edges 79 | void fillInFloor(float minX, float maxX, float minZ, float maxZ) 80 | { 81 | int[] minCoordinates = ConvertPositionToCoordinates(new int[] { (int)minX, (int)minZ }); 82 | int[] maxCoordinates = ConvertPositionToCoordinates(new int[] { (int)maxX, (int)maxZ }); 83 | 84 | for (int x = minCoordinates[0] + 1; x <= maxCoordinates[0] - 1; x++) 85 | { 86 | for (int z = minCoordinates[1] + 1; z <= maxCoordinates[1] - 1; z++) 87 | { 88 | grid[x, z] = CoordinateType.FLOOR; 89 | } 90 | } 91 | } 92 | 93 | // Helper method that marks the Unity position (x, z) as a particular type of coordinate in the corresponding grid position 94 | void fillInVertexType(float x, float z, CoordinateType type) 95 | { 96 | int[] coordinates = ConvertPositionToCoordinates(new int[] { (int)x, (int)z }); 97 | grid[coordinates[0], coordinates[1]] = type; 98 | } 99 | 100 | // Fill in the grid as all empty space 101 | for (int x = 0; x <= MAX_GRID_COORDINATES[0]; x++) 102 | { 103 | for (int z = 0; z <= MAX_GRID_COORDINATES[1]; z++) 104 | { 105 | grid[x, z] = CoordinateType.EMPTY; 106 | } 107 | } 108 | 109 | // Fill in the MainFloor and its vertices 110 | fillInFloor(MAIN_FLOOR_MIN_X, MAIN_FLOOR_MAX_X, MAIN_FLOOR_MIN_Z, MAIN_FLOOR_MAX_Z); 111 | 112 | // Fill in the top-left alcove and its vertices 113 | fillInFloor(-190f, -130f, MAIN_FLOOR_MAX_Z - OBSTACLE_BLOCK_LENGTH, 205f); 114 | fillInVertexType(-190f, MAIN_FLOOR_MAX_Z, CoordinateType.ALCOVE_VERTEX_1); 115 | fillInVertexType(-130f, MAIN_FLOOR_MAX_Z, CoordinateType.ALCOVE_VERTEX_2); 116 | 117 | // Fill in the top-mid alcove and its vertices 118 | fillInFloor(-70f, 20f, MAIN_FLOOR_MAX_Z - OBSTACLE_BLOCK_LENGTH, 175f); 119 | fillInVertexType(-70f, MAIN_FLOOR_MAX_Z, CoordinateType.ALCOVE_VERTEX_1); 120 | fillInVertexType(20f, MAIN_FLOOR_MAX_Z, CoordinateType.ALCOVE_VERTEX_2); 121 | 122 | // Fill in the top-right alcove and its vertices 123 | fillInFloor(110f, 210f, MAIN_FLOOR_MAX_Z - OBSTACLE_BLOCK_LENGTH, 225f); 124 | fillInVertexType(110f, MAIN_FLOOR_MAX_Z, CoordinateType.ALCOVE_VERTEX_1); 125 | fillInVertexType(210f, MAIN_FLOOR_MAX_Z, CoordinateType.ALCOVE_VERTEX_2); 126 | 127 | // Fill in the bottom-left alcove and its vertices 128 | fillInFloor(-140f, -80f, -175f, MAIN_FLOOR_MIN_Z + OBSTACLE_BLOCK_LENGTH); 129 | fillInVertexType(-140f, MAIN_FLOOR_MIN_Z, CoordinateType.ALCOVE_VERTEX_1); 130 | fillInVertexType(-80f, MAIN_FLOOR_MIN_Z, CoordinateType.ALCOVE_VERTEX_2); 131 | 132 | // Fill in the bottom-mid alcove and its vertices 133 | fillInFloor(-20f, 80f, -235f, MAIN_FLOOR_MIN_Z + OBSTACLE_BLOCK_LENGTH); 134 | fillInVertexType(-20f, MAIN_FLOOR_MIN_Z, CoordinateType.ALCOVE_VERTEX_1); 135 | fillInVertexType(80f, MAIN_FLOOR_MIN_Z, CoordinateType.ALCOVE_VERTEX_2); 136 | 137 | // Fill in the bottom-right alcove and its vertices 138 | fillInFloor(130f, 200f, -185f, MAIN_FLOOR_MIN_Z + OBSTACLE_BLOCK_LENGTH); 139 | fillInVertexType(130f, MAIN_FLOOR_MIN_Z, CoordinateType.ALCOVE_VERTEX_1); 140 | fillInVertexType(200f, MAIN_FLOOR_MIN_Z, CoordinateType.ALCOVE_VERTEX_2); 141 | 142 | // Fill in the left-top alcove and its vertices 143 | fillInFloor(-340f, MAIN_FLOOR_MIN_X + OBSTACLE_BLOCK_LENGTH, 15f, 85f); 144 | fillInVertexType(MAIN_FLOOR_MIN_X, 15f, CoordinateType.ALCOVE_VERTEX_1); 145 | fillInVertexType(MAIN_FLOOR_MIN_X, 85f, CoordinateType.ALCOVE_VERTEX_2); 146 | 147 | // Fill in the left-bottom alcove and its vertices 148 | fillInFloor(-280f, MAIN_FLOOR_MIN_X + OBSTACLE_BLOCK_LENGTH, -85f, -25f); 149 | fillInVertexType(MAIN_FLOOR_MIN_X, -85f, CoordinateType.ALCOVE_VERTEX_1); 150 | fillInVertexType(MAIN_FLOOR_MIN_X, -25f, CoordinateType.ALCOVE_VERTEX_2); 151 | 152 | // Fill in the right-top alcove and its vertices 153 | fillInFloor(MAIN_FLOOR_MAX_X - OBSTACLE_BLOCK_LENGTH, 300f, 5f, 85f); 154 | fillInVertexType(MAIN_FLOOR_MAX_X, 5f, CoordinateType.ALCOVE_VERTEX_1); 155 | fillInVertexType(MAIN_FLOOR_MAX_X, 85f, CoordinateType.ALCOVE_VERTEX_2); 156 | 157 | // Fill in the right-bottom alcove and its vertices 158 | fillInFloor(MAIN_FLOOR_MAX_X - OBSTACLE_BLOCK_LENGTH, 320f, -95f, -35f); 159 | fillInVertexType(MAIN_FLOOR_MAX_X, -95f, CoordinateType.ALCOVE_VERTEX_1); 160 | fillInVertexType(MAIN_FLOOR_MAX_X, -35f, CoordinateType.ALCOVE_VERTEX_2); 161 | } 162 | 163 | /* 164 | * Converts (x, z) coordinates in the grid to its cooresponding position in Unity units on the whole floor 165 | * This scales up the coordinates by OBSTACLE_BLOCK_LENGTH 166 | * and converts them from a scale of 0...(LevelPlatform.WHOLE_FLOOR_MAX_X(or Z) - LevelPlatform.WHOLE_FLOOR_MIN_X(or Z)) 167 | * to a scale of LevelPlatform.MAIN_FLOOR_MIN_X(or Z)...LevelPlatform.WHOLE_FLOOR_MAX_X(or Z) 168 | */ 169 | public static int[] ConvertCoordinatesToPosition(int[] coordinates) 170 | { 171 | int x = coordinates[0]; // Get x 172 | int z = coordinates[1]; // Get z 173 | x = (int)(x * OBSTACLE_BLOCK_LENGTH); // Scale up x 174 | z = (int)(z * OBSTACLE_BLOCK_LENGTH); // Scale up z 175 | x = (int)(x + WHOLE_FLOOR_MIN_X); // Change the scale of x 176 | z = (int)(z + WHOLE_FLOOR_MIN_Z); // Change the scale of z 177 | int[] position = new int[] { x, z }; // Create the position to return 178 | return position; 179 | } 180 | 181 | /* 182 | * Converts an (x, z) position in Unity units on the MainFloor to its cooresponding coordinates in the grid 183 | * This converts (x, z) from a scale of LevelPlatform.WHOLE_FLOOR_MIN_X(or Z)...LevelPlatform.WHOLE_FLOOR_MAX_X(or Z) 184 | * to a scale of 0...(LevelPlatform.WHOLE_FLOOR_MAX_X(or Z) - LevelPlatform.WHOLE_FLOOR_MIN_X(or Z)) 185 | * and then scales down the coordinates by OBSTACLE_BLOCK_LENGTH 186 | */ 187 | public static int[] ConvertPositionToCoordinates(int[] position) 188 | { 189 | int x = position[0]; // Get x 190 | int z = position[1]; // Get z 191 | x = (int)(x - WHOLE_FLOOR_MIN_X); // Change the scale of x 192 | z = (int)(z - WHOLE_FLOOR_MIN_Z); // Change the scale of z 193 | x = (int)(x / OBSTACLE_BLOCK_LENGTH); // Scale down x 194 | z = (int)(z / OBSTACLE_BLOCK_LENGTH); // Scale down z 195 | int[] coordinates = new int[] { x, z }; // Create the coordinates to return 196 | return coordinates; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /Assets/Scripts/LevelPlatform.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f850a5b2f01270048b2a8e3b0fad649f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: -50 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/ObstacleGenerator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is linked to the obstacles game object 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | 9 | /* 10 | * This class is used to generate random L-shaped obstacles at the start of the game. 11 | * Each obstacle is composed of ObstacleBlock game objects, which are visible, and InvisibleObstacleBlock game objects, which are invisible 12 | * The InvisibleObstacleBlock game objects are larger versions of the ObstacleBlock game object which overlap each ObstacleBlock. 13 | * The puprose of the InvisibleObstacleBlock game objects are for raycasting in the ReducedVisibilityGraphGenerator 14 | * This class also defines a grid of posittions along the MainFloor where obstacle blocks can be placed. 15 | */ 16 | public class ObstacleGenerator : MonoBehaviour 17 | { 18 | public GameObject obstacleBlock; // The visible obstacle block 19 | public GameObject invisibleObstacleBlock; // The invisible obstacle block 20 | private List availableCoordinates = new List(); // A list of all coordinates on the MainFloor availble to put an obstacle corner block (the corner of the L-shape) 21 | private int numberOfObstaclesToGenerate; // Number of obstacles to generate (fewer may be generated if the number is too high) 22 | private int numberOfObstacles = 0; // The actual number of obstacles generated 23 | 24 | public const int MAX_OBSTACLE_BLOCKS = 4; // The maximum number of obstacle blocks used to generate one segment of an L-shaped obstacle 25 | public const int MAX_NUMBER_OF_OBSTACLES = 8; // The maximum number of obstacles to generate 26 | public const int MIN_NUMBER_OF_OBSTACLES = 4; // The minimum number of obstacles to generate 27 | 28 | // Awake is called before any other script's Start() method 29 | // This Awake method is set to execute after the LevelPlatform.cs Awake method in the project settings 30 | void Awake() 31 | { 32 | System.Random random = new System.Random(); // Create an instance of the Random class 33 | numberOfObstaclesToGenerate = random.Next(MIN_NUMBER_OF_OBSTACLES, MAX_NUMBER_OF_OBSTACLES + 1); // Choose a random number of obstacles to generate 34 | 35 | AvailableCoordinatesInit(); 36 | 37 | // For each obstacle that needs to be generated 38 | for (int i = 0; i < numberOfObstaclesToGenerate; i++) 39 | { 40 | if (availableCoordinates.Count == 0) 41 | { // If no more available coordinates 42 | return; 43 | } 44 | 45 | int[] cornerPosition = PickRandomFromList(availableCoordinates, random); // Pick a random position for the corner of the L-shaped obstacle 46 | int numHorizontalBlocks = random.Next(1, MAX_OBSTACLE_BLOCKS + 1); // Pick the number of horizontal blocks to generate from the corner 47 | int numVerticalBlocks = random.Next(1, MAX_OBSTACLE_BLOCKS + 1); // Pick the number of the vertical blocks to generate from the corner 48 | int horizontalBlocksDirection = random.Next(0, 2); // Pick the direction for the horizontal blocks (0 or 1) 49 | int verticalBlocksDirection = random.Next(0, 2); // Pick the direction for the vertical blocks (0 or 1) 50 | 51 | // Instantiate the corner point 52 | InstantiateBlock(cornerPosition[0], cornerPosition[1], i, LevelPlatform.CoordinateType.BLOCK_CORNER_VERTEX); 53 | 54 | // For each horizontal block to instantiate 55 | for (int j = 1; j <= numHorizontalBlocks; j++) 56 | { 57 | LevelPlatform.CoordinateType blockType; // The blockType (1 or 2) used when updating obstacleGrid 58 | 59 | if (j == numHorizontalBlocks) 60 | { 61 | blockType = LevelPlatform.CoordinateType.BLOCK_VERTEX; 62 | } 63 | else 64 | { 65 | blockType = LevelPlatform.CoordinateType.BLOCK; 66 | } 67 | 68 | if (horizontalBlocksDirection == 0) 69 | { // Positive direction 70 | InstantiateBlock(cornerPosition[0] + j, cornerPosition[1], i, blockType); 71 | } 72 | else 73 | { // Negative direction 74 | InstantiateBlock(cornerPosition[0] - j, cornerPosition[1], i, blockType); 75 | } 76 | } 77 | 78 | // For each vertical block to instantiate 79 | for (int j = 1; j <= numVerticalBlocks; j++) 80 | { 81 | LevelPlatform.CoordinateType blockType; // The blockType (1 or 2) used when updating obstacleGrid 82 | 83 | if (j == numVerticalBlocks) 84 | { 85 | blockType = LevelPlatform.CoordinateType.BLOCK_VERTEX; 86 | } 87 | else 88 | { 89 | blockType = LevelPlatform.CoordinateType.BLOCK; 90 | } 91 | 92 | if (verticalBlocksDirection == 0) 93 | { // Positive direction 94 | InstantiateBlock(cornerPosition[0], cornerPosition[1] + j, i, blockType); 95 | } 96 | else 97 | { // Negative direction 98 | InstantiateBlock(cornerPosition[0], cornerPosition[1] - j, i, blockType); 99 | } 100 | } 101 | 102 | 103 | int extraLeft = 0, extraRight = 0, extraUp = 0, extraDown = 0; // The extra amount of surrounding coordinates to remove, based on how many horizontal and vertical blocks were generated 104 | 105 | if (horizontalBlocksDirection == 0) 106 | { // Positive x direction 107 | extraRight = numHorizontalBlocks; 108 | } 109 | else 110 | { // Negative x direction 111 | extraLeft = numHorizontalBlocks; 112 | } 113 | 114 | if (verticalBlocksDirection == 0) 115 | { // Positive z direction 116 | extraUp = numVerticalBlocks; 117 | } 118 | else 119 | { // Negative z direction 120 | extraDown = numVerticalBlocks; 121 | } 122 | 123 | // Remove the coordinates on and surrounding the cornerPosition of the generated obstacle 124 | // This is done so that the next obstacle corner block is not placed on or surrounding the current corner block 125 | for (int j = -MAX_OBSTACLE_BLOCKS - 2 - extraLeft; j <= MAX_OBSTACLE_BLOCKS + 2 + extraRight; j++) 126 | { 127 | for (int k = -MAX_OBSTACLE_BLOCKS - 2 - extraDown; k <= MAX_OBSTACLE_BLOCKS + 2 + extraUp; k++) 128 | { 129 | int[] coordinatesToRemove = new int[] { cornerPosition[0] + j, cornerPosition[1] + k }; 130 | availableCoordinates.RemoveAll(c => coordinatesToRemove[0] == c[0] && coordinatesToRemove[1] == c[1]); // Remove coordinatesToRemove from the list of available coordinates 131 | } 132 | } 133 | 134 | numberOfObstacles++; 135 | } 136 | } 137 | 138 | // Returns a random element from the list l 139 | private int[] PickRandomFromList(List l, System.Random random) 140 | { 141 | if (l.Count == 0) 142 | { // If l is empty 143 | return null; 144 | } 145 | 146 | int i = random.Next(0, l.Count); // Pick a random index 147 | return l[i]; 148 | } 149 | 150 | // Instantiate an obstacle block at coordinates (x, z) for obstacle i with coordinate type blockType 151 | // and update obstacleGrid 152 | private void InstantiateBlock(int x, int z, int i, LevelPlatform.CoordinateType blockType) 153 | { 154 | int[] position = LevelPlatform.ConvertCoordinatesToPosition(new int[] { x, z }); // Get the Unity position 155 | Vector3 vectorPosition = new Vector3(position[0], ReducedVisibilityGraphGenerator.VERTEX_Y, position[1]); 156 | GameObject block = Instantiate(obstacleBlock, vectorPosition, transform.rotation) as GameObject; // Instatiate the obstacle block 157 | GameObject invisibleBlock = Instantiate(invisibleObstacleBlock, vectorPosition, transform.rotation) as GameObject; // Instatiate the invisible obstacle block at the same position as the obstacle block 158 | block.name = "Obstacle Block " + x + "," + z; 159 | invisibleBlock.name = "Invisible Obstacle Block " + x + "," + z; 160 | 161 | // Create an empty game object (as a child of the game object Obstacles) for the i-th obstacle, if not already created 162 | if (transform.childCount <= i) 163 | { 164 | GameObject child = new GameObject(); 165 | child.name = "Obstacle " + i; 166 | child.transform.parent = gameObject.transform; 167 | } 168 | 169 | block.transform.parent = transform.GetChild(i).transform; // Make the obstacle block a child of the i-th obstacle game object 170 | invisibleBlock.transform.parent = transform.GetChild(i).transform; 171 | 172 | // Update the grid 173 | LevelPlatform.grid[x, z] = blockType; 174 | } 175 | 176 | // Initialize the list of available coordinates to place blocks 177 | private void AvailableCoordinatesInit() 178 | { 179 | // For each coordinate in the grid where a block could be placed, excluding a buffer zone around the edges of the grid 180 | for (int x = LevelPlatform.MIN_MAIN_FLOOR_GRID_COORDINATES[0] + MAX_OBSTACLE_BLOCKS + 3; x <= LevelPlatform.MAX_MAIN_FLOOR_GRID_COORDINATES[0] - MAX_OBSTACLE_BLOCKS - 3; x++) 181 | { 182 | for (int z = LevelPlatform.MIN_MAIN_FLOOR_GRID_COORDINATES[1] + MAX_OBSTACLE_BLOCKS + 3; z <= LevelPlatform.MAX_MAIN_FLOOR_GRID_COORDINATES[1] - MAX_OBSTACLE_BLOCKS - 3; z++) 183 | { 184 | int[] coordinates = new int[] { x, z }; 185 | availableCoordinates.Add(coordinates); // Add the coordinate to the list 186 | } 187 | } 188 | } 189 | 190 | public int GetActualNumberOfObstaclesGenerated() 191 | { 192 | return numberOfObstacles; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /Assets/Scripts/ObstacleGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a7041b2f3e2143e43848b6eeabccc302 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: -20 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Assets/Scripts/ReducedVisibilityGraphGenerator.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 Christopher Boustros 3 | * SPDX-License-Identifier: MIT 4 | */ 5 | // This script is linked to the ReducedVisibilityGraph game object 6 | using System.Collections.Generic; 7 | using UnityEngine; 8 | 9 | public class ReducedVisibilityGraphGenerator : MonoBehaviour 10 | { 11 | public GameObject vertexObject; // The game object that represents a vertex 12 | 13 | public const float VERTEX_Y = LevelPlatform.Y + LevelPlatform.OBSTACLE_BLOCK_LENGTH / 2; // The Unity y-position of an agent 14 | public static List vertices = new List(); // The list of vertices in the graph 15 | public static List edges = new List(); // The list of edges in the graph 16 | 17 | // Awake is called before any other script's Start() method 18 | // This Awake method is set to execute after the ObstacleGenerator.cs Awake method in the project settings 19 | void Awake() 20 | { 21 | VerticesInit(); // Initialize the vertices list 22 | DrawVertices(); // Draw all the vertices 23 | 24 | EdgesInit(); // Initialize the edges list 25 | DrawEdges(); // Draw all the edges 26 | } 27 | 28 | /* 29 | * This method finds all reflex vertices from LevelPlatform.grid and adds them to the list of vertices. 30 | * The grid coordinates are converted to Unity positions. 31 | * 32 | * The reflex vertices are always added one grid unit away from an obstacle block or alcove vertex so that when the edges 33 | * of the reduced visibility graph are created, they do not scrape against the obstacles or the exterior. This is the reason 34 | * why the ObstacleGenerator class generates invisible obstacle blocks at the same position of each obstacle block which are 35 | * larger in size. These larger invisible obstacle blocks fill in the gaps between the obstacle blocks and the vertices so that 36 | * the raycasting that is done to initialize the edges list detects an obstacle between those gaps. 37 | */ 38 | private void VerticesInit() 39 | { 40 | 41 | // A helper method that converts (x, z) grid coordinates to a Vector3 Unity position and adds it to the list of vertices 42 | void AddCoordinatesToList(int x, int z) 43 | { 44 | int[] coordinates = LevelPlatform.ConvertCoordinatesToPosition(new int[] { x, z }); // Convert the coordinates to a Unity (x, z) position 45 | Vector3 vertex = new Vector3(coordinates[0], VERTEX_Y, coordinates[1]); // Create the corresponding Vector3 46 | vertices.Add(vertex); // Add the vertex to the list of vertices 47 | } 48 | 49 | // For each cell of the grid 50 | for (int x = 0; x < LevelPlatform.grid.GetLength(0); x++) 51 | { 52 | for (int z = 0; z < LevelPlatform.grid.GetLength(1); z++) 53 | { 54 | LevelPlatform.CoordinateType coordinateType = LevelPlatform.grid[x, z]; 55 | if (coordinateType == LevelPlatform.CoordinateType.ALCOVE_VERTEX_1 || coordinateType == LevelPlatform.CoordinateType.ALCOVE_VERTEX_2) 56 | { // If the cell is an alcove vertex 57 | int[] pos = LevelPlatform.ConvertCoordinatesToPosition(new int[] { x, z }); // Get the Unity position of the coordinate 58 | int vertexX, vertexZ; // The x and z grid coordinates of the vertex to add to the list 59 | 60 | LevelPlatform.CoordinateType type1 = LevelPlatform.CoordinateType.ALCOVE_VERTEX_1; 61 | 62 | // Move the vertex in one unit towards the interior of the MainFloor and one unit towards the interior 63 | // of the alcove (so that it is not exactly on the edge of the MainFloor) 64 | if (pos[0] == LevelPlatform.MAIN_FLOOR_MIN_X) 65 | { // The vertex is for a left-side alcove 66 | if (coordinateType == type1) 67 | { 68 | vertexX = x + 1; 69 | vertexZ = z + 1; 70 | } 71 | else 72 | { 73 | vertexX = x + 1; 74 | vertexZ = z - 1; 75 | } 76 | } 77 | else if (pos[0] == LevelPlatform.MAIN_FLOOR_MAX_X) 78 | { // The vertex is for a right-side alcove 79 | if (coordinateType == type1) 80 | { 81 | vertexX = x - 1; 82 | vertexZ = z + 1; 83 | } 84 | else 85 | { 86 | vertexX = x - 1; 87 | vertexZ = z - 1; 88 | } 89 | } 90 | else if (pos[1] == LevelPlatform.MAIN_FLOOR_MIN_Z) 91 | { // The vertex is for a bottom-side alcove 92 | if (coordinateType == type1) 93 | { 94 | vertexX = x + 1; 95 | vertexZ = z + 1; 96 | } 97 | else 98 | { 99 | vertexX = x - 1; 100 | vertexZ = z + 1; 101 | } 102 | } 103 | else 104 | { // The vertex is for a top-side alcove 105 | if (coordinateType == type1) 106 | { 107 | vertexX = x + 1; 108 | vertexZ = z - 1; 109 | } 110 | else 111 | { 112 | vertexX = x - 1; 113 | vertexZ = z - 1; 114 | } 115 | } 116 | 117 | AddCoordinatesToList(vertexX, vertexZ); // Add the vertex 118 | } 119 | else if (LevelPlatform.grid[x, z] == LevelPlatform.CoordinateType.BLOCK_CORNER_VERTEX) 120 | { // If the cell is a corner block on an L-shaped obstacle 121 | bool blockToTheRight = LevelPlatform.grid[x + 1, z] == LevelPlatform.CoordinateType.BLOCK || LevelPlatform.grid[x + 1, z] == LevelPlatform.CoordinateType.BLOCK_VERTEX; // True if there is a block to the right of the corner block 122 | bool blockAbove = LevelPlatform.grid[x, z + 1] == LevelPlatform.CoordinateType.BLOCK || LevelPlatform.grid[x, z + 1] == LevelPlatform.CoordinateType.BLOCK_VERTEX; // True if there is a block above the corner block 123 | 124 | int vertexX, vertexZ; // The x and z grid coordinates of the vertex to add to the list 125 | 126 | if (blockToTheRight) 127 | { // There is a block to the right 128 | vertexX = x - 1; 129 | } 130 | else 131 | { // There is a block to the left 132 | vertexX = x + 1; 133 | } 134 | 135 | if (blockAbove) 136 | { // There is a block above 137 | vertexZ = z - 1; 138 | } 139 | else 140 | { // There is a block below 141 | vertexZ = z + 1; 142 | } 143 | 144 | AddCoordinatesToList(vertexX, vertexZ); // Add the vertex just outside of the corner block 145 | } 146 | else if (LevelPlatform.grid[x, z] == LevelPlatform.CoordinateType.BLOCK_VERTEX) 147 | { // If the cell is one of the two vertex blocks of the L-shaped obstacle (not the corner block) 148 | bool blockToTheRight = LevelPlatform.grid[x + 1, z] == LevelPlatform.CoordinateType.BLOCK || LevelPlatform.grid[x + 1, z] == LevelPlatform.CoordinateType.BLOCK_CORNER_VERTEX; // True if there is a block to the right of the vertex block 149 | bool blockToTheLeft = LevelPlatform.grid[x - 1, z] == LevelPlatform.CoordinateType.BLOCK || LevelPlatform.grid[x - 1, z] == LevelPlatform.CoordinateType.BLOCK_CORNER_VERTEX; // True if there is a block to the left of the vertex block 150 | bool blockAbove = LevelPlatform.grid[x, z + 1] == LevelPlatform.CoordinateType.BLOCK || LevelPlatform.grid[x, z + 1] == LevelPlatform.CoordinateType.BLOCK_CORNER_VERTEX; // True if there is a block above the vertex block 151 | bool blockBelow = LevelPlatform.grid[x, z - 1] == LevelPlatform.CoordinateType.BLOCK || LevelPlatform.grid[x, z - 1] == LevelPlatform.CoordinateType.BLOCK_CORNER_VERTEX; // True if there is a block below the vertex block 152 | 153 | // Two vertices need to be added to the list: one for each outer vertex of the block 154 | int vertex1X, vertex1Z; // The x and z grid coordinates of the first vertex to add to the list 155 | int vertex2X, vertex2Z; // The x and z grid coordinates of the second vertex to add to the list 156 | 157 | if (blockToTheLeft || blockToTheRight) 158 | { // There is a block either to the left or to the right 159 | vertex1Z = z + 1; 160 | vertex2Z = z - 1; 161 | 162 | if (blockToTheRight) 163 | { // The block is to the right 164 | vertex1X = x - 1; 165 | vertex2X = x - 1; 166 | } 167 | else 168 | { // The block is to the left 169 | vertex1X = x + 1; 170 | vertex2X = x + 1; 171 | } 172 | } 173 | else 174 | { // There is a block either above or below 175 | vertex1X = x + 1; 176 | vertex2X = x - 1; 177 | 178 | if (blockAbove) 179 | { // The block is above 180 | vertex1Z = z - 1; 181 | vertex2Z = z - 1; 182 | } 183 | else 184 | { // The block is below 185 | vertex1Z = z + 1; 186 | vertex2Z = z + 1; 187 | } 188 | } 189 | 190 | // Add the two vertices on each outer vertex of the block to the list 191 | AddCoordinatesToList(vertex1X, vertex1Z); 192 | AddCoordinatesToList(vertex2X, vertex2Z); 193 | 194 | } 195 | } 196 | } 197 | } 198 | 199 | /* 200 | * This method initializes the edges list. It adds all edges that should be in the reduced visibility graph. 201 | * Edges that are added to the list are bitangent edges. 202 | * A bitangent edge is an edge between two reflex vertices (in the vertices list) that does not intersect an any object or the exterior, even when it is sligthly extended on either end 203 | * Raycasts are used to detect intersection between edges and objects. 204 | */ 205 | private void EdgesInit() 206 | { 207 | for (int i = 0; i < vertices.Count; i++) 208 | { 209 | for (int j = i + 1; j < vertices.Count; j++) 210 | { 211 | Vector3[] edge = new Vector3[] { vertices[i], vertices[j] }; // The current edge 212 | 213 | // If the edge is bitangent, it needs to be added to the graph 214 | if (IsEdgeBitangent(edge, 1.8f * LevelPlatform.OBSTACLE_BLOCK_LENGTH)) 215 | { 216 | edges.Add(edge); 217 | } 218 | } 219 | } 220 | } 221 | 222 | /* 223 | * Determine if the edge is bitangent, meaning it can be added to the reduced visibility graph 224 | * A bitangent edge is an edge that does not intestect with an obstacle block or the exterior, 225 | * even when extended a little from either side. 226 | * The parameter extension is the distance by which to extend the edge on either side when 227 | * checking for intersection with an obstacle or the exterior 228 | */ 229 | public static bool IsEdgeBitangent(Vector3[] edge, float extension) 230 | { 231 | Vector3 direction = (edge[1] - edge[0]).normalized; // The direction from the first vertex to the second vertex of the edge 232 | float distance = (edge[1] - edge[0]).magnitude + extension; // The distance between the two vertices, with a slight extension 233 | 234 | // The reason we need to cast a ray in both directions is that we extend the ray slightly beyond the destination vertex 235 | // So, we cast from vertex1 to vertex2 to extend slightly beyond vertex2, and from vertex2 to vertex1 to extend slightly beyond vertex1 236 | RaycastHit[] hits1 = Physics.RaycastAll(edge[0], direction, distance); // Cast a ray from the first vertex (edge[0]) to the second vertex (edge[1]) and store the array of all objects hit 237 | RaycastHit[] hits2 = Physics.RaycastAll(edge[1], -direction, distance); // Cast a ray from the second vertex to the first vertex and store the array of all objects hit 238 | 239 | // Check the array hits1 to see if an obstacle block (including an invisible obstacle block) or the exterior was hit 240 | foreach (RaycastHit hit in hits1) 241 | { 242 | if (hit.transform.name.Contains("Obstacle Block") || hit.transform.name.Contains("Exterior Cube")) 243 | { // An obstacle block or the exterior was hit 244 | return false; // Not bitangent 245 | } 246 | } 247 | 248 | // Check the array hits2 to see if an obstacle block was hit 249 | foreach (RaycastHit hit in hits2) 250 | { 251 | if (hit.transform.name.Contains("Obstacle Block") || hit.transform.name.Contains("Exterior Cube")) 252 | { // An obstacle block or the exterior was hit 253 | return false; // Not bitangent 254 | } 255 | } 256 | 257 | return true; // Bitangent because no obstacle block or the exterior was hit by a ray 258 | } 259 | 260 | // Draw the vertices in the list of vertices as game objects so that they are visible in the game 261 | private void DrawVertices() 262 | { 263 | // Create a child of the ReducedVisibilityGraph game object to store the vertex game objects 264 | GameObject child = new GameObject("Vertices"); 265 | child.transform.parent = gameObject.transform; 266 | 267 | // For each vertex position in the list of vertices 268 | foreach (Vector3 vertexPosition in vertices) 269 | { 270 | // Create the game object for the vertex to instantiate 271 | GameObject obj = Instantiate(vertexObject, vertexPosition, transform.rotation) as GameObject; // Instatiate the vertex object 272 | obj.name = "Vertex " + vertexPosition.x + "," + vertexPosition.z; 273 | obj.transform.parent = child.transform; // Make the obstacle block a child of the child created above 274 | } 275 | } 276 | 277 | // Draw the edges in the list of edges using line renderers so that they are visible in the game 278 | private void DrawEdges() 279 | { 280 | // Create a child of the ReducedVisibilityGraph game object to store the lines renderers for the edges 281 | GameObject child = new GameObject("Edges"); 282 | child.transform.parent = gameObject.transform; 283 | 284 | foreach (Vector3[] edge in edges) 285 | { 286 | // Instantiate the line renderer 287 | LineRenderer lineRenderer = new GameObject("Edge " + edge[0].x + "," + edge[0].z + " to " + edge[1].x + "," + edge[1].z).AddComponent(); 288 | lineRenderer.startWidth = 1f; 289 | lineRenderer.endWidth = 1f; 290 | lineRenderer.positionCount = 2; 291 | lineRenderer.useWorldSpace = true; 292 | lineRenderer.transform.parent = child.transform; // Make the line renderer a child of the child created above 293 | 294 | // Create the line 295 | lineRenderer.SetPositions(edge); 296 | } 297 | } 298 | } 299 | -------------------------------------------------------------------------------- /Assets/Scripts/ReducedVisibilityGraphGenerator.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a8f117bebae52604e861f23328e39cfc 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: -10 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All contents of this repository excluding the Assets/Scripts/AStarAlgorithm.cs 2 | file are released under the MIT License as follows: 3 | 4 | """ 5 | MIT License 6 | 7 | Copyright (c) 2020 Christopher Boustros 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | """ 27 | 28 | The Assets/Scripts/AStarAlgorithm.cs file (the "File") is released under the 29 | CC BY-SA 4.0 License (see http://creativecommons.org/licenses/by-sa/4.0/). 30 | The File was made by Christopher Boustros as an adaptation of the 31 | pseudocode released here: 32 | https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode 33 | -------------------------------------------------------------------------------- /Packages/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.collab-proxy": "1.2.16", 4 | "com.unity.ide.rider": "1.1.4", 5 | "com.unity.ide.vscode": "1.2.1", 6 | "com.unity.test-framework": "1.1.16", 7 | "com.unity.textmeshpro": "2.1.1", 8 | "com.unity.timeline": "1.2.16", 9 | "com.unity.ugui": "1.0.0", 10 | "com.unity.modules.ai": "1.0.0", 11 | "com.unity.modules.androidjni": "1.0.0", 12 | "com.unity.modules.animation": "1.0.0", 13 | "com.unity.modules.assetbundle": "1.0.0", 14 | "com.unity.modules.audio": "1.0.0", 15 | "com.unity.modules.cloth": "1.0.0", 16 | "com.unity.modules.director": "1.0.0", 17 | "com.unity.modules.imageconversion": "1.0.0", 18 | "com.unity.modules.imgui": "1.0.0", 19 | "com.unity.modules.jsonserialize": "1.0.0", 20 | "com.unity.modules.particlesystem": "1.0.0", 21 | "com.unity.modules.physics": "1.0.0", 22 | "com.unity.modules.physics2d": "1.0.0", 23 | "com.unity.modules.screencapture": "1.0.0", 24 | "com.unity.modules.terrain": "1.0.0", 25 | "com.unity.modules.terrainphysics": "1.0.0", 26 | "com.unity.modules.tilemap": "1.0.0", 27 | "com.unity.modules.ui": "1.0.0", 28 | "com.unity.modules.uielements": "1.0.0", 29 | "com.unity.modules.umbra": "1.0.0", 30 | "com.unity.modules.unityanalytics": "1.0.0", 31 | "com.unity.modules.unitywebrequest": "1.0.0", 32 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 33 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 34 | "com.unity.modules.unitywebrequesttexture": "1.0.0", 35 | "com.unity.modules.unitywebrequestwww": "1.0.0", 36 | "com.unity.modules.vehicles": "1.0.0", 37 | "com.unity.modules.video": "1.0.0", 38 | "com.unity.modules.vr": "1.0.0", 39 | "com.unity.modules.wind": "1.0.0", 40 | "com.unity.modules.xr": "1.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Packages/packages-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "com.unity.collab-proxy": { 4 | "version": "1.2.16", 5 | "depth": 0, 6 | "source": "registry", 7 | "dependencies": {}, 8 | "url": "https://packages.unity.com" 9 | }, 10 | "com.unity.ext.nunit": { 11 | "version": "1.0.0", 12 | "depth": 1, 13 | "source": "registry", 14 | "dependencies": {}, 15 | "url": "https://packages.unity.com" 16 | }, 17 | "com.unity.ide.rider": { 18 | "version": "1.1.4", 19 | "depth": 0, 20 | "source": "registry", 21 | "dependencies": { 22 | "com.unity.test-framework": "1.1.1" 23 | }, 24 | "url": "https://packages.unity.com" 25 | }, 26 | "com.unity.ide.vscode": { 27 | "version": "1.2.1", 28 | "depth": 0, 29 | "source": "registry", 30 | "dependencies": {}, 31 | "url": "https://packages.unity.com" 32 | }, 33 | "com.unity.test-framework": { 34 | "version": "1.1.16", 35 | "depth": 0, 36 | "source": "registry", 37 | "dependencies": { 38 | "com.unity.ext.nunit": "1.0.0", 39 | "com.unity.modules.imgui": "1.0.0", 40 | "com.unity.modules.jsonserialize": "1.0.0" 41 | }, 42 | "url": "https://packages.unity.com" 43 | }, 44 | "com.unity.textmeshpro": { 45 | "version": "2.1.1", 46 | "depth": 0, 47 | "source": "registry", 48 | "dependencies": { 49 | "com.unity.ugui": "1.0.0" 50 | }, 51 | "url": "https://packages.unity.com" 52 | }, 53 | "com.unity.timeline": { 54 | "version": "1.2.16", 55 | "depth": 0, 56 | "source": "registry", 57 | "dependencies": {}, 58 | "url": "https://packages.unity.com" 59 | }, 60 | "com.unity.ugui": { 61 | "version": "1.0.0", 62 | "depth": 0, 63 | "source": "builtin", 64 | "dependencies": { 65 | "com.unity.modules.ui": "1.0.0", 66 | "com.unity.modules.imgui": "1.0.0" 67 | } 68 | }, 69 | "com.unity.modules.ai": { 70 | "version": "1.0.0", 71 | "depth": 0, 72 | "source": "builtin", 73 | "dependencies": {} 74 | }, 75 | "com.unity.modules.androidjni": { 76 | "version": "1.0.0", 77 | "depth": 0, 78 | "source": "builtin", 79 | "dependencies": {} 80 | }, 81 | "com.unity.modules.animation": { 82 | "version": "1.0.0", 83 | "depth": 0, 84 | "source": "builtin", 85 | "dependencies": {} 86 | }, 87 | "com.unity.modules.assetbundle": { 88 | "version": "1.0.0", 89 | "depth": 0, 90 | "source": "builtin", 91 | "dependencies": {} 92 | }, 93 | "com.unity.modules.audio": { 94 | "version": "1.0.0", 95 | "depth": 0, 96 | "source": "builtin", 97 | "dependencies": {} 98 | }, 99 | "com.unity.modules.cloth": { 100 | "version": "1.0.0", 101 | "depth": 0, 102 | "source": "builtin", 103 | "dependencies": { 104 | "com.unity.modules.physics": "1.0.0" 105 | } 106 | }, 107 | "com.unity.modules.director": { 108 | "version": "1.0.0", 109 | "depth": 0, 110 | "source": "builtin", 111 | "dependencies": { 112 | "com.unity.modules.audio": "1.0.0", 113 | "com.unity.modules.animation": "1.0.0" 114 | } 115 | }, 116 | "com.unity.modules.imageconversion": { 117 | "version": "1.0.0", 118 | "depth": 0, 119 | "source": "builtin", 120 | "dependencies": {} 121 | }, 122 | "com.unity.modules.imgui": { 123 | "version": "1.0.0", 124 | "depth": 0, 125 | "source": "builtin", 126 | "dependencies": {} 127 | }, 128 | "com.unity.modules.jsonserialize": { 129 | "version": "1.0.0", 130 | "depth": 0, 131 | "source": "builtin", 132 | "dependencies": {} 133 | }, 134 | "com.unity.modules.particlesystem": { 135 | "version": "1.0.0", 136 | "depth": 0, 137 | "source": "builtin", 138 | "dependencies": {} 139 | }, 140 | "com.unity.modules.physics": { 141 | "version": "1.0.0", 142 | "depth": 0, 143 | "source": "builtin", 144 | "dependencies": {} 145 | }, 146 | "com.unity.modules.physics2d": { 147 | "version": "1.0.0", 148 | "depth": 0, 149 | "source": "builtin", 150 | "dependencies": {} 151 | }, 152 | "com.unity.modules.screencapture": { 153 | "version": "1.0.0", 154 | "depth": 0, 155 | "source": "builtin", 156 | "dependencies": { 157 | "com.unity.modules.imageconversion": "1.0.0" 158 | } 159 | }, 160 | "com.unity.modules.subsystems": { 161 | "version": "1.0.0", 162 | "depth": 1, 163 | "source": "builtin", 164 | "dependencies": { 165 | "com.unity.modules.jsonserialize": "1.0.0" 166 | } 167 | }, 168 | "com.unity.modules.terrain": { 169 | "version": "1.0.0", 170 | "depth": 0, 171 | "source": "builtin", 172 | "dependencies": {} 173 | }, 174 | "com.unity.modules.terrainphysics": { 175 | "version": "1.0.0", 176 | "depth": 0, 177 | "source": "builtin", 178 | "dependencies": { 179 | "com.unity.modules.physics": "1.0.0", 180 | "com.unity.modules.terrain": "1.0.0" 181 | } 182 | }, 183 | "com.unity.modules.tilemap": { 184 | "version": "1.0.0", 185 | "depth": 0, 186 | "source": "builtin", 187 | "dependencies": { 188 | "com.unity.modules.physics2d": "1.0.0" 189 | } 190 | }, 191 | "com.unity.modules.ui": { 192 | "version": "1.0.0", 193 | "depth": 0, 194 | "source": "builtin", 195 | "dependencies": {} 196 | }, 197 | "com.unity.modules.uielements": { 198 | "version": "1.0.0", 199 | "depth": 0, 200 | "source": "builtin", 201 | "dependencies": { 202 | "com.unity.modules.imgui": "1.0.0", 203 | "com.unity.modules.jsonserialize": "1.0.0" 204 | } 205 | }, 206 | "com.unity.modules.umbra": { 207 | "version": "1.0.0", 208 | "depth": 0, 209 | "source": "builtin", 210 | "dependencies": {} 211 | }, 212 | "com.unity.modules.unityanalytics": { 213 | "version": "1.0.0", 214 | "depth": 0, 215 | "source": "builtin", 216 | "dependencies": { 217 | "com.unity.modules.unitywebrequest": "1.0.0", 218 | "com.unity.modules.jsonserialize": "1.0.0" 219 | } 220 | }, 221 | "com.unity.modules.unitywebrequest": { 222 | "version": "1.0.0", 223 | "depth": 0, 224 | "source": "builtin", 225 | "dependencies": {} 226 | }, 227 | "com.unity.modules.unitywebrequestassetbundle": { 228 | "version": "1.0.0", 229 | "depth": 0, 230 | "source": "builtin", 231 | "dependencies": { 232 | "com.unity.modules.assetbundle": "1.0.0", 233 | "com.unity.modules.unitywebrequest": "1.0.0" 234 | } 235 | }, 236 | "com.unity.modules.unitywebrequestaudio": { 237 | "version": "1.0.0", 238 | "depth": 0, 239 | "source": "builtin", 240 | "dependencies": { 241 | "com.unity.modules.unitywebrequest": "1.0.0", 242 | "com.unity.modules.audio": "1.0.0" 243 | } 244 | }, 245 | "com.unity.modules.unitywebrequesttexture": { 246 | "version": "1.0.0", 247 | "depth": 0, 248 | "source": "builtin", 249 | "dependencies": { 250 | "com.unity.modules.unitywebrequest": "1.0.0", 251 | "com.unity.modules.imageconversion": "1.0.0" 252 | } 253 | }, 254 | "com.unity.modules.unitywebrequestwww": { 255 | "version": "1.0.0", 256 | "depth": 0, 257 | "source": "builtin", 258 | "dependencies": { 259 | "com.unity.modules.unitywebrequest": "1.0.0", 260 | "com.unity.modules.unitywebrequestassetbundle": "1.0.0", 261 | "com.unity.modules.unitywebrequestaudio": "1.0.0", 262 | "com.unity.modules.audio": "1.0.0", 263 | "com.unity.modules.assetbundle": "1.0.0", 264 | "com.unity.modules.imageconversion": "1.0.0" 265 | } 266 | }, 267 | "com.unity.modules.vehicles": { 268 | "version": "1.0.0", 269 | "depth": 0, 270 | "source": "builtin", 271 | "dependencies": { 272 | "com.unity.modules.physics": "1.0.0" 273 | } 274 | }, 275 | "com.unity.modules.video": { 276 | "version": "1.0.0", 277 | "depth": 0, 278 | "source": "builtin", 279 | "dependencies": { 280 | "com.unity.modules.audio": "1.0.0", 281 | "com.unity.modules.ui": "1.0.0", 282 | "com.unity.modules.unitywebrequest": "1.0.0" 283 | } 284 | }, 285 | "com.unity.modules.vr": { 286 | "version": "1.0.0", 287 | "depth": 0, 288 | "source": "builtin", 289 | "dependencies": { 290 | "com.unity.modules.jsonserialize": "1.0.0", 291 | "com.unity.modules.physics": "1.0.0", 292 | "com.unity.modules.xr": "1.0.0" 293 | } 294 | }, 295 | "com.unity.modules.wind": { 296 | "version": "1.0.0", 297 | "depth": 0, 298 | "source": "builtin", 299 | "dependencies": {} 300 | }, 301 | "com.unity.modules.xr": { 302 | "version": "1.0.0", 303 | "depth": 0, 304 | "source": "builtin", 305 | "dependencies": { 306 | "com.unity.modules.physics": "1.0.0", 307 | "com.unity.modules.jsonserialize": "1.0.0", 308 | "com.unity.modules.subsystems": "1.0.0" 309 | } 310 | } 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /ProjectSettings/AudioManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!11 &1 4 | AudioManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Volume: 1 8 | Rolloff Scale: 1 9 | Doppler Factor: 1 10 | Default Speaker Mode: 2 11 | m_SampleRate: 0 12 | m_DSPBufferSize: 1024 13 | m_VirtualVoiceCount: 512 14 | m_RealVoiceCount: 32 15 | m_SpatializerPlugin: 16 | m_AmbisonicDecoderPlugin: 17 | m_DisableAudio: 0 18 | m_VirtualizeEffects: 1 19 | m_RequestedDSPBufferSize: 1024 20 | -------------------------------------------------------------------------------- /ProjectSettings/ClusterInputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!236 &1 4 | ClusterInputManager: 5 | m_ObjectHideFlags: 0 6 | m_Inputs: [] 7 | -------------------------------------------------------------------------------- /ProjectSettings/DynamicsManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!55 &1 4 | PhysicsManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 11 7 | m_Gravity: {x: 0, y: -9.81, z: 0} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_BounceThreshold: 2 10 | m_SleepThreshold: 0.005 11 | m_DefaultContactOffset: 0.01 12 | m_DefaultSolverIterations: 6 13 | m_DefaultSolverVelocityIterations: 1 14 | m_QueriesHitBackfaces: 0 15 | m_QueriesHitTriggers: 1 16 | m_EnableAdaptiveForce: 0 17 | m_ClothInterCollisionDistance: 0 18 | m_ClothInterCollisionStiffness: 0 19 | m_ContactsGeneration: 1 20 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 21 | m_AutoSimulation: 1 22 | m_AutoSyncTransforms: 0 23 | m_ReuseCollisionCallbacks: 1 24 | m_ClothInterCollisionSettingsToggle: 0 25 | m_ContactPairsMode: 0 26 | m_BroadphaseType: 0 27 | m_WorldBounds: 28 | m_Center: {x: 0, y: 0, z: 0} 29 | m_Extent: {x: 250, y: 250, z: 250} 30 | m_WorldSubdivisions: 8 31 | m_FrictionType: 0 32 | m_EnableEnhancedDeterminism: 0 33 | m_EnableUnifiedHeightmaps: 1 34 | m_DefaultMaxAngluarSpeed: 7 35 | -------------------------------------------------------------------------------- /ProjectSettings/EditorBuildSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1045 &1 4 | EditorBuildSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Scenes: [] 8 | m_configObjects: {} 9 | -------------------------------------------------------------------------------- /ProjectSettings/EditorSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!159 &1 4 | EditorSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 9 7 | m_ExternalVersionControlSupport: Visible Meta Files 8 | m_SerializationMode: 2 9 | m_LineEndingsForNewScripts: 0 10 | m_DefaultBehaviorMode: 0 11 | m_PrefabRegularEnvironment: {fileID: 0} 12 | m_PrefabUIEnvironment: {fileID: 0} 13 | m_SpritePackerMode: 0 14 | m_SpritePackerPaddingPower: 1 15 | m_EtcTextureCompressorBehavior: 1 16 | m_EtcTextureFastCompressor: 1 17 | m_EtcTextureNormalCompressor: 2 18 | m_EtcTextureBestCompressor: 4 19 | m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref 20 | m_ProjectGenerationRootNamespace: 21 | m_CollabEditorSettings: 22 | inProgressEnabled: 1 23 | m_EnableTextureStreamingInEditMode: 1 24 | m_EnableTextureStreamingInPlayMode: 1 25 | m_AsyncShaderCompilation: 1 26 | m_EnterPlayModeOptionsEnabled: 0 27 | m_EnterPlayModeOptions: 3 28 | m_ShowLightmapResolutionOverlay: 1 29 | m_UseLegacyProbeSampleCount: 0 30 | m_AssetPipelineMode: 1 31 | m_CacheServerMode: 0 32 | m_CacheServerEndpoint: 33 | m_CacheServerNamespacePrefix: default 34 | m_CacheServerEnableDownload: 1 35 | m_CacheServerEnableUpload: 1 36 | -------------------------------------------------------------------------------- /ProjectSettings/GraphicsSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!30 &1 4 | GraphicsSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 13 7 | m_Deferred: 8 | m_Mode: 1 9 | m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} 10 | m_DeferredReflections: 11 | m_Mode: 1 12 | m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} 13 | m_ScreenSpaceShadows: 14 | m_Mode: 1 15 | m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} 16 | m_LegacyDeferred: 17 | m_Mode: 1 18 | m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} 19 | m_DepthNormals: 20 | m_Mode: 1 21 | m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} 22 | m_MotionVectors: 23 | m_Mode: 1 24 | m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} 25 | m_LightHalo: 26 | m_Mode: 1 27 | m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} 28 | m_LensFlare: 29 | m_Mode: 1 30 | m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} 31 | m_AlwaysIncludedShaders: 32 | - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} 33 | - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} 34 | - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} 35 | - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} 36 | - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} 37 | - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} 38 | - {fileID: 16000, guid: 0000000000000000f000000000000000, type: 0} 39 | - {fileID: 16001, guid: 0000000000000000f000000000000000, type: 0} 40 | - {fileID: 17000, guid: 0000000000000000f000000000000000, type: 0} 41 | m_PreloadedShaders: [] 42 | m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, 43 | type: 0} 44 | m_CustomRenderPipeline: {fileID: 0} 45 | m_TransparencySortMode: 0 46 | m_TransparencySortAxis: {x: 0, y: 0, z: 1} 47 | m_DefaultRenderingPath: 1 48 | m_DefaultMobileRenderingPath: 1 49 | m_TierSettings: [] 50 | m_LightmapStripping: 0 51 | m_FogStripping: 0 52 | m_InstancingStripping: 0 53 | m_LightmapKeepPlain: 1 54 | m_LightmapKeepDirCombined: 1 55 | m_LightmapKeepDynamicPlain: 1 56 | m_LightmapKeepDynamicDirCombined: 1 57 | m_LightmapKeepShadowMask: 1 58 | m_LightmapKeepSubtractive: 1 59 | m_FogKeepLinear: 1 60 | m_FogKeepExp: 1 61 | m_FogKeepExp2: 1 62 | m_AlbedoSwatchInfos: [] 63 | m_LightsUseLinearIntensity: 0 64 | m_LightsUseColorTemperature: 0 65 | m_LogWhenShaderIsCompiled: 0 66 | m_AllowEnlightenSupportForUpgradedProject: 0 67 | -------------------------------------------------------------------------------- /ProjectSettings/InputManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!13 &1 4 | InputManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_Axes: 8 | - serializedVersion: 3 9 | m_Name: Horizontal 10 | descriptiveName: 11 | descriptiveNegativeName: 12 | negativeButton: left 13 | positiveButton: right 14 | altNegativeButton: a 15 | altPositiveButton: d 16 | gravity: 3 17 | dead: 0.001 18 | sensitivity: 3 19 | snap: 1 20 | invert: 0 21 | type: 0 22 | axis: 0 23 | joyNum: 0 24 | - serializedVersion: 3 25 | m_Name: Vertical 26 | descriptiveName: 27 | descriptiveNegativeName: 28 | negativeButton: down 29 | positiveButton: up 30 | altNegativeButton: s 31 | altPositiveButton: w 32 | gravity: 3 33 | dead: 0.001 34 | sensitivity: 3 35 | snap: 1 36 | invert: 0 37 | type: 0 38 | axis: 0 39 | joyNum: 0 40 | - serializedVersion: 3 41 | m_Name: Fire1 42 | descriptiveName: 43 | descriptiveNegativeName: 44 | negativeButton: 45 | positiveButton: left ctrl 46 | altNegativeButton: 47 | altPositiveButton: mouse 0 48 | gravity: 1000 49 | dead: 0.001 50 | sensitivity: 1000 51 | snap: 0 52 | invert: 0 53 | type: 0 54 | axis: 0 55 | joyNum: 0 56 | - serializedVersion: 3 57 | m_Name: Fire2 58 | descriptiveName: 59 | descriptiveNegativeName: 60 | negativeButton: 61 | positiveButton: left alt 62 | altNegativeButton: 63 | altPositiveButton: mouse 1 64 | gravity: 1000 65 | dead: 0.001 66 | sensitivity: 1000 67 | snap: 0 68 | invert: 0 69 | type: 0 70 | axis: 0 71 | joyNum: 0 72 | - serializedVersion: 3 73 | m_Name: Fire3 74 | descriptiveName: 75 | descriptiveNegativeName: 76 | negativeButton: 77 | positiveButton: left shift 78 | altNegativeButton: 79 | altPositiveButton: mouse 2 80 | gravity: 1000 81 | dead: 0.001 82 | sensitivity: 1000 83 | snap: 0 84 | invert: 0 85 | type: 0 86 | axis: 0 87 | joyNum: 0 88 | - serializedVersion: 3 89 | m_Name: Jump 90 | descriptiveName: 91 | descriptiveNegativeName: 92 | negativeButton: 93 | positiveButton: space 94 | altNegativeButton: 95 | altPositiveButton: 96 | gravity: 1000 97 | dead: 0.001 98 | sensitivity: 1000 99 | snap: 0 100 | invert: 0 101 | type: 0 102 | axis: 0 103 | joyNum: 0 104 | - serializedVersion: 3 105 | m_Name: Mouse X 106 | descriptiveName: 107 | descriptiveNegativeName: 108 | negativeButton: 109 | positiveButton: 110 | altNegativeButton: 111 | altPositiveButton: 112 | gravity: 0 113 | dead: 0 114 | sensitivity: 0.1 115 | snap: 0 116 | invert: 0 117 | type: 1 118 | axis: 0 119 | joyNum: 0 120 | - serializedVersion: 3 121 | m_Name: Mouse Y 122 | descriptiveName: 123 | descriptiveNegativeName: 124 | negativeButton: 125 | positiveButton: 126 | altNegativeButton: 127 | altPositiveButton: 128 | gravity: 0 129 | dead: 0 130 | sensitivity: 0.1 131 | snap: 0 132 | invert: 0 133 | type: 1 134 | axis: 1 135 | joyNum: 0 136 | - serializedVersion: 3 137 | m_Name: Mouse ScrollWheel 138 | descriptiveName: 139 | descriptiveNegativeName: 140 | negativeButton: 141 | positiveButton: 142 | altNegativeButton: 143 | altPositiveButton: 144 | gravity: 0 145 | dead: 0 146 | sensitivity: 0.1 147 | snap: 0 148 | invert: 0 149 | type: 1 150 | axis: 2 151 | joyNum: 0 152 | - serializedVersion: 3 153 | m_Name: Horizontal 154 | descriptiveName: 155 | descriptiveNegativeName: 156 | negativeButton: 157 | positiveButton: 158 | altNegativeButton: 159 | altPositiveButton: 160 | gravity: 0 161 | dead: 0.19 162 | sensitivity: 1 163 | snap: 0 164 | invert: 0 165 | type: 2 166 | axis: 0 167 | joyNum: 0 168 | - serializedVersion: 3 169 | m_Name: Vertical 170 | descriptiveName: 171 | descriptiveNegativeName: 172 | negativeButton: 173 | positiveButton: 174 | altNegativeButton: 175 | altPositiveButton: 176 | gravity: 0 177 | dead: 0.19 178 | sensitivity: 1 179 | snap: 0 180 | invert: 1 181 | type: 2 182 | axis: 1 183 | joyNum: 0 184 | - serializedVersion: 3 185 | m_Name: Fire1 186 | descriptiveName: 187 | descriptiveNegativeName: 188 | negativeButton: 189 | positiveButton: joystick button 0 190 | altNegativeButton: 191 | altPositiveButton: 192 | gravity: 1000 193 | dead: 0.001 194 | sensitivity: 1000 195 | snap: 0 196 | invert: 0 197 | type: 0 198 | axis: 0 199 | joyNum: 0 200 | - serializedVersion: 3 201 | m_Name: Fire2 202 | descriptiveName: 203 | descriptiveNegativeName: 204 | negativeButton: 205 | positiveButton: joystick button 1 206 | altNegativeButton: 207 | altPositiveButton: 208 | gravity: 1000 209 | dead: 0.001 210 | sensitivity: 1000 211 | snap: 0 212 | invert: 0 213 | type: 0 214 | axis: 0 215 | joyNum: 0 216 | - serializedVersion: 3 217 | m_Name: Fire3 218 | descriptiveName: 219 | descriptiveNegativeName: 220 | negativeButton: 221 | positiveButton: joystick button 2 222 | altNegativeButton: 223 | altPositiveButton: 224 | gravity: 1000 225 | dead: 0.001 226 | sensitivity: 1000 227 | snap: 0 228 | invert: 0 229 | type: 0 230 | axis: 0 231 | joyNum: 0 232 | - serializedVersion: 3 233 | m_Name: Jump 234 | descriptiveName: 235 | descriptiveNegativeName: 236 | negativeButton: 237 | positiveButton: joystick button 3 238 | altNegativeButton: 239 | altPositiveButton: 240 | gravity: 1000 241 | dead: 0.001 242 | sensitivity: 1000 243 | snap: 0 244 | invert: 0 245 | type: 0 246 | axis: 0 247 | joyNum: 0 248 | - serializedVersion: 3 249 | m_Name: Submit 250 | descriptiveName: 251 | descriptiveNegativeName: 252 | negativeButton: 253 | positiveButton: return 254 | altNegativeButton: 255 | altPositiveButton: joystick button 0 256 | gravity: 1000 257 | dead: 0.001 258 | sensitivity: 1000 259 | snap: 0 260 | invert: 0 261 | type: 0 262 | axis: 0 263 | joyNum: 0 264 | - serializedVersion: 3 265 | m_Name: Submit 266 | descriptiveName: 267 | descriptiveNegativeName: 268 | negativeButton: 269 | positiveButton: enter 270 | altNegativeButton: 271 | altPositiveButton: space 272 | gravity: 1000 273 | dead: 0.001 274 | sensitivity: 1000 275 | snap: 0 276 | invert: 0 277 | type: 0 278 | axis: 0 279 | joyNum: 0 280 | - serializedVersion: 3 281 | m_Name: Cancel 282 | descriptiveName: 283 | descriptiveNegativeName: 284 | negativeButton: 285 | positiveButton: escape 286 | altNegativeButton: 287 | altPositiveButton: joystick button 1 288 | gravity: 1000 289 | dead: 0.001 290 | sensitivity: 1000 291 | snap: 0 292 | invert: 0 293 | type: 0 294 | axis: 0 295 | joyNum: 0 296 | -------------------------------------------------------------------------------- /ProjectSettings/NavMeshAreas.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!126 &1 4 | NavMeshProjectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | areas: 8 | - name: Walkable 9 | cost: 1 10 | - name: Not Walkable 11 | cost: 1 12 | - name: Jump 13 | cost: 2 14 | - name: 15 | cost: 1 16 | - name: 17 | cost: 1 18 | - name: 19 | cost: 1 20 | - name: 21 | cost: 1 22 | - name: 23 | cost: 1 24 | - name: 25 | cost: 1 26 | - name: 27 | cost: 1 28 | - name: 29 | cost: 1 30 | - name: 31 | cost: 1 32 | - name: 33 | cost: 1 34 | - name: 35 | cost: 1 36 | - name: 37 | cost: 1 38 | - name: 39 | cost: 1 40 | - name: 41 | cost: 1 42 | - name: 43 | cost: 1 44 | - name: 45 | cost: 1 46 | - name: 47 | cost: 1 48 | - name: 49 | cost: 1 50 | - name: 51 | cost: 1 52 | - name: 53 | cost: 1 54 | - name: 55 | cost: 1 56 | - name: 57 | cost: 1 58 | - name: 59 | cost: 1 60 | - name: 61 | cost: 1 62 | - name: 63 | cost: 1 64 | - name: 65 | cost: 1 66 | - name: 67 | cost: 1 68 | - name: 69 | cost: 1 70 | - name: 71 | cost: 1 72 | m_LastAgentTypeID: -887442657 73 | m_Settings: 74 | - serializedVersion: 2 75 | agentTypeID: 0 76 | agentRadius: 0.5 77 | agentHeight: 2 78 | agentSlope: 45 79 | agentClimb: 0.75 80 | ledgeDropHeight: 0 81 | maxJumpAcrossDistance: 0 82 | minRegionArea: 2 83 | manualCellSize: 0 84 | cellSize: 0.16666667 85 | manualTileSize: 0 86 | tileSize: 256 87 | accuratePlacement: 0 88 | debug: 89 | m_Flags: 0 90 | m_SettingNames: 91 | - Humanoid 92 | -------------------------------------------------------------------------------- /ProjectSettings/Physics2DSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!19 &1 4 | Physics2DSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 4 7 | m_Gravity: {x: 0, y: -9.81} 8 | m_DefaultMaterial: {fileID: 0} 9 | m_VelocityIterations: 8 10 | m_PositionIterations: 3 11 | m_VelocityThreshold: 1 12 | m_MaxLinearCorrection: 0.2 13 | m_MaxAngularCorrection: 8 14 | m_MaxTranslationSpeed: 100 15 | m_MaxRotationSpeed: 360 16 | m_BaumgarteScale: 0.2 17 | m_BaumgarteTimeOfImpactScale: 0.75 18 | m_TimeToSleep: 0.5 19 | m_LinearSleepTolerance: 0.01 20 | m_AngularSleepTolerance: 2 21 | m_DefaultContactOffset: 0.01 22 | m_JobOptions: 23 | serializedVersion: 2 24 | useMultithreading: 0 25 | useConsistencySorting: 0 26 | m_InterpolationPosesPerJob: 100 27 | m_NewContactsPerJob: 30 28 | m_CollideContactsPerJob: 100 29 | m_ClearFlagsPerJob: 200 30 | m_ClearBodyForcesPerJob: 200 31 | m_SyncDiscreteFixturesPerJob: 50 32 | m_SyncContinuousFixturesPerJob: 50 33 | m_FindNearestContactsPerJob: 100 34 | m_UpdateTriggerContactsPerJob: 100 35 | m_IslandSolverCostThreshold: 100 36 | m_IslandSolverBodyCostScale: 1 37 | m_IslandSolverContactCostScale: 10 38 | m_IslandSolverJointCostScale: 10 39 | m_IslandSolverBodiesPerJob: 50 40 | m_IslandSolverContactsPerJob: 50 41 | m_AutoSimulation: 1 42 | m_QueriesHitTriggers: 1 43 | m_QueriesStartInColliders: 1 44 | m_CallbacksOnDisable: 1 45 | m_ReuseCollisionCallbacks: 1 46 | m_AutoSyncTransforms: 0 47 | m_AlwaysShowColliders: 0 48 | m_ShowColliderSleep: 1 49 | m_ShowColliderContacts: 0 50 | m_ShowColliderAABB: 0 51 | m_ContactArrowScale: 0.2 52 | m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} 53 | m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} 54 | m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} 55 | m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} 56 | m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 57 | -------------------------------------------------------------------------------- /ProjectSettings/PresetManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1386491679 &1 4 | PresetManager: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_DefaultPresets: {} 8 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!129 &1 4 | PlayerSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 20 7 | productGUID: bef65637e10bc26499e0ed8c5df7c8f1 8 | AndroidProfiler: 0 9 | AndroidFilterTouchesWhenObscured: 0 10 | AndroidEnableSustainedPerformanceMode: 0 11 | defaultScreenOrientation: 4 12 | targetDevice: 2 13 | useOnDemandResources: 0 14 | accelerometerFrequency: 60 15 | companyName: DefaultCompany 16 | productName: Unity-Visibility-Graph-Path-Planning-Simulation 17 | defaultCursor: {fileID: 0} 18 | cursorHotspot: {x: 0, y: 0} 19 | m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} 20 | m_ShowUnitySplashScreen: 1 21 | m_ShowUnitySplashLogo: 1 22 | m_SplashScreenOverlayOpacity: 1 23 | m_SplashScreenAnimation: 1 24 | m_SplashScreenLogoStyle: 1 25 | m_SplashScreenDrawMode: 0 26 | m_SplashScreenBackgroundAnimationZoom: 1 27 | m_SplashScreenLogoAnimationZoom: 1 28 | m_SplashScreenBackgroundLandscapeAspect: 1 29 | m_SplashScreenBackgroundPortraitAspect: 1 30 | m_SplashScreenBackgroundLandscapeUvs: 31 | serializedVersion: 2 32 | x: 0 33 | y: 0 34 | width: 1 35 | height: 1 36 | m_SplashScreenBackgroundPortraitUvs: 37 | serializedVersion: 2 38 | x: 0 39 | y: 0 40 | width: 1 41 | height: 1 42 | m_SplashScreenLogos: [] 43 | m_VirtualRealitySplashScreen: {fileID: 0} 44 | m_HolographicTrackingLossScreen: {fileID: 0} 45 | defaultScreenWidth: 1024 46 | defaultScreenHeight: 768 47 | defaultScreenWidthWeb: 960 48 | defaultScreenHeightWeb: 600 49 | m_StereoRenderingPath: 0 50 | m_ActiveColorSpace: 0 51 | m_MTRendering: 1 52 | m_StackTraceTypes: 010000000100000001000000010000000100000001000000 53 | iosShowActivityIndicatorOnLoading: -1 54 | androidShowActivityIndicatorOnLoading: -1 55 | iosUseCustomAppBackgroundBehavior: 0 56 | iosAllowHTTPDownload: 1 57 | allowedAutorotateToPortrait: 1 58 | allowedAutorotateToPortraitUpsideDown: 1 59 | allowedAutorotateToLandscapeRight: 1 60 | allowedAutorotateToLandscapeLeft: 1 61 | useOSAutorotation: 1 62 | use32BitDisplayBuffer: 1 63 | preserveFramebufferAlpha: 0 64 | disableDepthAndStencilBuffers: 0 65 | androidStartInFullscreen: 1 66 | androidRenderOutsideSafeArea: 1 67 | androidUseSwappy: 0 68 | androidBlitType: 0 69 | defaultIsNativeResolution: 1 70 | macRetinaSupport: 1 71 | runInBackground: 1 72 | captureSingleScreen: 0 73 | muteOtherAudioSources: 0 74 | Prepare IOS For Recording: 0 75 | Force IOS Speakers When Recording: 0 76 | deferSystemGesturesMode: 0 77 | hideHomeButton: 0 78 | submitAnalytics: 1 79 | usePlayerLog: 1 80 | bakeCollisionMeshes: 0 81 | forceSingleInstance: 0 82 | useFlipModelSwapchain: 1 83 | resizableWindow: 0 84 | useMacAppStoreValidation: 0 85 | macAppStoreCategory: public.app-category.games 86 | gpuSkinning: 1 87 | xboxPIXTextureCapture: 0 88 | xboxEnableAvatar: 0 89 | xboxEnableKinect: 0 90 | xboxEnableKinectAutoTracking: 0 91 | xboxEnableFitness: 0 92 | visibleInBackground: 1 93 | allowFullscreenSwitch: 1 94 | fullscreenMode: 1 95 | xboxSpeechDB: 0 96 | xboxEnableHeadOrientation: 0 97 | xboxEnableGuest: 0 98 | xboxEnablePIXSampling: 0 99 | metalFramebufferOnly: 0 100 | xboxOneResolution: 0 101 | xboxOneSResolution: 0 102 | xboxOneXResolution: 3 103 | xboxOneMonoLoggingLevel: 0 104 | xboxOneLoggingLevel: 1 105 | xboxOneDisableEsram: 0 106 | xboxOneEnableTypeOptimization: 0 107 | xboxOnePresentImmediateThreshold: 0 108 | switchQueueCommandMemory: 0 109 | switchQueueControlMemory: 16384 110 | switchQueueComputeMemory: 262144 111 | switchNVNShaderPoolsGranularity: 33554432 112 | switchNVNDefaultPoolsGranularity: 16777216 113 | switchNVNOtherPoolsGranularity: 16777216 114 | switchNVNMaxPublicTextureIDCount: 0 115 | switchNVNMaxPublicSamplerIDCount: 0 116 | stadiaPresentMode: 0 117 | stadiaTargetFramerate: 0 118 | vulkanNumSwapchainBuffers: 3 119 | vulkanEnableSetSRGBWrite: 0 120 | vulkanEnableLateAcquireNextImage: 0 121 | m_SupportedAspectRatios: 122 | 4:3: 1 123 | 5:4: 1 124 | 16:10: 1 125 | 16:9: 1 126 | Others: 1 127 | bundleVersion: 0.1 128 | preloadedAssets: [] 129 | metroInputSource: 0 130 | wsaTransparentSwapchain: 0 131 | m_HolographicPauseOnTrackingLoss: 1 132 | xboxOneDisableKinectGpuReservation: 1 133 | xboxOneEnable7thCore: 1 134 | vrSettings: 135 | cardboard: 136 | depthFormat: 0 137 | enableTransitionView: 0 138 | daydream: 139 | depthFormat: 0 140 | useSustainedPerformanceMode: 0 141 | enableVideoLayer: 0 142 | useProtectedVideoMemory: 0 143 | minimumSupportedHeadTracking: 0 144 | maximumSupportedHeadTracking: 1 145 | hololens: 146 | depthFormat: 1 147 | depthBufferSharingEnabled: 1 148 | lumin: 149 | depthFormat: 0 150 | frameTiming: 2 151 | enableGLCache: 0 152 | glCacheMaxBlobSize: 524288 153 | glCacheMaxFileSize: 8388608 154 | oculus: 155 | sharedDepthBuffer: 1 156 | dashSupport: 1 157 | lowOverheadMode: 0 158 | protectedContext: 0 159 | v2Signing: 1 160 | enable360StereoCapture: 0 161 | isWsaHolographicRemotingEnabled: 0 162 | enableFrameTimingStats: 0 163 | useHDRDisplay: 0 164 | D3DHDRBitDepth: 0 165 | m_ColorGamuts: 00000000 166 | targetPixelDensity: 30 167 | resolutionScalingMode: 0 168 | androidSupportedAspectRatio: 1 169 | androidMaxAspectRatio: 2.1 170 | applicationIdentifier: {} 171 | buildNumber: {} 172 | AndroidBundleVersionCode: 1 173 | AndroidMinSdkVersion: 19 174 | AndroidTargetSdkVersion: 0 175 | AndroidPreferredInstallLocation: 1 176 | aotOptions: 177 | stripEngineCode: 1 178 | iPhoneStrippingLevel: 0 179 | iPhoneScriptCallOptimization: 0 180 | ForceInternetPermission: 0 181 | ForceSDCardPermission: 0 182 | CreateWallpaper: 0 183 | APKExpansionFiles: 0 184 | keepLoadedShadersAlive: 0 185 | StripUnusedMeshComponents: 1 186 | VertexChannelCompressionMask: 4054 187 | iPhoneSdkVersion: 988 188 | iOSTargetOSVersionString: 10.0 189 | tvOSSdkVersion: 0 190 | tvOSRequireExtendedGameController: 0 191 | tvOSTargetOSVersionString: 10.0 192 | uIPrerenderedIcon: 0 193 | uIRequiresPersistentWiFi: 0 194 | uIRequiresFullScreen: 1 195 | uIStatusBarHidden: 1 196 | uIExitOnSuspend: 0 197 | uIStatusBarStyle: 0 198 | appleTVSplashScreen: {fileID: 0} 199 | appleTVSplashScreen2x: {fileID: 0} 200 | tvOSSmallIconLayers: [] 201 | tvOSSmallIconLayers2x: [] 202 | tvOSLargeIconLayers: [] 203 | tvOSLargeIconLayers2x: [] 204 | tvOSTopShelfImageLayers: [] 205 | tvOSTopShelfImageLayers2x: [] 206 | tvOSTopShelfImageWideLayers: [] 207 | tvOSTopShelfImageWideLayers2x: [] 208 | iOSLaunchScreenType: 0 209 | iOSLaunchScreenPortrait: {fileID: 0} 210 | iOSLaunchScreenLandscape: {fileID: 0} 211 | iOSLaunchScreenBackgroundColor: 212 | serializedVersion: 2 213 | rgba: 0 214 | iOSLaunchScreenFillPct: 100 215 | iOSLaunchScreenSize: 100 216 | iOSLaunchScreenCustomXibPath: 217 | iOSLaunchScreeniPadType: 0 218 | iOSLaunchScreeniPadImage: {fileID: 0} 219 | iOSLaunchScreeniPadBackgroundColor: 220 | serializedVersion: 2 221 | rgba: 0 222 | iOSLaunchScreeniPadFillPct: 100 223 | iOSLaunchScreeniPadSize: 100 224 | iOSLaunchScreeniPadCustomXibPath: 225 | iOSUseLaunchScreenStoryboard: 0 226 | iOSLaunchScreenCustomStoryboardPath: 227 | iOSDeviceRequirements: [] 228 | iOSURLSchemes: [] 229 | iOSBackgroundModes: 0 230 | iOSMetalForceHardShadows: 0 231 | metalEditorSupport: 1 232 | metalAPIValidation: 1 233 | iOSRenderExtraFrameOnPause: 0 234 | appleDeveloperTeamID: 235 | iOSManualSigningProvisioningProfileID: 236 | tvOSManualSigningProvisioningProfileID: 237 | iOSManualSigningProvisioningProfileType: 0 238 | tvOSManualSigningProvisioningProfileType: 0 239 | appleEnableAutomaticSigning: 0 240 | iOSRequireARKit: 0 241 | iOSAutomaticallyDetectAndAddCapabilities: 1 242 | appleEnableProMotion: 0 243 | clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea 244 | templatePackageId: com.unity.template.3d@4.2.8 245 | templateDefaultScene: Assets/Scenes/SampleScene.unity 246 | AndroidTargetArchitectures: 1 247 | AndroidSplashScreenScale: 0 248 | androidSplashScreen: {fileID: 0} 249 | AndroidKeystoreName: 250 | AndroidKeyaliasName: 251 | AndroidBuildApkPerCpuArchitecture: 0 252 | AndroidTVCompatibility: 0 253 | AndroidIsGame: 1 254 | AndroidEnableTango: 0 255 | androidEnableBanner: 1 256 | androidUseLowAccuracyLocation: 0 257 | androidUseCustomKeystore: 0 258 | m_AndroidBanners: 259 | - width: 320 260 | height: 180 261 | banner: {fileID: 0} 262 | androidGamepadSupportLevel: 0 263 | AndroidValidateAppBundleSize: 1 264 | AndroidAppBundleSizeToValidate: 150 265 | m_BuildTargetIcons: [] 266 | m_BuildTargetPlatformIcons: [] 267 | m_BuildTargetBatching: 268 | - m_BuildTarget: Standalone 269 | m_StaticBatching: 1 270 | m_DynamicBatching: 0 271 | - m_BuildTarget: tvOS 272 | m_StaticBatching: 1 273 | m_DynamicBatching: 0 274 | - m_BuildTarget: Android 275 | m_StaticBatching: 1 276 | m_DynamicBatching: 0 277 | - m_BuildTarget: iPhone 278 | m_StaticBatching: 1 279 | m_DynamicBatching: 0 280 | - m_BuildTarget: WebGL 281 | m_StaticBatching: 0 282 | m_DynamicBatching: 0 283 | m_BuildTargetGraphicsJobs: 284 | - m_BuildTarget: MacStandaloneSupport 285 | m_GraphicsJobs: 0 286 | - m_BuildTarget: Switch 287 | m_GraphicsJobs: 1 288 | - m_BuildTarget: MetroSupport 289 | m_GraphicsJobs: 1 290 | - m_BuildTarget: AppleTVSupport 291 | m_GraphicsJobs: 0 292 | - m_BuildTarget: BJMSupport 293 | m_GraphicsJobs: 1 294 | - m_BuildTarget: LinuxStandaloneSupport 295 | m_GraphicsJobs: 1 296 | - m_BuildTarget: PS4Player 297 | m_GraphicsJobs: 1 298 | - m_BuildTarget: iOSSupport 299 | m_GraphicsJobs: 0 300 | - m_BuildTarget: WindowsStandaloneSupport 301 | m_GraphicsJobs: 1 302 | - m_BuildTarget: XboxOnePlayer 303 | m_GraphicsJobs: 1 304 | - m_BuildTarget: LuminSupport 305 | m_GraphicsJobs: 0 306 | - m_BuildTarget: AndroidPlayer 307 | m_GraphicsJobs: 0 308 | - m_BuildTarget: WebGLSupport 309 | m_GraphicsJobs: 0 310 | m_BuildTargetGraphicsJobMode: 311 | - m_BuildTarget: PS4Player 312 | m_GraphicsJobMode: 0 313 | - m_BuildTarget: XboxOnePlayer 314 | m_GraphicsJobMode: 0 315 | m_BuildTargetGraphicsAPIs: 316 | - m_BuildTarget: AndroidPlayer 317 | m_APIs: 150000000b000000 318 | m_Automatic: 0 319 | - m_BuildTarget: iOSSupport 320 | m_APIs: 10000000 321 | m_Automatic: 1 322 | - m_BuildTarget: AppleTVSupport 323 | m_APIs: 10000000 324 | m_Automatic: 0 325 | - m_BuildTarget: WebGLSupport 326 | m_APIs: 0b000000 327 | m_Automatic: 1 328 | m_BuildTargetVRSettings: 329 | - m_BuildTarget: Standalone 330 | m_Enabled: 0 331 | m_Devices: 332 | - Oculus 333 | - OpenVR 334 | openGLRequireES31: 0 335 | openGLRequireES31AEP: 0 336 | openGLRequireES32: 0 337 | m_TemplateCustomTags: {} 338 | mobileMTRendering: 339 | Android: 1 340 | iPhone: 1 341 | tvOS: 1 342 | m_BuildTargetGroupLightmapEncodingQuality: [] 343 | m_BuildTargetGroupLightmapSettings: [] 344 | playModeTestRunnerEnabled: 0 345 | runPlayModeTestAsEditModeTest: 0 346 | actionOnDotNetUnhandledException: 1 347 | enableInternalProfiler: 0 348 | logObjCUncaughtExceptions: 1 349 | enableCrashReportAPI: 0 350 | cameraUsageDescription: 351 | locationUsageDescription: 352 | microphoneUsageDescription: 353 | switchNetLibKey: 354 | switchSocketMemoryPoolSize: 6144 355 | switchSocketAllocatorPoolSize: 128 356 | switchSocketConcurrencyLimit: 14 357 | switchScreenResolutionBehavior: 2 358 | switchUseCPUProfiler: 0 359 | switchApplicationID: 0x01004b9000490000 360 | switchNSODependencies: 361 | switchTitleNames_0: 362 | switchTitleNames_1: 363 | switchTitleNames_2: 364 | switchTitleNames_3: 365 | switchTitleNames_4: 366 | switchTitleNames_5: 367 | switchTitleNames_6: 368 | switchTitleNames_7: 369 | switchTitleNames_8: 370 | switchTitleNames_9: 371 | switchTitleNames_10: 372 | switchTitleNames_11: 373 | switchTitleNames_12: 374 | switchTitleNames_13: 375 | switchTitleNames_14: 376 | switchPublisherNames_0: 377 | switchPublisherNames_1: 378 | switchPublisherNames_2: 379 | switchPublisherNames_3: 380 | switchPublisherNames_4: 381 | switchPublisherNames_5: 382 | switchPublisherNames_6: 383 | switchPublisherNames_7: 384 | switchPublisherNames_8: 385 | switchPublisherNames_9: 386 | switchPublisherNames_10: 387 | switchPublisherNames_11: 388 | switchPublisherNames_12: 389 | switchPublisherNames_13: 390 | switchPublisherNames_14: 391 | switchIcons_0: {fileID: 0} 392 | switchIcons_1: {fileID: 0} 393 | switchIcons_2: {fileID: 0} 394 | switchIcons_3: {fileID: 0} 395 | switchIcons_4: {fileID: 0} 396 | switchIcons_5: {fileID: 0} 397 | switchIcons_6: {fileID: 0} 398 | switchIcons_7: {fileID: 0} 399 | switchIcons_8: {fileID: 0} 400 | switchIcons_9: {fileID: 0} 401 | switchIcons_10: {fileID: 0} 402 | switchIcons_11: {fileID: 0} 403 | switchIcons_12: {fileID: 0} 404 | switchIcons_13: {fileID: 0} 405 | switchIcons_14: {fileID: 0} 406 | switchSmallIcons_0: {fileID: 0} 407 | switchSmallIcons_1: {fileID: 0} 408 | switchSmallIcons_2: {fileID: 0} 409 | switchSmallIcons_3: {fileID: 0} 410 | switchSmallIcons_4: {fileID: 0} 411 | switchSmallIcons_5: {fileID: 0} 412 | switchSmallIcons_6: {fileID: 0} 413 | switchSmallIcons_7: {fileID: 0} 414 | switchSmallIcons_8: {fileID: 0} 415 | switchSmallIcons_9: {fileID: 0} 416 | switchSmallIcons_10: {fileID: 0} 417 | switchSmallIcons_11: {fileID: 0} 418 | switchSmallIcons_12: {fileID: 0} 419 | switchSmallIcons_13: {fileID: 0} 420 | switchSmallIcons_14: {fileID: 0} 421 | switchManualHTML: 422 | switchAccessibleURLs: 423 | switchLegalInformation: 424 | switchMainThreadStackSize: 1048576 425 | switchPresenceGroupId: 426 | switchLogoHandling: 0 427 | switchReleaseVersion: 0 428 | switchDisplayVersion: 1.0.0 429 | switchStartupUserAccount: 0 430 | switchTouchScreenUsage: 0 431 | switchSupportedLanguagesMask: 0 432 | switchLogoType: 0 433 | switchApplicationErrorCodeCategory: 434 | switchUserAccountSaveDataSize: 0 435 | switchUserAccountSaveDataJournalSize: 0 436 | switchApplicationAttribute: 0 437 | switchCardSpecSize: -1 438 | switchCardSpecClock: -1 439 | switchRatingsMask: 0 440 | switchRatingsInt_0: 0 441 | switchRatingsInt_1: 0 442 | switchRatingsInt_2: 0 443 | switchRatingsInt_3: 0 444 | switchRatingsInt_4: 0 445 | switchRatingsInt_5: 0 446 | switchRatingsInt_6: 0 447 | switchRatingsInt_7: 0 448 | switchRatingsInt_8: 0 449 | switchRatingsInt_9: 0 450 | switchRatingsInt_10: 0 451 | switchRatingsInt_11: 0 452 | switchRatingsInt_12: 0 453 | switchLocalCommunicationIds_0: 454 | switchLocalCommunicationIds_1: 455 | switchLocalCommunicationIds_2: 456 | switchLocalCommunicationIds_3: 457 | switchLocalCommunicationIds_4: 458 | switchLocalCommunicationIds_5: 459 | switchLocalCommunicationIds_6: 460 | switchLocalCommunicationIds_7: 461 | switchParentalControl: 0 462 | switchAllowsScreenshot: 1 463 | switchAllowsVideoCapturing: 1 464 | switchAllowsRuntimeAddOnContentInstall: 0 465 | switchDataLossConfirmation: 0 466 | switchUserAccountLockEnabled: 0 467 | switchSystemResourceMemory: 16777216 468 | switchSupportedNpadStyles: 22 469 | switchNativeFsCacheSize: 32 470 | switchIsHoldTypeHorizontal: 0 471 | switchSupportedNpadCount: 8 472 | switchSocketConfigEnabled: 0 473 | switchTcpInitialSendBufferSize: 32 474 | switchTcpInitialReceiveBufferSize: 64 475 | switchTcpAutoSendBufferSizeMax: 256 476 | switchTcpAutoReceiveBufferSizeMax: 256 477 | switchUdpSendBufferSize: 9 478 | switchUdpReceiveBufferSize: 42 479 | switchSocketBufferEfficiency: 4 480 | switchSocketInitializeEnabled: 1 481 | switchNetworkInterfaceManagerInitializeEnabled: 1 482 | switchPlayerConnectionEnabled: 1 483 | ps4NPAgeRating: 12 484 | ps4NPTitleSecret: 485 | ps4NPTrophyPackPath: 486 | ps4ParentalLevel: 11 487 | ps4ContentID: ED1633-NPXX51362_00-0000000000000000 488 | ps4Category: 0 489 | ps4MasterVersion: 01.00 490 | ps4AppVersion: 01.00 491 | ps4AppType: 0 492 | ps4ParamSfxPath: 493 | ps4VideoOutPixelFormat: 0 494 | ps4VideoOutInitialWidth: 1920 495 | ps4VideoOutBaseModeInitialWidth: 1920 496 | ps4VideoOutReprojectionRate: 60 497 | ps4PronunciationXMLPath: 498 | ps4PronunciationSIGPath: 499 | ps4BackgroundImagePath: 500 | ps4StartupImagePath: 501 | ps4StartupImagesFolder: 502 | ps4IconImagesFolder: 503 | ps4SaveDataImagePath: 504 | ps4SdkOverride: 505 | ps4BGMPath: 506 | ps4ShareFilePath: 507 | ps4ShareOverlayImagePath: 508 | ps4PrivacyGuardImagePath: 509 | ps4ExtraSceSysFile: 510 | ps4NPtitleDatPath: 511 | ps4RemotePlayKeyAssignment: -1 512 | ps4RemotePlayKeyMappingDir: 513 | ps4PlayTogetherPlayerCount: 0 514 | ps4EnterButtonAssignment: 1 515 | ps4ApplicationParam1: 0 516 | ps4ApplicationParam2: 0 517 | ps4ApplicationParam3: 0 518 | ps4ApplicationParam4: 0 519 | ps4DownloadDataSize: 0 520 | ps4GarlicHeapSize: 2048 521 | ps4ProGarlicHeapSize: 2560 522 | playerPrefsMaxSize: 32768 523 | ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ 524 | ps4pnSessions: 1 525 | ps4pnPresence: 1 526 | ps4pnFriends: 1 527 | ps4pnGameCustomData: 1 528 | playerPrefsSupport: 0 529 | enableApplicationExit: 0 530 | resetTempFolder: 1 531 | restrictedAudioUsageRights: 0 532 | ps4UseResolutionFallback: 0 533 | ps4ReprojectionSupport: 0 534 | ps4UseAudio3dBackend: 0 535 | ps4UseLowGarlicFragmentationMode: 1 536 | ps4SocialScreenEnabled: 0 537 | ps4ScriptOptimizationLevel: 0 538 | ps4Audio3dVirtualSpeakerCount: 14 539 | ps4attribCpuUsage: 0 540 | ps4PatchPkgPath: 541 | ps4PatchLatestPkgPath: 542 | ps4PatchChangeinfoPath: 543 | ps4PatchDayOne: 0 544 | ps4attribUserManagement: 0 545 | ps4attribMoveSupport: 0 546 | ps4attrib3DSupport: 0 547 | ps4attribShareSupport: 0 548 | ps4attribExclusiveVR: 0 549 | ps4disableAutoHideSplash: 0 550 | ps4videoRecordingFeaturesUsed: 0 551 | ps4contentSearchFeaturesUsed: 0 552 | ps4CompatibilityPS5: 0 553 | ps4GPU800MHz: 1 554 | ps4attribEyeToEyeDistanceSettingVR: 0 555 | ps4IncludedModules: [] 556 | ps4attribVROutputEnabled: 0 557 | monoEnv: 558 | splashScreenBackgroundSourceLandscape: {fileID: 0} 559 | splashScreenBackgroundSourcePortrait: {fileID: 0} 560 | blurSplashScreenBackground: 1 561 | spritePackerPolicy: 562 | webGLMemorySize: 16 563 | webGLExceptionSupport: 1 564 | webGLNameFilesAsHashes: 0 565 | webGLDataCaching: 1 566 | webGLDebugSymbols: 0 567 | webGLEmscriptenArgs: 568 | webGLModulesDirectory: 569 | webGLTemplate: APPLICATION:Default 570 | webGLAnalyzeBuildSize: 0 571 | webGLUseEmbeddedResources: 0 572 | webGLCompressionFormat: 1 573 | webGLLinkerTarget: 1 574 | webGLThreadsSupport: 0 575 | webGLWasmStreaming: 0 576 | scriptingDefineSymbols: {} 577 | platformArchitecture: {} 578 | scriptingBackend: {} 579 | il2cppCompilerConfiguration: {} 580 | managedStrippingLevel: {} 581 | incrementalIl2cppBuild: {} 582 | allowUnsafeCode: 0 583 | additionalIl2CppArgs: 584 | scriptingRuntimeVersion: 1 585 | gcIncremental: 0 586 | gcWBarrierValidation: 0 587 | apiCompatibilityLevelPerPlatform: {} 588 | m_RenderingPath: 1 589 | m_MobileRenderingPath: 1 590 | metroPackageName: Template_3D 591 | metroPackageVersion: 592 | metroCertificatePath: 593 | metroCertificatePassword: 594 | metroCertificateSubject: 595 | metroCertificateIssuer: 596 | metroCertificateNotAfter: 0000000000000000 597 | metroApplicationDescription: Template_3D 598 | wsaImages: {} 599 | metroTileShortName: 600 | metroTileShowName: 0 601 | metroMediumTileShowName: 0 602 | metroLargeTileShowName: 0 603 | metroWideTileShowName: 0 604 | metroSupportStreamingInstall: 0 605 | metroLastRequiredScene: 0 606 | metroDefaultTileSize: 1 607 | metroTileForegroundText: 2 608 | metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} 609 | metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, 610 | a: 1} 611 | metroSplashScreenUseBackgroundColor: 0 612 | platformCapabilities: {} 613 | metroTargetDeviceFamilies: {} 614 | metroFTAName: 615 | metroFTAFileTypes: [] 616 | metroProtocolName: 617 | XboxOneProductId: 618 | XboxOneUpdateKey: 619 | XboxOneSandboxId: 620 | XboxOneContentId: 621 | XboxOneTitleId: 622 | XboxOneSCId: 623 | XboxOneGameOsOverridePath: 624 | XboxOnePackagingOverridePath: 625 | XboxOneAppManifestOverridePath: 626 | XboxOneVersion: 1.0.0.0 627 | XboxOnePackageEncryption: 0 628 | XboxOnePackageUpdateGranularity: 2 629 | XboxOneDescription: 630 | XboxOneLanguage: 631 | - enus 632 | XboxOneCapability: [] 633 | XboxOneGameRating: {} 634 | XboxOneIsContentPackage: 0 635 | XboxOneEnableGPUVariability: 1 636 | XboxOneSockets: {} 637 | XboxOneSplashScreen: {fileID: 0} 638 | XboxOneAllowedProductIds: [] 639 | XboxOnePersistentLocalStorageSize: 0 640 | XboxOneXTitleMemory: 8 641 | XboxOneOverrideIdentityName: 642 | XboxOneOverrideIdentityPublisher: 643 | vrEditorSettings: 644 | daydream: 645 | daydreamIconForeground: {fileID: 0} 646 | daydreamIconBackground: {fileID: 0} 647 | cloudServicesEnabled: 648 | UNet: 1 649 | luminIcon: 650 | m_Name: 651 | m_ModelFolderPath: 652 | m_PortalFolderPath: 653 | luminCert: 654 | m_CertPath: 655 | m_SignPackage: 1 656 | luminIsChannelApp: 0 657 | luminVersion: 658 | m_VersionCode: 1 659 | m_VersionName: 660 | apiCompatibilityLevel: 6 661 | cloudProjectId: 662 | framebufferDepthMemorylessMode: 0 663 | projectName: 664 | organizationId: 665 | cloudEnabled: 0 666 | enableNativePlatformBackendsForNewInputSystem: 0 667 | disableOldInputManagerSupport: 0 668 | legacyClampBlendShapeWeights: 0 669 | -------------------------------------------------------------------------------- /ProjectSettings/ProjectVersion.txt: -------------------------------------------------------------------------------- 1 | m_EditorVersion: 2019.4.9f1 2 | m_EditorVersionWithRevision: 2019.4.9f1 (50fe8a171dd9) 3 | -------------------------------------------------------------------------------- /ProjectSettings/QualitySettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!47 &1 4 | QualitySettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 5 7 | m_CurrentQuality: 5 8 | m_QualitySettings: 9 | - serializedVersion: 2 10 | name: Very Low 11 | pixelLightCount: 0 12 | shadows: 0 13 | shadowResolution: 0 14 | shadowProjection: 1 15 | shadowCascades: 1 16 | shadowDistance: 15 17 | shadowNearPlaneOffset: 3 18 | shadowCascade2Split: 0.33333334 19 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 20 | shadowmaskMode: 0 21 | blendWeights: 1 22 | textureQuality: 1 23 | anisotropicTextures: 0 24 | antiAliasing: 0 25 | softParticles: 0 26 | softVegetation: 0 27 | realtimeReflectionProbes: 0 28 | billboardsFaceCameraPosition: 0 29 | vSyncCount: 0 30 | lodBias: 0.3 31 | maximumLODLevel: 0 32 | streamingMipmapsActive: 0 33 | streamingMipmapsAddAllCameras: 1 34 | streamingMipmapsMemoryBudget: 512 35 | streamingMipmapsRenderersPerFrame: 512 36 | streamingMipmapsMaxLevelReduction: 2 37 | streamingMipmapsMaxFileIORequests: 1024 38 | particleRaycastBudget: 4 39 | asyncUploadTimeSlice: 2 40 | asyncUploadBufferSize: 16 41 | asyncUploadPersistentBuffer: 1 42 | resolutionScalingFixedDPIFactor: 1 43 | excludedTargetPlatforms: [] 44 | - serializedVersion: 2 45 | name: Low 46 | pixelLightCount: 0 47 | shadows: 0 48 | shadowResolution: 0 49 | shadowProjection: 1 50 | shadowCascades: 1 51 | shadowDistance: 20 52 | shadowNearPlaneOffset: 3 53 | shadowCascade2Split: 0.33333334 54 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 55 | shadowmaskMode: 0 56 | blendWeights: 2 57 | textureQuality: 0 58 | anisotropicTextures: 0 59 | antiAliasing: 0 60 | softParticles: 0 61 | softVegetation: 0 62 | realtimeReflectionProbes: 0 63 | billboardsFaceCameraPosition: 0 64 | vSyncCount: 0 65 | lodBias: 0.4 66 | maximumLODLevel: 0 67 | streamingMipmapsActive: 0 68 | streamingMipmapsAddAllCameras: 1 69 | streamingMipmapsMemoryBudget: 512 70 | streamingMipmapsRenderersPerFrame: 512 71 | streamingMipmapsMaxLevelReduction: 2 72 | streamingMipmapsMaxFileIORequests: 1024 73 | particleRaycastBudget: 16 74 | asyncUploadTimeSlice: 2 75 | asyncUploadBufferSize: 16 76 | asyncUploadPersistentBuffer: 1 77 | resolutionScalingFixedDPIFactor: 1 78 | excludedTargetPlatforms: [] 79 | - serializedVersion: 2 80 | name: Medium 81 | pixelLightCount: 1 82 | shadows: 1 83 | shadowResolution: 0 84 | shadowProjection: 1 85 | shadowCascades: 1 86 | shadowDistance: 20 87 | shadowNearPlaneOffset: 3 88 | shadowCascade2Split: 0.33333334 89 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 90 | shadowmaskMode: 0 91 | blendWeights: 2 92 | textureQuality: 0 93 | anisotropicTextures: 1 94 | antiAliasing: 0 95 | softParticles: 0 96 | softVegetation: 0 97 | realtimeReflectionProbes: 0 98 | billboardsFaceCameraPosition: 0 99 | vSyncCount: 1 100 | lodBias: 0.7 101 | maximumLODLevel: 0 102 | streamingMipmapsActive: 0 103 | streamingMipmapsAddAllCameras: 1 104 | streamingMipmapsMemoryBudget: 512 105 | streamingMipmapsRenderersPerFrame: 512 106 | streamingMipmapsMaxLevelReduction: 2 107 | streamingMipmapsMaxFileIORequests: 1024 108 | particleRaycastBudget: 64 109 | asyncUploadTimeSlice: 2 110 | asyncUploadBufferSize: 16 111 | asyncUploadPersistentBuffer: 1 112 | resolutionScalingFixedDPIFactor: 1 113 | excludedTargetPlatforms: [] 114 | - serializedVersion: 2 115 | name: High 116 | pixelLightCount: 2 117 | shadows: 2 118 | shadowResolution: 1 119 | shadowProjection: 1 120 | shadowCascades: 2 121 | shadowDistance: 40 122 | shadowNearPlaneOffset: 3 123 | shadowCascade2Split: 0.33333334 124 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 125 | shadowmaskMode: 1 126 | blendWeights: 2 127 | textureQuality: 0 128 | anisotropicTextures: 1 129 | antiAliasing: 0 130 | softParticles: 0 131 | softVegetation: 1 132 | realtimeReflectionProbes: 1 133 | billboardsFaceCameraPosition: 1 134 | vSyncCount: 1 135 | lodBias: 1 136 | maximumLODLevel: 0 137 | streamingMipmapsActive: 0 138 | streamingMipmapsAddAllCameras: 1 139 | streamingMipmapsMemoryBudget: 512 140 | streamingMipmapsRenderersPerFrame: 512 141 | streamingMipmapsMaxLevelReduction: 2 142 | streamingMipmapsMaxFileIORequests: 1024 143 | particleRaycastBudget: 256 144 | asyncUploadTimeSlice: 2 145 | asyncUploadBufferSize: 16 146 | asyncUploadPersistentBuffer: 1 147 | resolutionScalingFixedDPIFactor: 1 148 | excludedTargetPlatforms: [] 149 | - serializedVersion: 2 150 | name: Very High 151 | pixelLightCount: 3 152 | shadows: 2 153 | shadowResolution: 2 154 | shadowProjection: 1 155 | shadowCascades: 2 156 | shadowDistance: 70 157 | shadowNearPlaneOffset: 3 158 | shadowCascade2Split: 0.33333334 159 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 160 | shadowmaskMode: 1 161 | blendWeights: 4 162 | textureQuality: 0 163 | anisotropicTextures: 2 164 | antiAliasing: 2 165 | softParticles: 1 166 | softVegetation: 1 167 | realtimeReflectionProbes: 1 168 | billboardsFaceCameraPosition: 1 169 | vSyncCount: 1 170 | lodBias: 1.5 171 | maximumLODLevel: 0 172 | streamingMipmapsActive: 0 173 | streamingMipmapsAddAllCameras: 1 174 | streamingMipmapsMemoryBudget: 512 175 | streamingMipmapsRenderersPerFrame: 512 176 | streamingMipmapsMaxLevelReduction: 2 177 | streamingMipmapsMaxFileIORequests: 1024 178 | particleRaycastBudget: 1024 179 | asyncUploadTimeSlice: 2 180 | asyncUploadBufferSize: 16 181 | asyncUploadPersistentBuffer: 1 182 | resolutionScalingFixedDPIFactor: 1 183 | excludedTargetPlatforms: [] 184 | - serializedVersion: 2 185 | name: Ultra 186 | pixelLightCount: 4 187 | shadows: 2 188 | shadowResolution: 2 189 | shadowProjection: 1 190 | shadowCascades: 4 191 | shadowDistance: 150 192 | shadowNearPlaneOffset: 3 193 | shadowCascade2Split: 0.33333334 194 | shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} 195 | shadowmaskMode: 1 196 | blendWeights: 4 197 | textureQuality: 0 198 | anisotropicTextures: 2 199 | antiAliasing: 2 200 | softParticles: 1 201 | softVegetation: 1 202 | realtimeReflectionProbes: 1 203 | billboardsFaceCameraPosition: 1 204 | vSyncCount: 1 205 | lodBias: 2 206 | maximumLODLevel: 0 207 | streamingMipmapsActive: 0 208 | streamingMipmapsAddAllCameras: 1 209 | streamingMipmapsMemoryBudget: 512 210 | streamingMipmapsRenderersPerFrame: 512 211 | streamingMipmapsMaxLevelReduction: 2 212 | streamingMipmapsMaxFileIORequests: 1024 213 | particleRaycastBudget: 4096 214 | asyncUploadTimeSlice: 2 215 | asyncUploadBufferSize: 16 216 | asyncUploadPersistentBuffer: 1 217 | resolutionScalingFixedDPIFactor: 1 218 | excludedTargetPlatforms: [] 219 | m_PerPlatformDefaultQuality: 220 | Android: 2 221 | Lumin: 5 222 | Nintendo 3DS: 5 223 | Nintendo Switch: 5 224 | PS4: 5 225 | PSP2: 2 226 | Stadia: 5 227 | Standalone: 5 228 | WebGL: 3 229 | Windows Store Apps: 5 230 | XboxOne: 5 231 | iPhone: 2 232 | tvOS: 2 233 | -------------------------------------------------------------------------------- /ProjectSettings/TagManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!78 &1 4 | TagManager: 5 | serializedVersion: 2 6 | tags: [] 7 | layers: 8 | - Default 9 | - TransparentFX 10 | - Ignore Raycast 11 | - 12 | - Water 13 | - UI 14 | - 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | - 25 | - 26 | - 27 | - 28 | - 29 | - 30 | - 31 | - 32 | - 33 | - 34 | - 35 | - 36 | - 37 | - 38 | - 39 | - 40 | m_SortingLayers: 41 | - name: Default 42 | uniqueID: 0 43 | locked: 0 44 | -------------------------------------------------------------------------------- /ProjectSettings/TimeManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!5 &1 4 | TimeManager: 5 | m_ObjectHideFlags: 0 6 | Fixed Timestep: 0.02 7 | Maximum Allowed Timestep: 0.33333334 8 | m_TimeScale: 1 9 | Maximum Particle Timestep: 0.03 10 | -------------------------------------------------------------------------------- /ProjectSettings/UnityConnectSettings.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!310 &1 4 | UnityConnectSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 1 7 | m_Enabled: 0 8 | m_TestMode: 0 9 | m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events 10 | m_EventUrl: https://cdp.cloud.unity3d.com/v1/events 11 | m_ConfigUrl: https://config.uca.cloud.unity3d.com 12 | m_TestInitMode: 0 13 | CrashReportingSettings: 14 | m_EventUrl: https://perf-events.cloud.unity3d.com 15 | m_Enabled: 0 16 | m_LogBufferSize: 10 17 | m_CaptureEditorExceptions: 1 18 | UnityPurchasingSettings: 19 | m_Enabled: 0 20 | m_TestMode: 0 21 | UnityAnalyticsSettings: 22 | m_Enabled: 0 23 | m_TestMode: 0 24 | m_InitializeOnStartup: 1 25 | UnityAdsSettings: 26 | m_Enabled: 0 27 | m_InitializeOnStartup: 1 28 | m_TestMode: 0 29 | m_IosGameId: 30 | m_AndroidGameId: 31 | m_GameIds: {} 32 | m_GameId: 33 | PerformanceReportingSettings: 34 | m_Enabled: 0 35 | -------------------------------------------------------------------------------- /ProjectSettings/VFXManager.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!937362698 &1 4 | VFXManager: 5 | m_ObjectHideFlags: 0 6 | m_IndirectShader: {fileID: 0} 7 | m_CopyBufferShader: {fileID: 0} 8 | m_SortShader: {fileID: 0} 9 | m_StripUpdateShader: {fileID: 0} 10 | m_RenderPipeSettingsPath: 11 | m_FixedTimeStep: 0.016666668 12 | m_MaxDeltaTime: 0.05 13 | -------------------------------------------------------------------------------- /ProjectSettings/XRSettings.asset: -------------------------------------------------------------------------------- 1 | { 2 | "m_SettingKeys": [ 3 | "VR Device Disabled", 4 | "VR Device User Alert" 5 | ], 6 | "m_SettingValues": [ 7 | "False", 8 | "False" 9 | ] 10 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Visibility Graph Path Planning Simulation 2 | ![GitHub code size](https://img.shields.io/github/languages/code-size/christopher-boustros/Unity-Visibility-Graph-Path-Planning-Simulation "Code size") 3 | 4 | A simulation made with Unity in which agents perform path planning with a dynamically generated reduced visibility graph and the A\* algorithm. This was made as part of a course assignment for COMP 521 Modern Computer Games in fall 2020 at McGill University. 5 | 6 | No third-party assets are used in this project. 7 | 8 | You can run the simulation on GitHub Pages [**HERE**](https://christopher-boustros.github.io/Unity-Visibility-Graph-Path-Planning-Simulation/)! 9 | 10 | ![Alt text](/Screenshot.png?raw=true "Screenshot") 11 |

12 | 13 | ## How to run the simulation 14 | 15 | ### Requirements 16 | 17 | You must have Unity version 2019.4.9f1 installed on your computer. Other versions of Unity may have compatibility issues. 18 | 19 | ### Running the simulation in Unity 20 | 21 | Clone the master branch of this repository with `git clone --single-branch https://github.com/christopher-boustros/Unity-Visibility-Graph-Path-Planning-Simulation.git`, or alternatively, download and extract the ZIP archive of the master branch. 22 | 23 | Open the Unity Hub, click on the Projects tab, click on the ADD button, and select the root directory of this repository. 24 | 25 | Click on the project to open it in Unity. 26 | 27 | In the Project window, double click on the `MainScene.unity` file from the `Assets/Scenes` folder to replace the sample scene. 28 | 29 | Click on the play button to play the simulation. 30 |

31 | 32 | ## Simulation mechanics 33 | 34 | ### Choosing the number of agents 35 | In Unity, click on the `Agents` game object from the Hierarchy tab. Then, in the Inspector tab, there will be an input field named `Number Of Agents`, which will let you choose the number of agents that will be generated when the simulation is played. 36 | 37 | Each agent is represented as a sphere with a distinct color, and each agent has a destination represented as a cube of the same color. The line segments from an agent's start position to its destination represents the dynamically generated path along the visibility graph that the agent will move along to reach its destination. Once an agent reaches its destination, it will randomly choose a new destination and generate a new path to its destination. 38 | 39 | ### L-Shaped obstacles 40 | When the simulation starts, between 4 and 8 obstacles are spawned at random locations. The obstacles are dynamically generated to have a random L-shape. 41 | 42 | ### Reduced visibility graph 43 | A reduced visibility graph is dynamically generated when the simulation starts. The blue spheres are the vertices and the pink lines are the edges of the graph. This graph allows the agents to plan paths that avoid obstacles. 44 | 45 | A **visibility graph** is a graph that connects each obstacle vertex to every other obstacle vertex with an edge. So, each vertex of the graph represents a location that an agent can move to, and each edge represents a visible path between two vertices. This type of graph is useful for path planning as every path in the graph is visible, meaning it does not intersect an obstacle. However, a visibility graph may have edges that are not necessary for path planning as they are not part of a shortest path between any two locations. 46 | 47 | A **reduced visibility graph** is a visibility graph that only contains reflex vertices and bitangent edges, so it eliminates many unnecessary edges. A **reflex vertex** is a vertex of a polygon that has an exterior angle of less than 180 degrees. A **bitangent edge** is an edge between two reflex vertices that does not intersect an obstacle, even when slightly extended from either end. An example of an edge of a visibility graph that is not bitangent, and thus would not be part of a reduced visibility graph, is an edge that goes directly into an obstacle. This type of edge would be unnecessary for path planning because edges that go directly into an obstacle as opposed to scraping the corner of an obstacle are never part of an optimal, shortest path. 48 | 49 | ### Path finding with the A\* algorithm 50 | An agent finds an optimal path from its start position to its destination by searching the reduced visibility graph for a shortest path using the A\* algorithm. The weight of an edge used by the A\* algorithm is the Euclidean distance between the two vertices of the edge. 51 | 52 | ### Collision avoidance 53 | The agents detect and avoid collisions with each other using a simple replanning strategy. When two or more agents are about to collide with each other, they will all stop moving and each agent will wait between 0.1 and 1.1 seconds before replanning its path. An agent replans its path by simply moving back to its previous vertex and then resuming the path towards its destination. When an agent is still unable to move to its destination after three consecutive replannings, it will choose a new destination. 54 |

55 | 56 | ## References 57 | 58 | - The `AStarAlgorithm.cs` file is transformed from and built upon the pseudocode [here](https://en.wikipedia.org/wiki/A*_search_algorithm#Pseudocode). Since that pseudocode was released on Wikipedia, it is licensed for use under the [CC BY-SA 3.0 License](https://creativecommons.org/licenses/by-sa/3.0/) and the author has agreed that a hyperlink or URL is sufficient attribution under that license. 59 | 60 | - The implementation of the `UpdateOrthographicCameraSize` method in `CameraScaler.cs` is inspired by [this source](https://pressstart.vip/tutorials/2018/06/14/37/understanding-orthographic-size.html). No code in this repository is copied from that source. 61 |

62 | 63 | ## License 64 | 65 | - All contents of this repository excluding the `Assets/Scripts/AStarAlgorithm.cs` file are released under the [MIT License](https://opensource.org/licenses/MIT) (see LICENSE). 66 | 67 | - The `Assets/Scripts/AStarAlgorithm.cs` file is released under the [CC BY-SA 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/) (see LICENSE). 68 | -------------------------------------------------------------------------------- /Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/christopher-boustros/Unity-Visibility-Graph-Path-Planning-Simulation/179344ba44e58a05a7029cd8d373d71bbbe043cc/Screenshot.png --------------------------------------------------------------------------------