Second commit
This commit is contained in:
commit
36840f3ad4
999 files changed
+61364
No files matched your search
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0070d9ab552be2bb8aa0b8fa9f5b035
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,124 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 468a46d0ae32c3544b7d98094e6448a9, type: 3}
|
||||
m_Name: AddressableAssetSettings
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetSettings
|
||||
m_DefaultGroup: c6b29e598b23fb86ab8489c479625427
|
||||
m_currentHash:
|
||||
serializedVersion: 2
|
||||
Hash: 6035695aa4e96d0309c1b9843c316678
|
||||
m_ExtractTypeTreeData: 0
|
||||
m_OptimizeCatalogSize: 0
|
||||
m_BuildRemoteCatalog: 0
|
||||
m_CatalogRequestsTimeout: 0
|
||||
m_DisableCatalogUpdateOnStart: 0
|
||||
m_InternalIdNamingMode: 0
|
||||
m_InternalBundleIdMode: 1
|
||||
m_AssetLoadMode: 0
|
||||
m_BundledAssetProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
|
||||
m_AssetBundleProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
|
||||
m_IgnoreUnsupportedFilesInBuild: 0
|
||||
m_UniqueBundleIds: 0
|
||||
m_EnableJsonCatalog: 0
|
||||
m_NonRecursiveBuilding: 1
|
||||
m_AllowNestedBundleFolders: 0
|
||||
m_CCDEnabled: 0
|
||||
m_maxConcurrentWebRequests: 3
|
||||
m_UseUWRForLocalBundles: 0
|
||||
m_BundleTimeout: 0
|
||||
m_BundleRetryCount: 0
|
||||
m_BundleRedirectLimit: -1
|
||||
m_SharedBundleSettings: 0
|
||||
m_SharedBundleSettingsCustomGroupIndex: 0
|
||||
m_simulatedLoadDelay: 0.1
|
||||
m_ContiguousBundles: 1
|
||||
m_StripUnityVersionFromBundleBuild: 0
|
||||
m_DisableVisibleSubAssetRepresentations: 0
|
||||
m_BuiltInBundleNaming: 0
|
||||
mBuiltInBundleCustomNaming:
|
||||
m_MonoScriptBundleNaming: 0
|
||||
m_CheckForContentUpdateRestrictionsOption: 0
|
||||
m_MonoScriptBundleCustomNaming:
|
||||
m_RemoteCatalogBuildPath:
|
||||
m_Id:
|
||||
m_RemoteCatalogLoadPath:
|
||||
m_Id:
|
||||
m_ContentStateBuildPathProfileVariableName:
|
||||
m_CustomContentStateBuildPath:
|
||||
m_ContentStateBuildPath:
|
||||
m_BuildAddressablesWithPlayerBuild: 0
|
||||
m_overridePlayerVersion: '[UnityEditor.PlayerSettings.bundleVersion]'
|
||||
m_GroupAssets:
|
||||
- {fileID: 11400000, guid: 26d0fba16e9d375ab8f8eee15dc5c99a, type: 2}
|
||||
m_BuildSettings:
|
||||
m_LogResourceManagerExceptions: 1
|
||||
m_BundleBuildPath: Temp/com.unity.addressables/AssetBundles
|
||||
m_ProfileSettings:
|
||||
m_Profiles:
|
||||
- m_InheritedParent:
|
||||
m_Id: 7936c68390da9b21c9d4f479d7f7a261
|
||||
m_ProfileName: Default
|
||||
m_Values:
|
||||
- m_Id: 29df4a9753b8b149d85f010cf7480237
|
||||
m_Value: '[UnityEngine.AddressableAssets.Addressables.BuildPath]/[BuildTarget]'
|
||||
- m_Id: 2fad9c55a0f95113b8afde036bf8d205
|
||||
m_Value: <undefined>
|
||||
- m_Id: 4efa63d245bcc3563a4e5c228ff91b55
|
||||
m_Value: '{UnityEngine.AddressableAssets.Addressables.RuntimePath}/[BuildTarget]'
|
||||
- m_Id: 4f6d10d48bbef02988375cf7a5a315a3
|
||||
m_Value: '[UnityEditor.EditorUserBuildSettings.activeBuildTarget]'
|
||||
- m_Id: 523506dc6b7458e49b2586343fb4ffa9
|
||||
m_Value: 'ServerData/[BuildTarget]'
|
||||
m_ProfileEntryNames:
|
||||
- m_Id: 29df4a9753b8b149d85f010cf7480237
|
||||
m_Name: Local.BuildPath
|
||||
m_InlineUsage: 0
|
||||
- m_Id: 2fad9c55a0f95113b8afde036bf8d205
|
||||
m_Name: Remote.LoadPath
|
||||
m_InlineUsage: 0
|
||||
- m_Id: 4efa63d245bcc3563a4e5c228ff91b55
|
||||
m_Name: Local.LoadPath
|
||||
m_InlineUsage: 0
|
||||
- m_Id: 4f6d10d48bbef02988375cf7a5a315a3
|
||||
m_Name: BuildTarget
|
||||
m_InlineUsage: 0
|
||||
- m_Id: 523506dc6b7458e49b2586343fb4ffa9
|
||||
m_Name: Remote.BuildPath
|
||||
m_InlineUsage: 0
|
||||
m_ProfileVersion: 1
|
||||
m_LabelTable:
|
||||
m_LabelNames:
|
||||
- default
|
||||
- AudioSourceSettings
|
||||
- AudioInfo
|
||||
- Particles
|
||||
- UIPanel
|
||||
- Volume
|
||||
- SceneInfo
|
||||
- CleanTool
|
||||
m_SchemaTemplates: []
|
||||
m_GroupTemplateObjects:
|
||||
- {fileID: 11400000, guid: 8c4ebef95ae1ef057bea1e3916daec48, type: 2}
|
||||
m_InitializationObjects: []
|
||||
m_CertificateHandlerType:
|
||||
m_AssemblyName:
|
||||
m_ClassName:
|
||||
m_ActivePlayerDataBuilderIndex: 2
|
||||
m_DataBuilders:
|
||||
- {fileID: 11400000, guid: 954ad4ecd0dc213b192cfe18e6022fcf, type: 2}
|
||||
- {fileID: 11400000, guid: e30c90a90283fe46d88ee48888ca5acf, type: 2}
|
||||
- {fileID: 11400000, guid: 36ff3fee814db2e40b7585fa27714179, type: 2}
|
||||
m_ActiveProfileId: 7936c68390da9b21c9d4f479d7f7a261
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fca3ff8b9d20369af80cdf3da2a95a6f
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e2e850970db2d8c579a490fc8dafcc5e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1a3c5d64ac83548c09dd1678b9f6f1cd, type: 3}
|
||||
m_Name: Packed Assets
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroupTemplate
|
||||
m_SchemaObjects:
|
||||
- {fileID: 8078399966258360141}
|
||||
- {fileID: 1844683351890208849}
|
||||
m_Description: Pack assets into asset bundles.
|
||||
m_Settings: {fileID: 11400000, guid: fca3ff8b9d20369af80cdf3da2a95a6f, type: 2}
|
||||
--- !u!114 &1844683351890208849
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
|
||||
m_Name: ContentUpdateGroupSchema
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema
|
||||
m_Group: {fileID: 0}
|
||||
m_StaticContent: 0
|
||||
--- !u!114 &8078399966258360141
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
|
||||
m_Name: BundledAssetGroupSchema
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema
|
||||
m_Group: {fileID: 0}
|
||||
m_InternalBundleIdMode: 1
|
||||
m_Compression: 1
|
||||
m_IncludeAddressInCatalog: 1
|
||||
m_IncludeGUIDInCatalog: 1
|
||||
m_IncludeLabelsInCatalog: 1
|
||||
m_InternalIdNamingMode: 0
|
||||
m_CacheClearBehavior: 0
|
||||
m_IncludeInBuild: 1
|
||||
m_BundledAssetProviderType:
|
||||
m_AssemblyName:
|
||||
m_ClassName:
|
||||
m_StripDownloadOptions: 0
|
||||
m_ForceUniqueProvider: 0
|
||||
m_UseAssetBundleCache: 1
|
||||
m_UseAssetBundleCrc: 1
|
||||
m_UseAssetBundleCrcForCachedBundles: 1
|
||||
m_UseUWRForLocalBundles: 0
|
||||
m_Timeout: 0
|
||||
m_ChunkedTransfer: 0
|
||||
m_RedirectLimit: -1
|
||||
m_RetryCount: 0
|
||||
m_BuildPath:
|
||||
m_Id:
|
||||
m_LoadPath:
|
||||
m_Id:
|
||||
m_BundleMode: 0
|
||||
m_AssetBundleProviderType:
|
||||
m_AssemblyName:
|
||||
m_ClassName:
|
||||
m_UseDefaultSchemaSettings: 0
|
||||
m_SelectedPathPairIndex: 0
|
||||
m_BundleNaming: 0
|
||||
m_AssetLoadMode: 0
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c4ebef95ae1ef057bea1e3916daec48
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3dc806bebae8fc990aed755daf9f2e11
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: bbb281ee3bf0b054c82ac2347e9e782c, type: 3}
|
||||
m_Name: Default Local Group
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup
|
||||
m_GroupName: Default Local Group
|
||||
m_GUID: c6b29e598b23fb86ab8489c479625427
|
||||
m_SerializeEntries:
|
||||
- m_GUID: 0ad4fd11028eb24559196762a241834a
|
||||
m_Address: Assets/Infrastructure/Audio/NoBlendSource.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels:
|
||||
- AudioSourceSettings
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 0e4f435f78018b832b63442391e12c8b
|
||||
m_Address: Assets/DCleaner/Camera/GameCamera.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels: []
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 1d088f052c2092d1f9cb64b3a16f5779
|
||||
m_Address: Assets/Infrastructure/UI/CanvasSettings.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels: []
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 23d63858ba5674a208b4577b77319113
|
||||
m_Address: Assets/DCleaner/Audio/Audio Source.prefab
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels: []
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 2e21bba962bb10f53a41bb8aee11cbb2
|
||||
m_Address: Assets/Infrastructure/Audio/AudioSourcePrefab.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels: []
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 4063962b1b4e97ccd90729bd538a1fb4
|
||||
m_Address: Assets/Infrastructure/Audio/Full3DSource.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels:
|
||||
- AudioSourceSettings
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 7e53d1050bed148929357759009cc715
|
||||
m_Address: Assets/Infrastructure/Audio/AudioMixerSettings.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels: []
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: e92086276d9b32213abd64903ad4b730
|
||||
m_Address: Assets/Infrastructure/Input/InputService.asset
|
||||
m_ReadOnly: 0
|
||||
m_SerializedLabels: []
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
m_ReadOnly: 0
|
||||
m_Settings: {fileID: 11400000, guid: fca3ff8b9d20369af80cdf3da2a95a6f, type: 2}
|
||||
m_SchemaSet:
|
||||
m_Schemas:
|
||||
- {fileID: 11400000, guid: 4c0a03f9a585ef062b42f9bf0e69ab08, type: 2}
|
||||
- {fileID: 11400000, guid: a4b2eb4eda3160b34a3cfbea0f1a3049, type: 2}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 26d0fba16e9d375ab8f8eee15dc5c99a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d19f468b4db9986098a38c3b4cfd69e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: e5d17a21594effb4e9591490b009e7aa, type: 3}
|
||||
m_Name: Default Local Group_BundledAssetGroupSchema
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.BundledAssetGroupSchema
|
||||
m_Group: {fileID: 11400000, guid: 26d0fba16e9d375ab8f8eee15dc5c99a, type: 2}
|
||||
m_InternalBundleIdMode: 1
|
||||
m_Compression: 1
|
||||
m_IncludeAddressInCatalog: 1
|
||||
m_IncludeGUIDInCatalog: 1
|
||||
m_IncludeLabelsInCatalog: 1
|
||||
m_InternalIdNamingMode: 0
|
||||
m_CacheClearBehavior: 0
|
||||
m_IncludeInBuild: 1
|
||||
m_BundledAssetProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.BundledAssetProvider
|
||||
m_StripDownloadOptions: 0
|
||||
m_ForceUniqueProvider: 0
|
||||
m_UseAssetBundleCache: 1
|
||||
m_UseAssetBundleCrc: 1
|
||||
m_UseAssetBundleCrcForCachedBundles: 1
|
||||
m_UseUWRForLocalBundles: 0
|
||||
m_Timeout: 0
|
||||
m_ChunkedTransfer: 0
|
||||
m_RedirectLimit: -1
|
||||
m_RetryCount: 0
|
||||
m_BuildPath:
|
||||
m_Id: 29df4a9753b8b149d85f010cf7480237
|
||||
m_LoadPath:
|
||||
m_Id: 4efa63d245bcc3563a4e5c228ff91b55
|
||||
m_BundleMode: 0
|
||||
m_AssetBundleProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.AssetBundleProvider
|
||||
m_UseDefaultSchemaSettings: 0
|
||||
m_SelectedPathPairIndex: 0
|
||||
m_BundleNaming: 0
|
||||
m_AssetLoadMode: 0
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c0a03f9a585ef062b42f9bf0e69ab08
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5834b5087d578d24c926ce20cd31e6d6, type: 3}
|
||||
m_Name: Default Local Group_ContentUpdateGroupSchema
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.GroupSchemas.ContentUpdateGroupSchema
|
||||
m_Group: {fileID: 11400000, guid: 26d0fba16e9d375ab8f8eee15dc5c99a, type: 2}
|
||||
m_StaticContent: 0
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4b2eb4eda3160b34a3cfbea0f1a3049
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91b16a7e9299972d698d5de40363afd1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 88d21199f5d473f4db36845f2318f180, type: 3}
|
||||
m_Name: BuildScriptFastMode
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptFastMode
|
||||
instanceProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider
|
||||
sceneProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.SceneProvider
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 954ad4ecd0dc213b192cfe18e6022fcf
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3e2e0ffa088c91d41a086d0b8cb16bdc, type: 3}
|
||||
m_Name: BuildScriptPackedMode
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedMode
|
||||
instanceProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider
|
||||
sceneProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.SceneProvider
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36ff3fee814db2e40b7585fa27714179
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: ad8c280d42ee0ed41a27db23b43dd2bf, type: 3}
|
||||
m_Name: BuildScriptPackedPlayMode
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Build.DataBuilders.BuildScriptPackedPlayMode
|
||||
instanceProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.InstanceProvider
|
||||
sceneProviderType:
|
||||
m_AssemblyName: Unity.ResourceManager, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
|
||||
m_ClassName: UnityEngine.ResourceManagement.ResourceProviders.SceneProvider
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e30c90a90283fe46d88ee48888ca5acf
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3a189bb168d8d90478a09ea08c2f3d72, type: 3}
|
||||
m_Name: DefaultObject
|
||||
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject
|
||||
m_AddressableAssetSettingsGuid: fca3ff8b9d20369af80cdf3da2a95a6f
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56f261798a15fdfc4a61112565af447b
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cccfb83c072506af5ace8e119f44435b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f948a9778c6c4fd78629a4618a7e5302
|
||||
timeCreated: 1785829267
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 601de2d2ea58417f8b5a46faf0b11196
|
||||
timeCreated: 1785923690
|
||||
@@ -0,0 +1,31 @@
|
||||
using R3;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
public abstract class CleanTool
|
||||
{
|
||||
protected float DurabilityUsageStep;
|
||||
protected Texture2D BrushTexture;
|
||||
protected float CleanRadius;
|
||||
|
||||
public abstract CleanToolType ToolType { get; }
|
||||
|
||||
protected CleanTool(float durabilityUsageStep, float cleanRadius, Texture2D brushTexture)
|
||||
{
|
||||
IsDirty.Value = false;
|
||||
|
||||
DurabilityUsageStep = durabilityUsageStep;
|
||||
CleanRadius = cleanRadius;
|
||||
BrushTexture = brushTexture;
|
||||
}
|
||||
|
||||
public ReactiveProperty<bool> IsDirty { get; } = new();
|
||||
public ReactiveProperty<float> CurrentDirtiness { get; }
|
||||
= new(0f);
|
||||
|
||||
public abstract TryapkaUsageInfo Use();
|
||||
|
||||
public abstract void Clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc959003316e4db99a7f190b1b431298
|
||||
timeCreated: 1785939044
|
||||
@@ -0,0 +1,15 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
[Config("Cleaning/CleanToolConfig", multiple: true)]
|
||||
[CreateAssetMenu(fileName = "CleanToolConfig", menuName = "Config/CleanToolConfig")]
|
||||
public class CleanToolConfig : ScriptableObject
|
||||
{
|
||||
public float DurabilityUsageStep;
|
||||
public Texture2D BrushTexture;
|
||||
public float CleanRadius;
|
||||
public CleanToolType ToolType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98cb6ddb562747d8b4549287a391a98e
|
||||
timeCreated: 1786032650
|
||||
@@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
public abstract class CleanToolInteractable : MonoBehaviour
|
||||
{
|
||||
public abstract void Use(CleanTool tool);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d17365593864a6e9c5cab8971c33c75
|
||||
timeCreated: 1785938942
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
public enum CleanToolType
|
||||
{
|
||||
Tryapka
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56a8b3bb2a354e59a3a9a3d6e83c8fe0
|
||||
timeCreated: 1786028280
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
public class DirtyToolCleaner : CleanToolInteractable
|
||||
{
|
||||
public override void Use(CleanTool tool)
|
||||
{
|
||||
tool.Clean();
|
||||
Debug.Log("Tool cleaned");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90e6386fcc8249afad82234df1fcf3d4
|
||||
timeCreated: 1785923693
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
public record ToolUsageInfo
|
||||
{
|
||||
public float Dirtiness;
|
||||
public bool IsDirty;
|
||||
public Texture BrushTexture;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0723fb7c41244d8c8b9272d09977dc8f
|
||||
timeCreated: 1785939283
|
||||
@@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.CleanTools
|
||||
{
|
||||
public class Tryapka : CleanTool
|
||||
{
|
||||
public Tryapka(float durabilityUsageStep, float cleanRadius, Texture2D brushTexture) : base(durabilityUsageStep, cleanRadius, brushTexture)
|
||||
{
|
||||
}
|
||||
|
||||
public override CleanToolType ToolType => CleanToolType.Tryapka;
|
||||
|
||||
public override TryapkaUsageInfo Use()
|
||||
{
|
||||
if (!IsDirty.CurrentValue)
|
||||
{
|
||||
CurrentDirtiness.Value += DurabilityUsageStep;
|
||||
|
||||
if (CurrentDirtiness.Value >= 1) IsDirty.Value = true;
|
||||
}
|
||||
|
||||
return new(CleanRadius, CurrentDirtiness.Value, IsDirty.CurrentValue, BrushTexture);
|
||||
}
|
||||
|
||||
public override void Clean()
|
||||
{
|
||||
CurrentDirtiness.Value = 0;
|
||||
IsDirty.Value = false;
|
||||
}
|
||||
}
|
||||
|
||||
public record TryapkaUsageInfo : ToolUsageInfo
|
||||
{
|
||||
public float Radius;
|
||||
|
||||
public TryapkaUsageInfo(float radius, float dirtiness, bool isDirty, Texture brush)
|
||||
{
|
||||
Radius = radius;
|
||||
Dirtiness = dirtiness;
|
||||
IsDirty = isDirty;
|
||||
BrushTexture = brush;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5da5c20e36c0403691a65f6e0317c129
|
||||
timeCreated: 1785923693
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b6718c9ff8a4963941f9f966f49f795
|
||||
timeCreated: 1785923035
|
||||
@@ -0,0 +1,11 @@
|
||||
using R3;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning
|
||||
{
|
||||
public class Cleanable : MonoBehaviour
|
||||
{
|
||||
public ReactiveProperty<bool> Cleaned { get; } = new();
|
||||
public ReactiveProperty<float> CleanProgress { get; } = new();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 219620ccf64f42d7a64d27a3a152f961
|
||||
timeCreated: 1785923122
|
||||
@@ -0,0 +1,35 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning
|
||||
{
|
||||
public class CleanableAsset : Cleanable
|
||||
{
|
||||
private Collider _dirtyCollider;
|
||||
private static readonly int MaskMap = Shader.PropertyToID("_Mask");
|
||||
[SerializeField] private float cleanCountPerFrame;
|
||||
private Material _renderMaterial;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_dirtyCollider = GetComponent<Collider>();
|
||||
|
||||
_renderMaterial = GetComponent<MeshRenderer>().material;
|
||||
}
|
||||
private void AssumedAsCleaned()
|
||||
{
|
||||
Cleaned.Value = true;
|
||||
_dirtyCollider.enabled = false;
|
||||
_renderMaterial.SetTexture(MaskMap, Texture2D.blackTexture);
|
||||
}
|
||||
|
||||
public void Clean()
|
||||
{
|
||||
CleanProgress.Value += cleanCountPerFrame;
|
||||
|
||||
if(CleanProgress.CurrentValue >= 100)
|
||||
AssumedAsCleaned();
|
||||
|
||||
Debug.Log($"{name} прогресс очистки: {CleanProgress.CurrentValue}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b184056d80d64c5d9f9cdb03cb00efc7
|
||||
timeCreated: 1785923122
|
||||
@@ -0,0 +1,490 @@
|
||||
using System.Collections.Generic;
|
||||
using Code.D.Cleaning.CleanTools;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using TinyGoose.Tremble;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Code.D.Cleaning
|
||||
{
|
||||
[BrushEntity("CleanableSurface", layer: "Cleanable")]
|
||||
public class CleanableSurface : Cleanable, IOnImportFromMapEntity
|
||||
{
|
||||
private static readonly int MaskMap = Shader.PropertyToID("_Mask");
|
||||
private static readonly int DrawPosition = Shader.PropertyToID("_DrawPosition");
|
||||
private static readonly int DrawRadius = Shader.PropertyToID("_DrawRadius");
|
||||
private static readonly int ToolDirtiness = Shader.PropertyToID("_ToolDirtiness");
|
||||
private static readonly int BrushTex = Shader.PropertyToID("_BrushTex");
|
||||
private static readonly int DrawAngleX = Shader.PropertyToID("_DrawAngleX");
|
||||
private static readonly int DrawAngleY = Shader.PropertyToID("_DrawAngleY");
|
||||
|
||||
private const int CalcResolution = 64;
|
||||
|
||||
[SerializeField] private float cleanedThreshold = 0.7f;
|
||||
|
||||
private RenderTexture _maskRT;
|
||||
private RenderTexture _calcRT;
|
||||
private Material _brushMaterial;
|
||||
private Material _renderMaterial;
|
||||
|
||||
private bool _onProcess;
|
||||
private UniTask _calculationOperation;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
gameObject.tag = "CleanableSurface";
|
||||
|
||||
_maskRT = new RenderTexture(1024, 1024, 0, RenderTextureFormat.ARGB32);
|
||||
_maskRT.Create();
|
||||
Graphics.Blit(Texture2D.whiteTexture, _maskRT);
|
||||
|
||||
_calcRT = new RenderTexture(CalcResolution, CalcResolution, 0, RenderTextureFormat.ARGB32);
|
||||
_calcRT.Create();
|
||||
|
||||
_brushMaterial = new Material(Shader.Find("Unlit/BrushPainter"));
|
||||
|
||||
if (!TryGetComponent<MeshRenderer>(out var renderer)) return;
|
||||
_renderMaterial = renderer.material;
|
||||
_renderMaterial.SetTexture(MaskMap, _maskRT);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Нейросеть написала и этот метод, слишком много математики мне он не нравится. Он заставляет игру лагать. Нужно сделать проще.
|
||||
/// Хотябы комментарии оставлены человеком.
|
||||
/// Я профнепригоден.
|
||||
/// </summary>
|
||||
/// <param name="hit"></param>
|
||||
/// <param name="tryapkaUsageInfo"></param>
|
||||
/// <param name="playerCamera"></param>
|
||||
public void Clean(RaycastHit hit, TryapkaUsageInfo tryapkaUsageInfo, Transform playerCamera)
|
||||
{
|
||||
if (Cleaned.CurrentValue) return;
|
||||
|
||||
Vector2 uv = hit.textureCoord;
|
||||
|
||||
// Логика вычисления направления кисти
|
||||
Vector3 dirToCamera = playerCamera.position - hit.point;
|
||||
Vector3 projDir = Vector3.ProjectOnPlane(dirToCamera, hit.normal);
|
||||
|
||||
if (projDir.sqrMagnitude < 0.0001f)
|
||||
{
|
||||
projDir = Vector3.ProjectOnPlane(playerCamera.up, hit.normal);
|
||||
}
|
||||
|
||||
projDir.Normalize();
|
||||
|
||||
// Логика определения U V или W
|
||||
Vector3 localDir = hit.transform.InverseTransformDirection(projDir);
|
||||
Vector3 localNormal = hit.transform.InverseTransformDirection(hit.normal).normalized;
|
||||
|
||||
ComputeTangentBasis(localNormal, out var axisU, out var axisV);
|
||||
|
||||
// Определяем синус и косинус поворота
|
||||
float u = Vector3.Dot(localDir, axisU);
|
||||
float v = Vector3.Dot(localDir, axisV);
|
||||
|
||||
_brushMaterial.SetVector(DrawPosition, uv);
|
||||
_brushMaterial.SetFloat(DrawRadius, tryapkaUsageInfo.Radius);
|
||||
_brushMaterial.SetFloat(DrawAngleX, v);
|
||||
_brushMaterial.SetFloat(DrawAngleY, u);
|
||||
_brushMaterial.SetFloat(ToolDirtiness, tryapkaUsageInfo.Dirtiness);
|
||||
_brushMaterial.SetTexture(BrushTex, tryapkaUsageInfo.BrushTexture);
|
||||
|
||||
Graphics.Blit(Texture2D.blackTexture, _maskRT, _brushMaterial, 0);
|
||||
|
||||
if (_calculationOperation.Status != UniTaskStatus.Pending)
|
||||
{
|
||||
_calculationOperation = CalculateCleanPercentage();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ComputeTangentBasis(Vector3 normal, out Vector3 axisU, out Vector3 axisV)
|
||||
{
|
||||
if (Mathf.Abs(normal.y) > FlatNormalThreshold)
|
||||
{
|
||||
axisU = Vector3.right;
|
||||
axisV = Vector3.forward;
|
||||
}
|
||||
else
|
||||
{
|
||||
axisU = Vector3.Cross(Vector3.up, normal).normalized;
|
||||
axisV = Vector3.up;
|
||||
}
|
||||
}
|
||||
|
||||
private async UniTask CalculateCleanPercentage()
|
||||
{
|
||||
if (!_maskRT || _onProcess) return;
|
||||
|
||||
_onProcess = true;
|
||||
|
||||
Graphics.Blit(_maskRT, _calcRT);
|
||||
|
||||
var destroyToken = this.GetCancellationTokenOnDestroy();
|
||||
var request = AsyncGPUReadback.Request(_calcRT, 0, TextureFormat.RGBA32);
|
||||
await request.ToUniTask(cancellationToken: destroyToken);
|
||||
|
||||
if (request.hasError)
|
||||
{
|
||||
_onProcess = false;
|
||||
return;
|
||||
}
|
||||
|
||||
NativeArray<byte> data = request.GetData<byte>();
|
||||
int totalBytes = data.Length;
|
||||
long totalBrightness = 0;
|
||||
|
||||
for (var i = 0; i < totalBytes; i += 4)
|
||||
{
|
||||
totalBrightness += data[i];
|
||||
}
|
||||
|
||||
int pixelCount = totalBytes / 4;
|
||||
float maxPossibleBrightness = pixelCount * 255f;
|
||||
|
||||
float progress = 1.0f - (totalBrightness / maxPossibleBrightness);
|
||||
|
||||
if (Mathf.Abs(progress - CleanProgress.CurrentValue) > 0.01f)
|
||||
{
|
||||
CleanProgress.Value = progress;
|
||||
}
|
||||
|
||||
if (CleanProgress.CurrentValue >= cleanedThreshold && !Cleaned.CurrentValue)
|
||||
{
|
||||
AssumedAsCleaned();
|
||||
}
|
||||
|
||||
_onProcess = false;
|
||||
}
|
||||
|
||||
private void AssumedAsCleaned()
|
||||
{
|
||||
Cleaned.Value = true;
|
||||
FinishClean();
|
||||
}
|
||||
|
||||
private void FinishClean()
|
||||
{
|
||||
Graphics.Blit(Texture2D.blackTexture, _maskRT);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_maskRT) _maskRT.Release();
|
||||
if (_calcRT) _calcRT.Release();
|
||||
if (_brushMaterial) Destroy(_brushMaterial);
|
||||
if (_renderMaterial) Destroy(_renderMaterial);
|
||||
}
|
||||
|
||||
public void OnImportFromMapEntity(MapBsp mapBsp, BspEntity entity)
|
||||
{
|
||||
Debug.Log("Found a brush!");
|
||||
|
||||
var meshFilter = gameObject.GetComponent<MeshFilter>();
|
||||
if (meshFilter == null)
|
||||
{
|
||||
Debug.LogError($"[CleanableSurface] MeshFilter отсутствует на {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceMesh = meshFilter.sharedMesh;
|
||||
if (sourceMesh == null)
|
||||
{
|
||||
Debug.LogError($"[CleanableSurface] sharedMesh == null на {gameObject.name}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sourceMesh.isReadable)
|
||||
{
|
||||
Debug.LogError($"[CleanableSurface] Меш '{sourceMesh.name}' не readable, не могу построить UV");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sourceMesh.vertexCount == 0 || sourceMesh.triangles.Length == 0)
|
||||
{
|
||||
Debug.LogError($"[CleanableSurface] Меш '{sourceMesh.name}' пустой");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BuildLayeredUVInPlace(sourceMesh);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
Debug.LogError($"[CleanableSurface] Исключение при построении UV для {gameObject.name}: {ex}");
|
||||
return;
|
||||
}
|
||||
|
||||
var meshCollider = gameObject.GetComponent<MeshCollider>();
|
||||
if (meshCollider != null)
|
||||
meshCollider.sharedMesh = sourceMesh;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
var existingFlags = GameObjectUtility.GetStaticEditorFlags(gameObject);
|
||||
GameObjectUtility.SetStaticEditorFlags(gameObject, existingFlags | StaticEditorFlags.ContributeGI);
|
||||
#endif
|
||||
|
||||
Debug.Log(
|
||||
$"[CleanableSurface] UV построен для {gameObject.name}: verts={sourceMesh.vertexCount}, tris={sourceMesh.triangles.Length / 3}");
|
||||
}
|
||||
|
||||
private const float MaskUvPadding = 0.08f;
|
||||
|
||||
private const float WeldEpsilon = 0.0005f;
|
||||
|
||||
private const float CoplanarDotThreshold = 0.999f;
|
||||
|
||||
private const float FlatNormalThreshold = 0.999f;
|
||||
|
||||
/// <summary>
|
||||
/// Этот большой и сложный метод написан нейросетью Claude Sonnet 5 Medium. Я профнепригоден
|
||||
/// </summary>
|
||||
/// <param name="mesh"></param>
|
||||
private static void BuildLayeredUVInPlace(Mesh mesh)
|
||||
{
|
||||
var srcVerts = mesh.vertices;
|
||||
var srcNormals = mesh.normals;
|
||||
var srcUvTile = mesh.uv;
|
||||
bool hasNormals = srcNormals.Length == srcVerts.Length;
|
||||
bool hasUvTile = srcUvTile.Length == srcVerts.Length;
|
||||
|
||||
int subMeshCount = mesh.subMeshCount;
|
||||
|
||||
var posToId = new Dictionary<Vector3Int, int>();
|
||||
|
||||
int CanonicalId(Vector3 p)
|
||||
{
|
||||
var key = new Vector3Int(
|
||||
Mathf.RoundToInt(p.x / WeldEpsilon),
|
||||
Mathf.RoundToInt(p.y / WeldEpsilon),
|
||||
Mathf.RoundToInt(p.z / WeldEpsilon));
|
||||
if (posToId.TryGetValue(key, out var id)) return id;
|
||||
id = posToId.Count;
|
||||
posToId[key] = id;
|
||||
return id;
|
||||
}
|
||||
|
||||
var triSubMesh = new List<int>();
|
||||
var triI0 = new List<int>();
|
||||
var triI1 = new List<int>();
|
||||
var triI2 = new List<int>();
|
||||
var triCanonA = new List<int>();
|
||||
var triCanonB = new List<int>();
|
||||
var triCanonC = new List<int>();
|
||||
var triNormal = new List<Vector3>();
|
||||
|
||||
for (int s = 0; s < subMeshCount; s++)
|
||||
{
|
||||
var tris = mesh.GetTriangles(s);
|
||||
for (int t = 0; t < tris.Length; t += 3)
|
||||
{
|
||||
int i0 = tris[t], i1 = tris[t + 1], i2 = tris[t + 2];
|
||||
Vector3 p0 = srcVerts[i0], p1 = srcVerts[i1], p2 = srcVerts[i2];
|
||||
Vector3 n = Vector3.Cross(p1 - p0, p2 - p0);
|
||||
n = n.sqrMagnitude > 1e-10f ? n.normalized : Vector3.up;
|
||||
|
||||
triSubMesh.Add(s);
|
||||
triI0.Add(i0);
|
||||
triI1.Add(i1);
|
||||
triI2.Add(i2);
|
||||
triCanonA.Add(CanonicalId(p0));
|
||||
triCanonB.Add(CanonicalId(p1));
|
||||
triCanonC.Add(CanonicalId(p2));
|
||||
triNormal.Add(n);
|
||||
}
|
||||
}
|
||||
|
||||
int triCount = triSubMesh.Count;
|
||||
|
||||
var parent = new int[triCount];
|
||||
for (int i = 0; i < triCount; i++) parent[i] = i;
|
||||
|
||||
int Find(int x)
|
||||
{
|
||||
while (parent[x] != x)
|
||||
{
|
||||
parent[x] = parent[parent[x]];
|
||||
x = parent[x];
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
void Union(int a, int b)
|
||||
{
|
||||
a = Find(a);
|
||||
b = Find(b);
|
||||
if (a != b) parent[a] = b;
|
||||
}
|
||||
|
||||
var edgeMap = new Dictionary<long, int>();
|
||||
|
||||
long PackEdge(int a, int b)
|
||||
{
|
||||
if (a > b) (a, b) = (b, a);
|
||||
return ((long)a << 32) | (uint)b;
|
||||
}
|
||||
|
||||
void ProcessEdge(long e, int t)
|
||||
{
|
||||
if (edgeMap.TryGetValue(e, out var other))
|
||||
{
|
||||
if (Vector3.Dot(triNormal[t], triNormal[other]) > CoplanarDotThreshold)
|
||||
Union(t, other);
|
||||
}
|
||||
else
|
||||
{
|
||||
edgeMap[e] = t;
|
||||
}
|
||||
}
|
||||
|
||||
for (int t = 0; t < triCount; t++)
|
||||
{
|
||||
int a = triCanonA[t], b = triCanonB[t], c = triCanonC[t];
|
||||
ProcessEdge(PackEdge(a, b), t);
|
||||
ProcessEdge(PackEdge(b, c), t);
|
||||
ProcessEdge(PackEdge(c, a), t);
|
||||
}
|
||||
|
||||
var islandOf = new int[triCount];
|
||||
var islandRootToIndex = new Dictionary<int, int>();
|
||||
for (int t = 0; t < triCount; t++)
|
||||
{
|
||||
int root = Find(t);
|
||||
if (!islandRootToIndex.TryGetValue(root, out var idx))
|
||||
{
|
||||
idx = islandRootToIndex.Count;
|
||||
islandRootToIndex[root] = idx;
|
||||
}
|
||||
|
||||
islandOf[t] = idx;
|
||||
}
|
||||
|
||||
int islandCount = islandRootToIndex.Count;
|
||||
|
||||
var accumNormal = new Vector3[islandCount];
|
||||
for (int t = 0; t < triCount; t++)
|
||||
accumNormal[islandOf[t]] += triNormal[t];
|
||||
|
||||
var islandAxisU = new Vector3[islandCount];
|
||||
var islandAxisV = new Vector3[islandCount];
|
||||
for (int i = 0; i < islandCount; i++)
|
||||
{
|
||||
var n = accumNormal[i].normalized;
|
||||
ComputeTangentBasis(n, out islandAxisU[i], out islandAxisV[i]);
|
||||
}
|
||||
|
||||
var islandMinU = new float[islandCount];
|
||||
var islandMinV = new float[islandCount];
|
||||
var islandMaxU = new float[islandCount];
|
||||
var islandMaxV = new float[islandCount];
|
||||
for (int i = 0; i < islandCount; i++)
|
||||
{
|
||||
islandMinU[i] = islandMinV[i] = float.PositiveInfinity;
|
||||
islandMaxU[i] = islandMaxV[i] = float.NegativeInfinity;
|
||||
}
|
||||
|
||||
Vector2 ProjectUV(Vector3 local, Vector3 axisU, Vector3 axisV) =>
|
||||
new Vector2(Vector3.Dot(local, axisU), Vector3.Dot(local, axisV));
|
||||
|
||||
for (int t = 0; t < triCount; t++)
|
||||
{
|
||||
int island = islandOf[t];
|
||||
Vector2 a = ProjectUV(srcVerts[triI0[t]], islandAxisU[island], islandAxisV[island]);
|
||||
Vector2 b = ProjectUV(srcVerts[triI1[t]], islandAxisU[island], islandAxisV[island]);
|
||||
Vector2 c = ProjectUV(srcVerts[triI2[t]], islandAxisU[island], islandAxisV[island]);
|
||||
|
||||
islandMinU[island] = Mathf.Min(islandMinU[island], a.x, b.x, c.x);
|
||||
islandMinV[island] = Mathf.Min(islandMinV[island], a.y, b.y, c.y);
|
||||
islandMaxU[island] = Mathf.Max(islandMaxU[island], a.x, b.x, c.x);
|
||||
islandMaxV[island] = Mathf.Max(islandMaxV[island], a.y, b.y, c.y);
|
||||
}
|
||||
|
||||
int gridSize = Mathf.Max(1, Mathf.CeilToInt(Mathf.Sqrt(islandCount)));
|
||||
float cellSize = 1f / gridSize;
|
||||
float cellPad = cellSize * MaskUvPadding * 0.5f;
|
||||
|
||||
var islandCellOrigin = new Vector2[islandCount];
|
||||
var islandScale = new float[islandCount];
|
||||
for (int i = 0; i < islandCount; i++)
|
||||
{
|
||||
int col = i % gridSize;
|
||||
int row = i / gridSize;
|
||||
islandCellOrigin[i] = new Vector2(col * cellSize, row * cellSize);
|
||||
|
||||
float span = Mathf.Max(Mathf.Max(islandMaxU[i] - islandMinU[i], islandMaxV[i] - islandMinV[i]), 1e-5f);
|
||||
float usableCell = cellSize - cellPad * 2f;
|
||||
islandScale[i] = usableCell / span;
|
||||
}
|
||||
|
||||
var newVerts = new List<Vector3>();
|
||||
var newNormals = new List<Vector3>();
|
||||
var newUvMask = new List<Vector2>();
|
||||
var newUvTile = new List<Vector2>();
|
||||
var subTriangleLists = new List<int>[subMeshCount];
|
||||
for (int s = 0; s < subMeshCount; s++) subTriangleLists[s] = new List<int>();
|
||||
|
||||
for (int t = 0; t < triCount; t++)
|
||||
{
|
||||
int island = islandOf[t];
|
||||
|
||||
Vector2 MapAtlas(Vector3 local)
|
||||
{
|
||||
Vector2 uv = ProjectUV(local, islandAxisU[island], islandAxisV[island]);
|
||||
Vector2 norm = new Vector2(uv.x - islandMinU[island], uv.y - islandMinV[island]) *
|
||||
islandScale[island];
|
||||
return islandCellOrigin[island] + new Vector2(cellPad, cellPad) + norm;
|
||||
}
|
||||
|
||||
int i0 = triI0[t], i1 = triI1[t], i2 = triI2[t];
|
||||
Vector3 p0 = srcVerts[i0], p1 = srcVerts[i1], p2 = srcVerts[i2];
|
||||
|
||||
int baseIndex = newVerts.Count;
|
||||
newVerts.Add(p0);
|
||||
newVerts.Add(p1);
|
||||
newVerts.Add(p2);
|
||||
newNormals.Add(hasNormals ? srcNormals[i0] : triNormal[t]);
|
||||
newNormals.Add(hasNormals ? srcNormals[i1] : triNormal[t]);
|
||||
newNormals.Add(hasNormals ? srcNormals[i2] : triNormal[t]);
|
||||
|
||||
newUvMask.Add(MapAtlas(p0));
|
||||
newUvMask.Add(MapAtlas(p1));
|
||||
newUvMask.Add(MapAtlas(p2));
|
||||
|
||||
newUvTile.Add(hasUvTile ? srcUvTile[i0] : Vector2.zero);
|
||||
newUvTile.Add(hasUvTile ? srcUvTile[i1] : Vector2.zero);
|
||||
newUvTile.Add(hasUvTile ? srcUvTile[i2] : Vector2.zero);
|
||||
|
||||
int subMesh = triSubMesh[t];
|
||||
subTriangleLists[subMesh].Add(baseIndex);
|
||||
subTriangleLists[subMesh].Add(baseIndex + 1);
|
||||
subTriangleLists[subMesh].Add(baseIndex + 2);
|
||||
}
|
||||
|
||||
mesh.Clear();
|
||||
mesh.indexFormat = newVerts.Count > 65000
|
||||
? UnityEngine.Rendering.IndexFormat.UInt32
|
||||
: UnityEngine.Rendering.IndexFormat.UInt16;
|
||||
mesh.SetVertices(newVerts);
|
||||
mesh.SetNormals(newNormals);
|
||||
mesh.SetUVs(0, newUvMask);
|
||||
mesh.SetUVs(2, newUvTile);
|
||||
mesh.subMeshCount = subMeshCount;
|
||||
for (int s = 0; s < subMeshCount; s++)
|
||||
mesh.SetTriangles(subTriangleLists[s], s);
|
||||
|
||||
mesh.RecalculateBounds();
|
||||
if (!hasNormals) mesh.RecalculateNormals();
|
||||
mesh.RecalculateTangents();
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Unwrapping.GenerateSecondaryUVSet(mesh);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a09905e536314ef1bd4c016d3b5cfb76
|
||||
timeCreated: 1785923052
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using R3;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning
|
||||
{
|
||||
public interface ICleaningService
|
||||
{
|
||||
}
|
||||
|
||||
public class CleaningService : IDisposable, ICleaningService
|
||||
{
|
||||
private List<Cleanable> _cleanableSurfaces = new();
|
||||
|
||||
private IDisposable _surfaces;
|
||||
|
||||
public ReactiveProperty<bool> LevelCleaned { get; } = new();
|
||||
|
||||
public CleaningService(Cleanable[] cleanableSurfaces)
|
||||
{
|
||||
DisposableBuilder builder = new DisposableBuilder();
|
||||
|
||||
foreach (var cleanable in cleanableSurfaces)
|
||||
{
|
||||
_cleanableSurfaces.Add(cleanable);
|
||||
builder.Add(cleanable.Cleaned
|
||||
.Subscribe(x => CheckProgress(cleanable)));
|
||||
}
|
||||
|
||||
_surfaces = builder.Build();
|
||||
}
|
||||
|
||||
private void CheckProgress(Cleanable cleanable)
|
||||
{
|
||||
if(cleanable.Cleaned.CurrentValue) Debug.Log($"{cleanable.name} cleaned");
|
||||
|
||||
CheckOverallProgress();
|
||||
}
|
||||
|
||||
private void CheckOverallProgress()
|
||||
{
|
||||
if (LevelCleaned.CurrentValue)
|
||||
return;
|
||||
|
||||
foreach (var t in _cleanableSurfaces)
|
||||
if (!t.Cleaned.CurrentValue) return;
|
||||
|
||||
Debug.Log($"VICTORY!!!");
|
||||
LevelCleaned.Value = true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_surfaces?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5ce468dffcf438d98691a527f9c51ba
|
||||
timeCreated: 1785923122
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a45200a1a0d48beaea636b4b794ed95
|
||||
timeCreated: 1785925560
|
||||
@@ -0,0 +1,85 @@
|
||||
Shader "Unlit/BrushPainter"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_DrawPosition("Draw Position", Vector) = (0.5, 0.5, 0, 0)
|
||||
_DrawRadius("Draw Radius", Float) = 0.05
|
||||
_DrawAngleX("Draw Angle (Rad) X", Float) = 0.0
|
||||
_DrawAngleY("Draw Angle (Rad) Y", Float) = 0.0
|
||||
_ToolDirtiness("Tool Dirtiness", Range(0, 1)) = 0
|
||||
[MainTexture] _BrushTex("Brush Texture", 2D) = "white" {}
|
||||
}
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags
|
||||
{
|
||||
"RenderType" = "Transparent"
|
||||
"Queue" = "Transparent"
|
||||
}
|
||||
|
||||
Pass
|
||||
{
|
||||
Blend SrcAlpha OneMinusSrcAlpha
|
||||
ZWrite Off
|
||||
ZTest Always
|
||||
|
||||
HLSLPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
|
||||
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
|
||||
|
||||
struct Attributes
|
||||
{
|
||||
float4 positionOS : POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct Varyings
|
||||
{
|
||||
float4 positionHCS : SV_POSITION;
|
||||
float2 uv : TEXCOORD0;
|
||||
};
|
||||
|
||||
float4 _DrawPosition;
|
||||
float _DrawRadius;
|
||||
float _DrawAngleX;
|
||||
float _DrawAngleY;
|
||||
float _ToolDirtiness;
|
||||
|
||||
TEXTURE2D(_BrushTex);
|
||||
SAMPLER(sampler_BrushTex);
|
||||
|
||||
Varyings vert(Attributes IN)
|
||||
{
|
||||
Varyings OUT;
|
||||
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
|
||||
OUT.uv = IN.uv;
|
||||
return OUT;
|
||||
}
|
||||
|
||||
half4 frag(Varyings IN) : SV_Target
|
||||
{
|
||||
float2 centeredUV = (IN.uv - _DrawPosition.xy) / (_DrawRadius * 2.0);
|
||||
|
||||
float2 rotatedUV;
|
||||
rotatedUV.x = centeredUV.x * _DrawAngleX - centeredUV.y * _DrawAngleY;
|
||||
rotatedUV.y = centeredUV.x * _DrawAngleY + centeredUV.y * _DrawAngleX;
|
||||
|
||||
float2 brushUV = rotatedUV + 0.5;
|
||||
|
||||
float inBounds = step(0.0, brushUV.x) * step(brushUV.x, 1.0) *
|
||||
step(0.0, brushUV.y) * step(brushUV.y, 1.0);
|
||||
|
||||
half4 brushColor = SAMPLE_TEXTURE2D(_BrushTex, sampler_BrushTex, brushUV);
|
||||
|
||||
float brushMask = brushColor.a * inBounds;
|
||||
float fillValue = _ToolDirtiness * brushMask;
|
||||
|
||||
return half4(fillValue, fillValue, fillValue, brushMask);
|
||||
}
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 31f42842d3a8460ea125575cb5a72a5a
|
||||
timeCreated: 1785925570
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5e608514d754bcfb44c3df7c722601d
|
||||
timeCreated: 1786025274
|
||||
@@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.UI
|
||||
{
|
||||
public abstract class CleanToolWidget : MonoBehaviour
|
||||
{
|
||||
public abstract void SetToolDirtiness(float dirtiness);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 95907fda6bb942a1865c6f1d9a6c1f91
|
||||
timeCreated: 1786025360
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Code.D.Cleaning.CleanTools;
|
||||
using Code.Infrastructure.UI;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Cleaning.UI
|
||||
{
|
||||
public class CleaningPanel : UIPanel
|
||||
{
|
||||
[Inject]
|
||||
private void Construct(List<CleanTool> cleanTools)
|
||||
{
|
||||
Debug.Log("InjectingPanel");
|
||||
|
||||
foreach (var cleanTool in cleanTools) Debug.Log(cleanTool);
|
||||
}
|
||||
|
||||
public override UniTask Open(CancellationToken cts = default)
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override UniTask Close(CancellationToken cts = default)
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f7be6d67e6944899ab2c3ae0255b58e
|
||||
timeCreated: 1786025297
|
||||
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Code.D.Cleaning.CleanTools;
|
||||
using R3;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Code.D.Cleaning.UI
|
||||
{
|
||||
public class TryapkaWidget : CleanToolWidget
|
||||
{
|
||||
[SerializeField] private Image toolImage;
|
||||
[SerializeField] private Color cleanToolColor;
|
||||
[SerializeField] private Color dirtyToolColor;
|
||||
|
||||
private IDisposable _disposable;
|
||||
|
||||
[Inject]
|
||||
private void Construct(List<CleanTool> cleanTools)
|
||||
{
|
||||
Debug.Log("InjectingWidget");
|
||||
|
||||
var tool = cleanTools.SingleOrDefault(x => x.ToolType == CleanToolType.Tryapka);
|
||||
|
||||
if (tool == null) return;
|
||||
|
||||
_disposable = tool.CurrentDirtiness
|
||||
.Subscribe(SetToolDirtiness);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_disposable?.Dispose();
|
||||
}
|
||||
|
||||
public override void SetToolDirtiness(float dirtiness)
|
||||
{
|
||||
toolImage.color = Color.Lerp(cleanToolColor, dirtyToolColor, dirtiness);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6cbf9cd4573e4544a67318da5d5fa072
|
||||
timeCreated: 1786025415
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9891a4d4490a4d35ab073ab28b4d0c25
|
||||
timeCreated: 1785846398
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Camera.CameraStates;
|
||||
using Code.Infrastructure.Generators;
|
||||
using Code.Infrastructure.Input;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using R3;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Code.Game.Gameplay.Player
|
||||
{
|
||||
[State(typeof(CameraMode),typeof(CameraStateMachineContext), ManualInherit = true)]
|
||||
public partial class CleanerCameraState : BaseCameraState
|
||||
{
|
||||
public void SetTarget(Transform target)
|
||||
{
|
||||
_target = target;
|
||||
Context.cameraLoadedData.Camera.transform.position = _target.position;
|
||||
Context.cameraLoadedData.Camera.transform.rotation = _target.rotation;
|
||||
}
|
||||
|
||||
private IDisposable _disposable;
|
||||
public void SetPlayer(PlayerMovementController playerMovementController)
|
||||
{
|
||||
_disposable = playerMovementController.IsSliding.Subscribe(SlideToggle);
|
||||
}
|
||||
|
||||
private void SlideToggle(bool isSliding) => _isSliding = isSliding;
|
||||
|
||||
private Transform _target;
|
||||
private Vector2 _mouseDelta;
|
||||
private Vector2 _rotation = Vector2.zero;
|
||||
|
||||
private float _sensitivityX = 0.1f;
|
||||
private float _sensitivityY = 0.1f;
|
||||
private float _slideStupidity = 1f;
|
||||
private bool _isSliding;
|
||||
|
||||
public CleanerCameraState(CameraStateMachineContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
private void LookCancelled(InputAction.CallbackContext obj) => _mouseDelta = Vector2.zero;
|
||||
private void LookPerformed(InputAction.CallbackContext obj) => _mouseDelta = obj.ReadValue<Vector2>();
|
||||
|
||||
public override CameraMode MyState => CameraMode.Cleaner;
|
||||
|
||||
public override UniTask EnterState()
|
||||
{
|
||||
Context.InputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookPerformed);
|
||||
Context.InputService.BindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookCancelled);
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override UniTask ExitState()
|
||||
{
|
||||
Context.InputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookPerformed);
|
||||
Context.InputService.UnbindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Watchment, LookCancelled);
|
||||
_disposable.Dispose();
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
}
|
||||
|
||||
public override void LateUpdate()
|
||||
{
|
||||
if (_target is null) return;
|
||||
|
||||
var camTransform = Context.cameraLoadedData.Camera.transform;
|
||||
|
||||
camTransform.position = _target.position;
|
||||
|
||||
var mouseDeltaX = _mouseDelta.x * _sensitivityX;
|
||||
var mouseDeltaY = _mouseDelta.y * _sensitivityY;
|
||||
|
||||
if (_isSliding)
|
||||
{
|
||||
mouseDeltaX = Mathf.Clamp(mouseDeltaX, -_slideStupidity, _slideStupidity);
|
||||
mouseDeltaY = Mathf.Clamp(mouseDeltaY, -_slideStupidity, _slideStupidity);
|
||||
}
|
||||
|
||||
_rotation.x += mouseDeltaX;
|
||||
_rotation.y -= mouseDeltaY;
|
||||
|
||||
_rotation.y = Mathf.Clamp(_rotation.y, -90f, 90f);
|
||||
|
||||
camTransform.localRotation = Quaternion.Euler(_rotation.y, _rotation.x, 0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e592628c3fe45bf9659d1050680c296
|
||||
timeCreated: 1785846388
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9b8ea0290514b809c83dd30d68391ca
|
||||
timeCreated: 1785846388
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using Code.Infrastructure.Utils;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Reflex.Attributes;
|
||||
using Reflex.Core;
|
||||
using Reflex.Injectors;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace Code.Game.Gameplay.Player.Factory
|
||||
{
|
||||
public interface IPlayerFactory
|
||||
{
|
||||
UniTask<GameObject> CreatePlayer();
|
||||
void InjectPlayer(Container container);
|
||||
}
|
||||
|
||||
public class PlayerFactory : IDisposable, IPlayerFactory
|
||||
{
|
||||
private readonly SingleConfig<PlayerFactorySettings> _config;
|
||||
|
||||
private GameObject _playerInstance;
|
||||
|
||||
public PlayerFactory(SingleConfig<PlayerFactorySettings> config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
public async UniTask<GameObject> CreatePlayer()
|
||||
{
|
||||
_playerInstance ??= await Addressables.InstantiateAsync(_config.Config.Player).ToUniTask();
|
||||
|
||||
return _playerInstance;
|
||||
}
|
||||
|
||||
public void InjectPlayer(Container container)
|
||||
{
|
||||
GameObjectInjector.InjectRecursive(_playerInstance, container);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Addressables.ReleaseInstance(_playerInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdc8848de9734ba3bb1c3e3ec81145e6
|
||||
timeCreated: 1778956904
|
||||
@@ -0,0 +1,13 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace Code.Game.Gameplay.Player.Factory
|
||||
{
|
||||
[Config("Configs/Gameplay/PlayerFactory")]
|
||||
[CreateAssetMenu(fileName = "PlayerFactorySettings", menuName = "Configs/Gameplay/PlayerFactory")]
|
||||
public class PlayerFactorySettings : ScriptableObject
|
||||
{
|
||||
public AssetReference Player;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c312323c8dc049b2b7e7330f54b09aad
|
||||
timeCreated: 1785871572
|
||||
@@ -0,0 +1,13 @@
|
||||
using Code.Infrastructure.Camera;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Game.Gameplay.Player
|
||||
{
|
||||
public class PlayerCameraTarget : MonoBehaviour
|
||||
{
|
||||
[Inject]
|
||||
private void Construct(CameraStateMachine cameraStateMachine) =>
|
||||
((CleanerCameraState)cameraStateMachine.CurrentBaseState).SetTarget(transform);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c579fd0c46544b26b3dd27ecdf36fc37
|
||||
timeCreated: 1785846388
|
||||
@@ -0,0 +1,96 @@
|
||||
using Code.Game.Gameplay.Player;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Input;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Code.Game.Cleaning.Player
|
||||
{
|
||||
public class PlayerControlsProvider : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private PlayerMovementController playerMovementController;
|
||||
|
||||
private IInputService _inputService;
|
||||
|
||||
private Vector2 _movementInput;
|
||||
private bool _jumpDown;
|
||||
private bool _crouchDown;
|
||||
private bool _walkOn;
|
||||
private Transform _cameraTransform;
|
||||
|
||||
[Inject]
|
||||
private void Construct(IInputService inputService, CameraStateMachine cameraStateMachine)
|
||||
{
|
||||
_cameraTransform = cameraStateMachine.Camera.transform;
|
||||
_inputService = inputService;
|
||||
|
||||
_inputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Movement,
|
||||
MovementPerformed);
|
||||
_inputService.BindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Movement,
|
||||
MovementCancelled);
|
||||
|
||||
_inputService.BindActionPerformed((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Jump, JumpPerformed);
|
||||
_inputService.BindActionCancelled((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Jump, JumpCancelled);
|
||||
|
||||
_inputService.BindActionPerformed((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Walk, WalkPerformed);
|
||||
|
||||
_inputService.BindActionPerformed((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Crouch, CrouchPerformed);
|
||||
_inputService.BindActionCancelled((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Crouch, CrouchCancelled);
|
||||
}
|
||||
|
||||
private void CrouchPerformed(InputAction.CallbackContext obj) => _crouchDown = true;
|
||||
private void CrouchCancelled(InputAction.CallbackContext obj) => _crouchDown = false;
|
||||
|
||||
private void WalkPerformed(InputAction.CallbackContext obj) => _walkOn = !_walkOn;
|
||||
private void JumpCancelled(InputAction.CallbackContext obj) => _jumpDown = false;
|
||||
private void JumpPerformed(InputAction.CallbackContext obj) => _jumpDown = true;
|
||||
|
||||
private void MovementCancelled(InputAction.CallbackContext obj) => _movementInput = Vector2.zero;
|
||||
private void MovementPerformed(InputAction.CallbackContext obj) => _movementInput = obj.ReadValue<Vector2>();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!_cameraTransform) return;
|
||||
|
||||
var inputs = new PlayerCharacterInputs()
|
||||
{
|
||||
MoveAxisForward = _movementInput.y,
|
||||
MoveAxisRight = _movementInput.x,
|
||||
CameraRotation = _cameraTransform.rotation,
|
||||
JumpDown = _jumpDown,
|
||||
CrouchDown = _crouchDown,
|
||||
CrouchUp = !_crouchDown,
|
||||
WalkOn = _walkOn
|
||||
};
|
||||
|
||||
playerMovementController.SetInputs(ref inputs);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Movement,
|
||||
MovementPerformed);
|
||||
_inputService.UnbindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Movement,
|
||||
MovementCancelled);
|
||||
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Jump, JumpPerformed);
|
||||
_inputService.UnbindActionCancelled((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Jump, JumpCancelled);
|
||||
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Walk, WalkPerformed);
|
||||
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Crouch, CrouchPerformed);
|
||||
_inputService.UnbindActionCancelled((int)ActionMappings.Cleaning,
|
||||
(int)CleaningActions.Crouch, CrouchCancelled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75c0d109df244d6ebf8c0eb976553c6a
|
||||
timeCreated: 1785846388
|
||||
@@ -0,0 +1,114 @@
|
||||
using Code.D.Cleaning;
|
||||
using Code.D.Player;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Input;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using R3;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Code.Game.Gameplay.Player
|
||||
{
|
||||
public class PlayerDetailMaskDrawer : MonoBehaviour
|
||||
{
|
||||
private IInputService _inputService;
|
||||
private Transform _cameraTransform;
|
||||
|
||||
private bool _cleaning, _cleaningUnder;
|
||||
|
||||
private LayerMask _layerMask;
|
||||
private TagHandle _surfaceTag;
|
||||
|
||||
private CleanableSurface _lastCleaned;
|
||||
[SerializeField] private float cleaningDistance = 5f;
|
||||
[SerializeField] private PlayerEquipment playerEquipment;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_surfaceTag = TagHandle.GetExistingTag("CleanableSurface");
|
||||
_layerMask = LayerMask.GetMask("Cleanable");
|
||||
|
||||
GetComponent<PlayerMovementController>().IsSliding.Subscribe(SlideToggle).AddTo(destroyCancellationToken);
|
||||
}
|
||||
|
||||
[Inject]
|
||||
private void Construct(IInputService inputService, CameraStateMachine cameraStateMachine)
|
||||
{
|
||||
_cameraTransform = cameraStateMachine.Camera.transform;
|
||||
_inputService = inputService;
|
||||
|
||||
_inputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Clean, DrawPerformed);
|
||||
_inputService.BindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Clean, DrawCancelled);
|
||||
}
|
||||
|
||||
private void SlideToggle(bool isSliding) => _cleaningUnder = isSliding;
|
||||
|
||||
private void DrawPerformed(InputAction.CallbackContext obj) => _cleaning = true;
|
||||
|
||||
private void DrawCancelled(InputAction.CallbackContext obj) => _cleaning = false;
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
if (_cleaning) CleanInFront();
|
||||
if (_cleaningUnder) CleanUnder();
|
||||
}
|
||||
|
||||
private void CleanUnder()
|
||||
{
|
||||
if (!Physics.Raycast(
|
||||
_cameraTransform.position,
|
||||
-transform.up,
|
||||
out var info,
|
||||
5f,
|
||||
layerMask: _layerMask)) return;
|
||||
|
||||
if (info.collider.CompareTag(_surfaceTag))
|
||||
CleanSurface(info);
|
||||
}
|
||||
|
||||
private void CleanInFront()
|
||||
{
|
||||
if (!Physics.Raycast(
|
||||
_cameraTransform.position,
|
||||
_cameraTransform.forward,
|
||||
out var info,
|
||||
cleaningDistance,
|
||||
layerMask: _layerMask)) return;
|
||||
|
||||
if (info.collider.CompareTag(_surfaceTag))
|
||||
CleanSurface(info);
|
||||
else
|
||||
CleanAsset(info);
|
||||
}
|
||||
|
||||
private void CleanAsset(RaycastHit info)
|
||||
{
|
||||
var cleanable = info.collider.GetComponent<CleanableAsset>();
|
||||
|
||||
cleanable.Clean();
|
||||
}
|
||||
|
||||
private void CleanSurface(RaycastHit info)
|
||||
{
|
||||
CleanableSurface cleanable;
|
||||
if (_lastCleaned is not null && info.collider.GetEntityId() == _lastCleaned.GetEntityId())
|
||||
cleanable = _lastCleaned;
|
||||
else
|
||||
{
|
||||
cleanable = info.collider.GetComponent<CleanableSurface>();
|
||||
_lastCleaned = cleanable;
|
||||
}
|
||||
|
||||
cleanable.Clean(info, playerEquipment.CurrentTool.Use(), _cameraTransform);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Clean,
|
||||
DrawPerformed);
|
||||
_inputService.UnbindActionCancelled((int)ActionMappings.Cleaning, (int)CleaningActions.Clean,
|
||||
DrawCancelled);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f1606bdb9e6840f5960df117e5298061
|
||||
timeCreated: 1785923251
|
||||
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Code.D.Cleaning.CleanTools;
|
||||
using R3;
|
||||
using Reflex.Attributes;
|
||||
using Unity.Burst;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.D.Player
|
||||
{
|
||||
public class PlayerEquipment : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Texture2D tryapkaBrushTexture;
|
||||
public CleanTool CurrentTool { get; private set; }
|
||||
private Dictionary<CleanToolType, CleanTool> _cleanTools = new();
|
||||
public ReactiveProperty<CleanToolType> CurrentToolType { get; } = new();
|
||||
|
||||
private IDisposable _dirtinessDisposable;
|
||||
|
||||
[Inject]
|
||||
private void Construct(List<CleanTool> cleanTools)
|
||||
{
|
||||
foreach (var cleanTool in cleanTools) _cleanTools.Add(cleanTool.ToolType, cleanTool);
|
||||
|
||||
var firstTool = _cleanTools.First();
|
||||
CurrentToolType.Value = firstTool.Key;
|
||||
CurrentTool = firstTool.Value;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
//CurrentTool = new Tryapka(0.0001f, 0.005f, tryapkaBrushTexture);
|
||||
//
|
||||
// DisposableBuilder builder = new DisposableBuilder();
|
||||
// // Я безумец, здесь подписаться на все сразу
|
||||
// builder.Add(CurrentTool.CurrentDirtiness.Subscribe(x => CurrentToolDirtiness.Value =
|
||||
// new ToolDirtinessData
|
||||
// {
|
||||
// Dirtiness = x,
|
||||
// ToolType = CleanToolType.Tryapka
|
||||
// }
|
||||
// ));
|
||||
//
|
||||
// _dirtinessDisposable = builder.Build();
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_dirtinessDisposable?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public struct ToolDirtinessData : IEquatable<ToolDirtinessData>
|
||||
{
|
||||
public float Dirtiness;
|
||||
public CleanToolType ToolType;
|
||||
|
||||
public bool Equals(ToolDirtinessData other)
|
||||
{
|
||||
return Mathf.Approximately(Dirtiness, other.Dirtiness) && ToolType == other.ToolType;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is ToolDirtinessData other && Equals(other);
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(Dirtiness, ToolType);
|
||||
}
|
||||
|
||||
public static bool operator ==(ToolDirtinessData left, ToolDirtinessData right) => left.Equals(right);
|
||||
public static bool operator !=(ToolDirtinessData left, ToolDirtinessData right) => !left.Equals(right);
|
||||
}
|
||||
|
||||
public struct ToolDirtyData : IEquatable<ToolDirtyData>
|
||||
{
|
||||
public CleanToolType ToolType;
|
||||
|
||||
public bool Equals(ToolDirtyData other)
|
||||
{
|
||||
return ToolType == other.ToolType;
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is ToolDirtyData other && Equals(other);
|
||||
}
|
||||
|
||||
[BurstDiscard]
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ToolType.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(ToolDirtyData left, ToolDirtyData right) => left.Equals(right);
|
||||
public static bool operator !=(ToolDirtyData left, ToolDirtyData right) => !left.Equals(right);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ba4e659f17b147db992374aab735ed4c
|
||||
timeCreated: 1785940207
|
||||
@@ -0,0 +1,64 @@
|
||||
using Code.D.Cleaning.CleanTools;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Input;
|
||||
using Reflex.Attributes;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
namespace Code.D.Player
|
||||
{
|
||||
public class PlayerInteractor : MonoBehaviour
|
||||
{
|
||||
private IInputService _inputService;
|
||||
private LayerMask _cleanToolInteractableMask;
|
||||
private Transform _cameraTransform;
|
||||
private CleanToolInteractable _lastCleanToolInteractable;
|
||||
|
||||
[SerializeField] private float interactionDistance = 5f;
|
||||
[SerializeField] private PlayerEquipment playerEquipment;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_cleanToolInteractableMask = LayerMask.GetMask("CleanToolInteractable");
|
||||
}
|
||||
|
||||
[Inject]
|
||||
private void Construct(IInputService inputService, CameraStateMachine cameraStateMachine)
|
||||
{
|
||||
_cameraTransform = cameraStateMachine.Camera.transform;
|
||||
|
||||
_inputService = inputService;
|
||||
inputService.BindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Interact, TryInteract);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
_inputService.UnbindActionPerformed((int)ActionMappings.Cleaning, (int)CleaningActions.Interact,
|
||||
TryInteract);
|
||||
}
|
||||
|
||||
private void TryInteract(InputAction.CallbackContext obj)
|
||||
{
|
||||
if (!Physics.Raycast(
|
||||
_cameraTransform.position,
|
||||
_cameraTransform.forward,
|
||||
out var info,
|
||||
interactionDistance,
|
||||
layerMask: _cleanToolInteractableMask)) return;
|
||||
|
||||
CleanToolInteractable interactable;
|
||||
if (_lastCleanToolInteractable is not null &&
|
||||
info.collider.GetEntityId() == _lastCleanToolInteractable.GetEntityId())
|
||||
{
|
||||
interactable = _lastCleanToolInteractable;
|
||||
}
|
||||
else
|
||||
{
|
||||
interactable = info.collider.gameObject.GetComponent<CleanToolInteractable>();
|
||||
_lastCleanToolInteractable = interactable;
|
||||
}
|
||||
|
||||
interactable.Use(playerEquipment.CurrentTool);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 997fa523ddda4b1ea3f4b0b1e1e7864a
|
||||
timeCreated: 1785939712
|
||||
@@ -0,0 +1,644 @@
|
||||
using System.Collections.Generic;
|
||||
using Alchemy.Inspector;
|
||||
using KinematicCharacterController;
|
||||
using LitMotion;
|
||||
using LitMotion.Extensions;
|
||||
using R3;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Game.Gameplay.Player
|
||||
{
|
||||
public enum CharacterState
|
||||
{
|
||||
Default,
|
||||
Sliding
|
||||
}
|
||||
|
||||
public enum OrientationMethod
|
||||
{
|
||||
TowardsCamera,
|
||||
TowardsMovement,
|
||||
}
|
||||
|
||||
public struct PlayerCharacterInputs
|
||||
{
|
||||
public float MoveAxisForward;
|
||||
public float MoveAxisRight;
|
||||
public Quaternion CameraRotation;
|
||||
public bool JumpDown;
|
||||
public bool CrouchDown;
|
||||
public bool CrouchUp;
|
||||
public bool WalkOn;
|
||||
}
|
||||
|
||||
public struct AICharacterInputs
|
||||
{
|
||||
public Vector3 MoveVector;
|
||||
public Quaternion Look;
|
||||
}
|
||||
|
||||
public enum BonusOrientationMethod
|
||||
{
|
||||
None,
|
||||
TowardsGravity,
|
||||
TowardsGroundSlopeAndGravity,
|
||||
}
|
||||
|
||||
public class PlayerMovementController : MonoBehaviour, ICharacterController
|
||||
{
|
||||
public KinematicCharacterMotor Motor;
|
||||
|
||||
[TabGroup("Stable Movement")] public float MaxStableMoveSpeed = 10f;
|
||||
[TabGroup("Stable Movement")] public float SprintingModifier = 2f;
|
||||
[TabGroup("Stable Movement")] public float StableMovementSharpness = 15f;
|
||||
[TabGroup("Stable Movement")] public float OrientationSharpness = 10f;
|
||||
[TabGroup("Stable Movement")] public OrientationMethod OrientationMethod = OrientationMethod.TowardsCamera;
|
||||
|
||||
[TabGroup("Sliding")] public AnimationCurve SlideSpeedMultiplierCurve;
|
||||
[TabGroup("Sliding")] public float SlideSpeedCurveStep = 0.1f;
|
||||
[TabGroup("Sliding")] public float MaxCrouchMoveSpeed = 5f;
|
||||
[TabGroup("Sliding")] public float InCrouchTime = 1f;
|
||||
[TabGroup("Sliding")] public float OutCrouchTime = 1f;
|
||||
[TabGroup("Sliding")] public float SlideStupidity = 0.1f;
|
||||
|
||||
[TabGroup("Air Movement")] public float MaxAirMoveSpeed = 15f;
|
||||
[TabGroup("Air Movement")] public float AirAccelerationSpeed = 15f;
|
||||
[TabGroup("Air Movement")] public float Drag = 0.1f;
|
||||
|
||||
[TabGroup("Jumping")] public bool AllowJumpingWhenSliding = false;
|
||||
[TabGroup("Jumping")] public float JumpUpSpeed = 10f;
|
||||
[TabGroup("Jumping")] public float JumpScalableForwardSpeed = 10f;
|
||||
[TabGroup("Jumping")] public float JumpPreGroundingGraceTime = 0f;
|
||||
[TabGroup("Jumping")] public float JumpPostGroundingGraceTime = 0f;
|
||||
[TabGroup("Jumping")] public BonusOrientationMethod BonusOrientationMethod = BonusOrientationMethod.None;
|
||||
[TabGroup("Jumping")] public float BonusOrientationSharpness = 10f;
|
||||
[TabGroup("Jumping")] public float BonusOrientationGravitySharpness;
|
||||
[TabGroup("Jumping")] public Vector3 Gravity = new Vector3(0, -30f, 0);
|
||||
|
||||
[TabGroup("Misc")] public List<Collider> IgnoredColliders = new List<Collider>();
|
||||
[TabGroup("Misc")] public Transform cameraTransform;
|
||||
[TabGroup("Misc")] public float CrouchedCapsuleHeight = 1f;
|
||||
public CharacterState CurrentCharacterState { get; private set; }
|
||||
public Vector3 CurrentVelocity => Motor.Velocity;
|
||||
public Quaternion CurrentRotation => Motor.TransientRotation;
|
||||
|
||||
private Collider[] _probedColliders = new Collider[8];
|
||||
private RaycastHit[] _probedHits = new RaycastHit[8];
|
||||
private Vector3 _moveInputVector;
|
||||
private Vector3 _lookInputVector;
|
||||
private bool _jumpRequested = false;
|
||||
private bool _jumpConsumed = false;
|
||||
private bool _jumpedThisFrame = false;
|
||||
private float _timeSinceJumpRequested = Mathf.Infinity;
|
||||
private float _timeSinceLastAbleToJump = 0f;
|
||||
private Vector3 _internalVelocityAdd = Vector3.zero;
|
||||
private bool _shouldBeCrouching = false;
|
||||
private bool _isCrouching = false;
|
||||
public ReactiveProperty<bool> IsSliding { get; } = new();
|
||||
private bool _isSliding = false;
|
||||
private float _slideCurveProgress;
|
||||
private bool _isSlideEnded = false;
|
||||
private bool _isSprinting = false;
|
||||
|
||||
private Vector3 lastInnerNormal = Vector3.zero;
|
||||
private Vector3 lastOuterNormal = Vector3.zero;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
// Handle initial state
|
||||
TransitionToState(CharacterState.Default);
|
||||
|
||||
// Assign the characterController to the motor
|
||||
Motor.CharacterController = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles movement state transitions and enter/exit callbacks
|
||||
/// </summary>
|
||||
public void TransitionToState(CharacterState newState)
|
||||
{
|
||||
CharacterState tmpInitialState = CurrentCharacterState;
|
||||
OnStateExit(tmpInitialState, newState);
|
||||
CurrentCharacterState = newState;
|
||||
OnStateEnter(newState, tmpInitialState);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event when entering a state
|
||||
/// </summary>
|
||||
public void OnStateEnter(CharacterState state, CharacterState fromState)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event when exiting a state
|
||||
/// </summary>
|
||||
public void OnStateExit(CharacterState state, CharacterState toState)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called every frame by ExamplePlayer in order to tell the character what its inputs are
|
||||
/// </summary>
|
||||
public void SetInputs(ref PlayerCharacterInputs inputs)
|
||||
{
|
||||
// Clamp input
|
||||
Vector3 moveInputVector =
|
||||
Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0f, inputs.MoveAxisForward), 1f);
|
||||
|
||||
// Calculate camera direction and rotation on the character plane
|
||||
Vector3 cameraPlanarDirection =
|
||||
Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.forward, Motor.CharacterUp).normalized;
|
||||
if (cameraPlanarDirection.sqrMagnitude == 0f)
|
||||
{
|
||||
cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.CameraRotation * Vector3.up, Motor.CharacterUp)
|
||||
.normalized;
|
||||
}
|
||||
|
||||
Quaternion cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
|
||||
|
||||
switch (CurrentCharacterState)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
if (_isSliding)
|
||||
{
|
||||
moveInputVector.x *= SlideStupidity;
|
||||
}
|
||||
// Move and look inputs
|
||||
_moveInputVector = cameraPlanarRotation * moveInputVector;
|
||||
|
||||
switch (OrientationMethod)
|
||||
{
|
||||
case OrientationMethod.TowardsCamera:
|
||||
_lookInputVector = cameraPlanarDirection;
|
||||
break;
|
||||
case OrientationMethod.TowardsMovement:
|
||||
_lookInputVector = _moveInputVector.normalized;
|
||||
break;
|
||||
}
|
||||
|
||||
// Jumping input
|
||||
if (inputs.JumpDown)
|
||||
{
|
||||
_timeSinceJumpRequested = 0f;
|
||||
_jumpRequested = true;
|
||||
}
|
||||
|
||||
_isSprinting = !inputs.WalkOn;
|
||||
|
||||
// Crouching input
|
||||
if (inputs.CrouchDown)
|
||||
{
|
||||
_shouldBeCrouching = true;
|
||||
|
||||
if (!_isCrouching)
|
||||
{
|
||||
if(_isSprinting && !_isSlideEnded)
|
||||
{
|
||||
_isSliding = true;
|
||||
IsSliding.Value = true;
|
||||
}
|
||||
else _isSlideEnded = true;
|
||||
|
||||
_isCrouching = true;
|
||||
Motor.SetCapsuleDimensions(0.5f, CrouchedCapsuleHeight, CrouchedCapsuleHeight * 0.5f);
|
||||
|
||||
if(_crouchTransition.IsPlaying()) _crouchTransition.Cancel();
|
||||
|
||||
_crouchTransition = LMotion.Create(cameraTransform.localPosition.y, 0.85f, InCrouchTime)
|
||||
.WithEase(Ease.InOutQuad)
|
||||
.BindToLocalPositionY(cameraTransform);
|
||||
}
|
||||
|
||||
}
|
||||
else if (inputs.CrouchUp)
|
||||
{
|
||||
_shouldBeCrouching = false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called every frame by the AI script in order to tell the character what its inputs are
|
||||
/// </summary>
|
||||
public void SetInputs(ref AICharacterInputs inputs)
|
||||
{
|
||||
// _moveInputVector = inputs.MoveVector;
|
||||
// _lookInputVector = inputs.Look;
|
||||
var cameraPlanarDirection =
|
||||
Vector3.ProjectOnPlane(inputs.Look * Vector3.forward, Motor.CharacterUp).normalized;
|
||||
|
||||
if (cameraPlanarDirection.sqrMagnitude == 0f)
|
||||
{
|
||||
cameraPlanarDirection = Vector3.ProjectOnPlane(inputs.Look * Vector3.up, Motor.CharacterUp)
|
||||
.normalized;
|
||||
}
|
||||
|
||||
//var cameraPlanarRotation = Quaternion.LookRotation(cameraPlanarDirection, Motor.CharacterUp);
|
||||
|
||||
_moveInputVector = inputs.MoveVector; // cameraPlanarRotation *
|
||||
_lookInputVector = cameraPlanarDirection;
|
||||
}
|
||||
|
||||
private Quaternion _tmpTransientRot;
|
||||
private MotionHandle _crouchTransition;
|
||||
|
||||
/// <summary>
|
||||
/// (Called by KinematicCharacterMotor during its update cycle)
|
||||
/// This is called before the character begins its movement update
|
||||
/// </summary>
|
||||
public void BeforeCharacterUpdate(float deltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Called by KinematicCharacterMotor during its update cycle)
|
||||
/// This is where you tell your character what its rotation should be right now.
|
||||
/// This is the ONLY place where you should set the character's rotation
|
||||
/// </summary>
|
||||
public void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
|
||||
{
|
||||
switch (CurrentCharacterState)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
if (_lookInputVector.sqrMagnitude > 0f && OrientationSharpness > 0f)
|
||||
{
|
||||
// Smoothly interpolate from current to target look direction
|
||||
|
||||
Vector3 smoothedLookInputDirection = Vector3.Slerp(Motor.CharacterForward, _lookInputVector,
|
||||
1 - Mathf.Exp(-OrientationSharpness * deltaTime)).normalized;
|
||||
|
||||
// Set the current rotation (which will be used by the KinematicCharacterMotor)
|
||||
currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, Motor.CharacterUp);
|
||||
}
|
||||
|
||||
Vector3 currentUp = (currentRotation * Vector3.up);
|
||||
if (BonusOrientationMethod == BonusOrientationMethod.TowardsGravity)
|
||||
{
|
||||
// Rotate from current up to invert gravity
|
||||
Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, -Gravity.normalized,
|
||||
1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime));
|
||||
currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) * currentRotation;
|
||||
}
|
||||
else if (BonusOrientationMethod == BonusOrientationMethod.TowardsGroundSlopeAndGravity)
|
||||
{
|
||||
if (Motor.GroundingStatus.IsStableOnGround)
|
||||
{
|
||||
Vector3 initialCharacterBottomHemiCenter =
|
||||
Motor.TransientPosition + (currentUp * Motor.Capsule.radius);
|
||||
|
||||
Vector3 smoothedGroundNormal = Vector3.Slerp(Motor.CharacterUp,
|
||||
Motor.GroundingStatus.GroundNormal,
|
||||
1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime));
|
||||
currentRotation = Quaternion.FromToRotation(currentUp, smoothedGroundNormal) *
|
||||
currentRotation;
|
||||
|
||||
// Move the position to create a rotation around the bottom hemi center instead of around the pivot
|
||||
Motor.SetTransientPosition(initialCharacterBottomHemiCenter +
|
||||
(currentRotation * Vector3.down * Motor.Capsule.radius));
|
||||
}
|
||||
else
|
||||
{
|
||||
BonusOrientationGravitySharpness = 0.01f;
|
||||
Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, Motor.Velocity.normalized,
|
||||
1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime *
|
||||
BonusOrientationGravitySharpness));
|
||||
// Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, -Gravity.normalized,
|
||||
// 1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime * BonusOrientationGravitySharpness));
|
||||
currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) *
|
||||
currentRotation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Vector3 smoothedGravityDir = Vector3.Slerp(currentUp, Vector3.up,
|
||||
1 - Mathf.Exp(-BonusOrientationSharpness * deltaTime));
|
||||
currentRotation = Quaternion.FromToRotation(currentUp, smoothedGravityDir) * currentRotation;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Called by KinematicCharacterMotor during its update cycle)
|
||||
/// This is where you tell your character what its velocity should be right now.
|
||||
/// This is the ONLY place where you can set the character's velocity
|
||||
/// </summary>
|
||||
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
|
||||
{
|
||||
switch (CurrentCharacterState)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
// Ground movement
|
||||
if (Motor.GroundingStatus.IsStableOnGround)
|
||||
{
|
||||
float currentVelocityMagnitude = currentVelocity.magnitude;
|
||||
|
||||
Vector3 effectiveGroundNormal = Motor.GroundingStatus.GroundNormal;
|
||||
|
||||
// Reorient velocity on slope
|
||||
currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, effectiveGroundNormal) *
|
||||
currentVelocityMagnitude;
|
||||
|
||||
// Calculate target velocity
|
||||
Vector3 inputRight = Vector3.Cross(_moveInputVector, Motor.CharacterUp);
|
||||
|
||||
Vector3 reorientedInput = Vector3.Cross(effectiveGroundNormal, inputRight).normalized *
|
||||
_moveInputVector.magnitude;
|
||||
|
||||
Vector3 targetMovementVelocity;
|
||||
|
||||
switch (_isCrouching)
|
||||
{
|
||||
case true when _isSliding && !_isSlideEnded:
|
||||
{
|
||||
_slideCurveProgress += deltaTime;
|
||||
|
||||
var slideMultiplier = SlideSpeedMultiplierCurve
|
||||
.Evaluate(_slideCurveProgress * SlideSpeedCurveStep);
|
||||
targetMovementVelocity = reorientedInput * (MaxStableMoveSpeed * slideMultiplier);
|
||||
|
||||
if (_slideCurveProgress >= 1f) _isSlideEnded = true;
|
||||
break;
|
||||
}
|
||||
case true:
|
||||
targetMovementVelocity = reorientedInput * MaxCrouchMoveSpeed;
|
||||
break;
|
||||
default:
|
||||
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_isSprinting) targetMovementVelocity *= SprintingModifier;
|
||||
|
||||
// Smooth movement Velocity
|
||||
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity,
|
||||
1f - Mathf.Exp(-StableMovementSharpness * deltaTime));
|
||||
}
|
||||
// Air movement
|
||||
else
|
||||
{
|
||||
// Add move input
|
||||
if (_moveInputVector.sqrMagnitude > 0f)
|
||||
{
|
||||
Vector3 addedVelocity = _moveInputVector * (AirAccelerationSpeed * deltaTime);
|
||||
|
||||
Vector3 currentVelocityOnInputsPlane =
|
||||
Vector3.ProjectOnPlane(currentVelocity, Motor.CharacterUp);
|
||||
|
||||
// Limit air velocity from inputs
|
||||
if (currentVelocityOnInputsPlane.magnitude < MaxAirMoveSpeed)
|
||||
{
|
||||
// clamp addedVel to make total vel not exceed max vel on inputs plane
|
||||
Vector3 newTotal = Vector3.ClampMagnitude(currentVelocityOnInputsPlane + addedVelocity,
|
||||
MaxAirMoveSpeed);
|
||||
addedVelocity = newTotal - currentVelocityOnInputsPlane;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure added vel doesn't go in the direction of the already-exceeding velocity
|
||||
if (Vector3.Dot(currentVelocityOnInputsPlane, addedVelocity) > 0f)
|
||||
{
|
||||
addedVelocity = Vector3.ProjectOnPlane(addedVelocity,
|
||||
currentVelocityOnInputsPlane.normalized);
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent air-climbing sloped walls
|
||||
if (Motor.GroundingStatus.FoundAnyGround)
|
||||
{
|
||||
if (Vector3.Dot(currentVelocity + addedVelocity, addedVelocity) > 0f)
|
||||
{
|
||||
Vector3 perpenticularObstructionNormal = Vector3
|
||||
.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal),
|
||||
Motor.CharacterUp).normalized;
|
||||
addedVelocity =
|
||||
Vector3.ProjectOnPlane(addedVelocity, perpenticularObstructionNormal);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply added velocity
|
||||
currentVelocity += addedVelocity;
|
||||
}
|
||||
|
||||
// Gravity
|
||||
currentVelocity += Gravity * deltaTime;
|
||||
|
||||
// Drag
|
||||
currentVelocity *= (1f / (1f + (Drag * deltaTime)));
|
||||
}
|
||||
|
||||
// Handle jumping
|
||||
_jumpedThisFrame = false;
|
||||
_timeSinceJumpRequested += deltaTime;
|
||||
if (_jumpRequested)
|
||||
{
|
||||
// See if we actually are allowed to jump
|
||||
if (!_jumpConsumed &&
|
||||
((AllowJumpingWhenSliding
|
||||
? Motor.GroundingStatus.FoundAnyGround
|
||||
: Motor.GroundingStatus.IsStableOnGround) ||
|
||||
_timeSinceLastAbleToJump <= JumpPostGroundingGraceTime))
|
||||
{
|
||||
// Calculate jump direction before ungrounding
|
||||
Vector3 jumpDirection = Motor.CharacterUp;
|
||||
if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround)
|
||||
{
|
||||
jumpDirection = Motor.GroundingStatus.GroundNormal;
|
||||
}
|
||||
|
||||
// Makes the character skip ground probing/snapping on its next update.
|
||||
// If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see.
|
||||
Motor.ForceUnground();
|
||||
|
||||
// Add to the return velocity and reset jump state
|
||||
currentVelocity += (jumpDirection * JumpUpSpeed) -
|
||||
Vector3.Project(currentVelocity, Motor.CharacterUp);
|
||||
currentVelocity += (_moveInputVector * JumpScalableForwardSpeed);
|
||||
_jumpRequested = false;
|
||||
_jumpConsumed = true;
|
||||
_jumpedThisFrame = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Take into account additive velocity
|
||||
if (_internalVelocityAdd.sqrMagnitude > 0f)
|
||||
{
|
||||
currentVelocity += _internalVelocityAdd;
|
||||
_internalVelocityAdd = Vector3.zero;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (Called by KinematicCharacterMotor during its update cycle)
|
||||
/// This is called after the character has finished its movement update
|
||||
/// </summary>
|
||||
public void AfterCharacterUpdate(float deltaTime)
|
||||
{
|
||||
switch (CurrentCharacterState)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
// Handle jump-related values
|
||||
{
|
||||
// Handle jumping pre-ground grace period
|
||||
if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime)
|
||||
{
|
||||
_jumpRequested = false;
|
||||
}
|
||||
|
||||
if (AllowJumpingWhenSliding
|
||||
? Motor.GroundingStatus.FoundAnyGround
|
||||
: Motor.GroundingStatus.IsStableOnGround)
|
||||
{
|
||||
// If we're on a ground surface, reset jumping values
|
||||
if (!_jumpedThisFrame)
|
||||
{
|
||||
_jumpConsumed = false;
|
||||
}
|
||||
|
||||
_timeSinceLastAbleToJump = 0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep track of time since we were last able to jump (for grace period)
|
||||
_timeSinceLastAbleToJump += deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isSliding && _isSlideEnded)
|
||||
{
|
||||
_isSliding = false;
|
||||
IsSliding.Value = false;
|
||||
}
|
||||
// Handle uncrouching
|
||||
if (_isCrouching && !_shouldBeCrouching)
|
||||
{
|
||||
// Do an overlap test with the character's standing height to see if there are any obstructions
|
||||
Motor.SetCapsuleDimensions(0.5f, 2f, 1f);
|
||||
if (Motor.CharacterOverlap(
|
||||
Motor.TransientPosition,
|
||||
Motor.TransientRotation,
|
||||
_probedColliders,
|
||||
Motor.CollidableLayers,
|
||||
QueryTriggerInteraction.Ignore) > 0)
|
||||
{
|
||||
// If obstructions, just stick to crouching dimensions
|
||||
Motor.SetCapsuleDimensions(0.5f, CrouchedCapsuleHeight, CrouchedCapsuleHeight * 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no obstructions, uncrouch
|
||||
if(_crouchTransition.IsPlaying()) _crouchTransition.Cancel();
|
||||
|
||||
_crouchTransition = LMotion.Create(cameraTransform.localPosition.y, 1.71f, OutCrouchTime)
|
||||
.WithEase(Ease.InOutQuad)
|
||||
.BindToLocalPositionY(cameraTransform);
|
||||
|
||||
_isCrouching = false;
|
||||
_isSliding = false;
|
||||
IsSliding.Value = false;
|
||||
_isSlideEnded = false;
|
||||
_slideCurveProgress = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PostGroundingUpdate(float deltaTime)
|
||||
{
|
||||
// Handle landing and leaving ground
|
||||
if (Motor.GroundingStatus.IsStableOnGround && !Motor.LastGroundingStatus.IsStableOnGround)
|
||||
{
|
||||
OnLanded();
|
||||
}
|
||||
else if (!Motor.GroundingStatus.IsStableOnGround && Motor.LastGroundingStatus.IsStableOnGround)
|
||||
{
|
||||
OnLeaveStableGround();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsColliderValidForCollisions(Collider coll)
|
||||
{
|
||||
if (IgnoredColliders.Count == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IgnoredColliders.Contains(coll))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
|
||||
ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
|
||||
ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
public void AddVelocity(Vector3 velocity)
|
||||
{
|
||||
switch (CurrentCharacterState)
|
||||
{
|
||||
case CharacterState.Default:
|
||||
{
|
||||
_internalVelocityAdd += velocity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
|
||||
Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
|
||||
{
|
||||
}
|
||||
|
||||
protected void OnLanded()
|
||||
{
|
||||
}
|
||||
|
||||
protected void OnLeaveStableGround()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnDiscreteCollisionDetected(Collider hitCollider)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 45d9830d22b54832ade96a92f599643a
|
||||
timeCreated: 1785846388
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e882a0f0fb5d41f5a1d3b2c41d1f4097
|
||||
timeCreated: 1785874067
|
||||
@@ -0,0 +1,20 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public class StartFromBootstrap
|
||||
{
|
||||
static StartFromBootstrap()
|
||||
{
|
||||
var scenePath = "Assets/Infrastructure/Bootstrap.unity";
|
||||
var sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(scenePath);
|
||||
|
||||
if (sceneAsset != null)
|
||||
EditorSceneManager.playModeStartScene = sceneAsset;
|
||||
else
|
||||
Debug.LogError("Could not find scene at " + scenePath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c1b8ca63d9a4ba19fb70cb4ec7b7609
|
||||
timeCreated: 1785874078
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c030bebb626a43c7acf7f3a48acc09eb
|
||||
timeCreated: 1785847329
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Code.Game.Gameplay.Player.Factory;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using R3;
|
||||
using Reflex.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Game.TestingLevel
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public struct TestingLevelData
|
||||
{
|
||||
public Transform playerSpawnPoint;
|
||||
}
|
||||
public class TestingLevelSceneInstaller: MonoBehaviour, IInstaller, IDisposable
|
||||
{
|
||||
private IDisposable _onContainerBuildDisposable;
|
||||
[SerializeField] private TestingLevelData testingLevelData;
|
||||
|
||||
public void InstallBindings(ContainerBuilder containerBuilder)
|
||||
{
|
||||
containerBuilder.RegisterValue(testingLevelData);
|
||||
|
||||
_onContainerBuildDisposable = Observable
|
||||
.FromEvent<Container>(
|
||||
h => containerBuilder.OnContainerBuilt += h,
|
||||
h => containerBuilder.OnContainerBuilt -= h)
|
||||
.Subscribe(x => OnContainerBuilt(x).Forget());
|
||||
}
|
||||
|
||||
private ISceneContainerManager _sceneContainerManager;
|
||||
private async UniTaskVoid OnContainerBuilt(Container container)
|
||||
{
|
||||
await UniTask.Yield();
|
||||
|
||||
container.Resolve<IPlayerFactory>().InjectPlayer(container);
|
||||
|
||||
_onContainerBuildDisposable.Dispose();
|
||||
|
||||
_sceneContainerManager = container.Resolve<ISceneContainerManager>();
|
||||
_sceneContainerManager.ScenesContainers.Add(SceneId.Testing, container);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_sceneContainerManager.ScenesContainers.Remove(SceneId.Testing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db514476e4864e78b2ab1734a44b450c
|
||||
timeCreated: 1785847631
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Code.D.Cleaning.CleanTools;
|
||||
using Code.D.Cleaning.UI;
|
||||
using Code.D.Player;
|
||||
using Code.Game.Gameplay.Player;
|
||||
using Code.Game.Gameplay.Player.Factory;
|
||||
using Code.Infrastructure.App;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Generators;
|
||||
using Code.Infrastructure.Input;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Code.Infrastructure.UI;
|
||||
using Code.Infrastructure.Utils;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using KinematicCharacterController;
|
||||
using ObservableCollections;
|
||||
using R3;
|
||||
using Reflex.Core;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace Code.Game.TestingLevel
|
||||
{
|
||||
[State(typeof(AppStates), typeof(AppStateMachineContext))]
|
||||
public partial class TestingState
|
||||
{
|
||||
public TestingState(AppStateMachineContext context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public override AppStates MyState => AppStates.Testing;
|
||||
|
||||
public override async UniTask EnterState()
|
||||
{
|
||||
Cursor.lockState = CursorLockMode.Locked;
|
||||
|
||||
Context.InputService.EnableMap(ActionMappings.Cleaning);
|
||||
|
||||
Context.AudioService.SetAudioListener(Context.Camera.Camera.GetComponent<AudioListener>());
|
||||
|
||||
await Context.Camera.SwitchState(CameraMode.Cleaner);
|
||||
|
||||
var waitForContainer =
|
||||
Context.SceneContainerManager.ScenesContainers
|
||||
.ObserveDictionaryAdd()
|
||||
.Where(x => x.Key == SceneId.Testing)
|
||||
.Take(1)
|
||||
.WaitAsync()
|
||||
.AsUniTask();
|
||||
|
||||
var cleaningPanel = (CleaningPanel) await Context.UIFactory.LoadPanel(UIPanelType.Cleaning,true);
|
||||
|
||||
var factoryConfig = new SingleConfig<PlayerFactorySettings>();
|
||||
var cleanToolsConfigs = new MultipleConfig<CleanToolConfig>();
|
||||
|
||||
await UniTask.WhenAll(
|
||||
factoryConfig.LoadConfig(),
|
||||
cleanToolsConfigs.LoadConfigs()
|
||||
);
|
||||
|
||||
var factory = new PlayerFactory(factoryConfig);
|
||||
var player = await factory.CreatePlayer();
|
||||
var playerKinematicCharacterMotor = player.GetComponent<KinematicCharacterMotor>();
|
||||
var playerMovementController = player.GetComponent<PlayerMovementController>();
|
||||
var playerEquipment = player.GetComponent<PlayerEquipment>();
|
||||
|
||||
CleanToolConfig[] toolsConfigs = cleanToolsConfigs.Configs.ToArray();
|
||||
List<CleanTool> cleanTools = new();
|
||||
|
||||
// TODO Сделать сервис снабжения игрока
|
||||
foreach (var toolConfig in toolsConfigs)
|
||||
{
|
||||
switch (toolConfig.ToolType)
|
||||
{
|
||||
case CleanToolType.Tryapka:
|
||||
cleanTools.Add(new Tryapka(toolConfig.DurabilityUsageStep, toolConfig.CleanRadius, toolConfig.BrushTexture));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InstallExtra(Scene scene, ContainerBuilder builder)
|
||||
{
|
||||
builder.RegisterValue(factoryConfig);
|
||||
builder.RegisterValue(factory, new []{typeof(IPlayerFactory)});
|
||||
builder.RegisterValue(playerKinematicCharacterMotor);
|
||||
builder.RegisterValue(playerMovementController);
|
||||
builder.RegisterValue(playerEquipment);
|
||||
builder.RegisterValue(cleanTools);
|
||||
builder.RegisterValue(cleaningPanel);
|
||||
}
|
||||
|
||||
await UniTask.WhenAll(
|
||||
Context.SceneLoader
|
||||
.LoadSceneAsync(
|
||||
SceneId.Testing,
|
||||
LoadSceneMode.Single,
|
||||
true,
|
||||
InstallExtra),
|
||||
waitForContainer
|
||||
);
|
||||
|
||||
var container = Context.SceneContainerManager.ScenesContainers[SceneId.Testing];
|
||||
|
||||
container.Resolve<KinematicCharacterMotor>()
|
||||
.SetPositionAndRotation(
|
||||
container.Resolve<TestingLevelData>().playerSpawnPoint.position,
|
||||
container.Resolve<TestingLevelData>().playerSpawnPoint.rotation);
|
||||
|
||||
((CleanerCameraState)Context.Camera.CurrentBaseState)
|
||||
.SetPlayer(container.Resolve<PlayerMovementController>());
|
||||
}
|
||||
|
||||
public override async UniTask ExitState()
|
||||
{
|
||||
Context.InputService.DisableMap(ActionMappings.Cleaning);
|
||||
|
||||
await Context.SceneLoader.UnloadSceneAsync(SceneId.Testing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c6095424c534587b8b6ed7c758375e5
|
||||
timeCreated: 1785847339
|
||||
@@ -0,0 +1,74 @@
|
||||
Shader "Custom/UVRegionHighlighter"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_HighlightMin ("Highlight Min (U, V)", Vector) = (0.2, 0.2, 0, 0)
|
||||
_HighlightMax ("Highlight Max (U, V)", Vector) = (0.5, 0.5, 0, 0)
|
||||
_GridCount ("Grid Count", Float) = 10.0
|
||||
_HighlightColor ("Highlight Color", Color) = (1, 0, 0, 1)
|
||||
}
|
||||
SubShader
|
||||
{
|
||||
Tags { "RenderType"="Opaque" }
|
||||
LOD 100
|
||||
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
struct appdata
|
||||
{
|
||||
float4 vertex : POSITION;
|
||||
float2 uv : TEXCOORD1;
|
||||
};
|
||||
|
||||
struct v2f
|
||||
{
|
||||
float2 uv : TEXCOORD1;
|
||||
float4 vertex : SV_POSITION;
|
||||
};
|
||||
|
||||
float4 _HighlightMin;
|
||||
float4 _HighlightMax;
|
||||
float _GridCount;
|
||||
fixed4 _HighlightColor;
|
||||
|
||||
v2f vert (appdata v)
|
||||
{
|
||||
v2f o;
|
||||
o.vertex = UnityObjectToClipPos(v.vertex);
|
||||
o.uv = v.uv;
|
||||
return o;
|
||||
}
|
||||
|
||||
fixed4 frag (v2f i) : SV_Target
|
||||
{
|
||||
float2 uv = i.uv;
|
||||
|
||||
// Сетка (линии разметки)
|
||||
float2 grid = frac(uv * _GridCount);
|
||||
float lineMask = step(0.92, grid.x) + step(0.92, grid.y);
|
||||
lineMask = saturate(lineMask);
|
||||
|
||||
// Проверка: находится ли пиксель в выбранных UV-координатах
|
||||
bool inRegion = (uv.x >= _HighlightMin.x && uv.x <= _HighlightMax.x &&
|
||||
uv.y >= _HighlightMin.y && uv.y <= _HighlightMax.y);
|
||||
|
||||
// Базовый цвет UV + черная сетка
|
||||
fixed4 baseColor = lerp(fixed4(uv.x, uv.y, 0.0, 1.0), fixed4(0, 0, 0, 1), lineMask);
|
||||
|
||||
// Если пиксель внутри выделенного участка UV — подсвечиваем его
|
||||
if (inRegion)
|
||||
{
|
||||
return lerp(_HighlightColor, fixed4(1, 1, 1, 1), lineMask * 0.5);
|
||||
}
|
||||
|
||||
return baseColor;
|
||||
}
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa803291ec594773ad1056019437aa30
|
||||
timeCreated: 1786007069
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67a3491d6e6742faa2f703b763446706
|
||||
timeCreated: 1785766160
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 03ec58f5292de68cb94cf053c242d44a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,33 @@
|
||||
using Code.Infrastructure.Audio;
|
||||
using Code.Infrastructure.Camera;
|
||||
using Code.Infrastructure.Input;
|
||||
using Code.Infrastructure.Particles;
|
||||
using Code.Infrastructure.SceneLoader;
|
||||
using Code.Infrastructure.UI;
|
||||
using Code.Infrastructure.Volume;
|
||||
using Reflex.Attributes;
|
||||
|
||||
namespace Code.Infrastructure.App
|
||||
{
|
||||
public class AppStateMachineContext
|
||||
{
|
||||
[Inject] public ISceneContainerManager SceneContainerManager { get; set; }
|
||||
[Inject] public ISceneLoader SceneLoader { get; set; }
|
||||
[Inject] public IUIFactory UIFactory { get; set; }
|
||||
[Inject] public CameraStateMachine Camera { get; set; }
|
||||
[Inject] public ICameraFactory CameraFactory { get; set; }
|
||||
[Inject] public IAudioService AudioService { get; set; }
|
||||
[Inject] public IAudioFactory AudioFactory { get; set; }
|
||||
[Inject] public IInputService InputService { get; set; }
|
||||
[Inject] public IVolumeService VolumeService { get; set; }
|
||||
[Inject] public IParticleLoader ParticleLoader { get; set; }
|
||||
public AppStateMachine StateMachine { get; set; }
|
||||
}
|
||||
|
||||
[Generators.StateMachine(typeof(AppStateMachineContext),typeof(AppStates))]
|
||||
public partial class AppStateMachine
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5627248405434f028be921cb7916f823
|
||||
timeCreated: 1765572329
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc39950ba97e90dc09676d793e810207
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Code.Infrastructure.Configs;
|
||||
using Code.Infrastructure.Utils;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
public interface IAudioFactory
|
||||
{
|
||||
void UnloadAudioClips(AudioPartition groupPartition);
|
||||
UniTask LoadAudioClips(AudioPartition groupPartition);
|
||||
public Dictionary<AudioPartition, Dictionary<int, AudioReference>> ReferenceDictionary { get; }
|
||||
}
|
||||
|
||||
public interface IAudioFactoryInitializer
|
||||
{
|
||||
UniTask LoadConfigs();
|
||||
}
|
||||
|
||||
public class AudioFactory : IAudioFactory, IDisposable, IAudioFactoryInitializer
|
||||
{
|
||||
private string _label;
|
||||
private AsyncOperationHandle<IList<AudioInfoConfig>> _configsHandle;
|
||||
|
||||
public Dictionary<AudioPartition, Dictionary<int, AudioReference>> ReferenceDictionary { get; } = new();
|
||||
|
||||
public AudioFactory(IConfigLocator configLocator)
|
||||
{
|
||||
_label = configLocator.TryGetManyConfigAssetReferences<AudioInfoConfig>();
|
||||
|
||||
}
|
||||
|
||||
public async UniTask LoadConfigs()
|
||||
{
|
||||
if(!await AddressablesUtilities.CheckLabelExists(_label)) return;
|
||||
|
||||
_configsHandle = Addressables.LoadAssetsAsync<AudioInfoConfig>(_label);
|
||||
|
||||
await _configsHandle.ToUniTask();
|
||||
|
||||
foreach (AudioInfoConfig config in _configsHandle.Result)
|
||||
{
|
||||
if(!ReferenceDictionary.ContainsKey(config.GroupPartition))
|
||||
ReferenceDictionary.Add(config.GroupPartition, new());
|
||||
ReferenceDictionary[config.GroupPartition].Add(config.id, config.Reference);
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask LoadAudioClips(AudioPartition groupPartition)
|
||||
{
|
||||
foreach (var reference in ReferenceDictionary[groupPartition])
|
||||
{
|
||||
var load = reference.Value.Load();
|
||||
if (load.Status == UniTaskStatus.Pending)
|
||||
await load;
|
||||
}
|
||||
}
|
||||
|
||||
public void UnloadAudioClips(AudioPartition groupPartition)
|
||||
{
|
||||
foreach (var reference in ReferenceDictionary[groupPartition])
|
||||
{
|
||||
reference.Value.Unload();
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var partition in ReferenceDictionary)
|
||||
{
|
||||
foreach (var reference in partition.Value)
|
||||
{
|
||||
reference.Value.Unload();
|
||||
}
|
||||
}
|
||||
|
||||
if(_configsHandle.IsValid()) _configsHandle.Release();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc45c23918ed446681564b467668304b
|
||||
timeCreated: 1769344269
|
||||
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
[Serializable]
|
||||
public abstract class AudioReference
|
||||
{
|
||||
public abstract UniTask Load();
|
||||
public abstract void Unload();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AudioReferenceLODed : AudioReference
|
||||
{
|
||||
private AsyncOperationHandle<AudioClip> _interiorClipHandle;
|
||||
private AsyncOperationHandle<AudioClip> _closeClipHandle;
|
||||
private AsyncOperationHandle<AudioClip> _distantClipHandle;
|
||||
private AsyncOperationHandle<AudioClip> _farClipHandle;
|
||||
|
||||
public override async UniTask Load()
|
||||
{
|
||||
if (_interiorClipHandle.IsValid()) return;
|
||||
|
||||
_interiorClipHandle = Addressables.LoadAssetAsync<AudioClip>(interior);
|
||||
_closeClipHandle = Addressables.LoadAssetAsync<AudioClip>(close);
|
||||
_distantClipHandle = Addressables.LoadAssetAsync<AudioClip>(distant);
|
||||
_farClipHandle = Addressables.LoadAssetAsync<AudioClip>(far);
|
||||
|
||||
await UniTask.WhenAll(
|
||||
_interiorClipHandle.ToUniTask(),
|
||||
_closeClipHandle.ToUniTask(),
|
||||
_distantClipHandle.ToUniTask(),
|
||||
_farClipHandle.ToUniTask()
|
||||
);
|
||||
|
||||
Interior = _interiorClipHandle.Result;
|
||||
Close = _closeClipHandle.Result;
|
||||
Distant = _distantClipHandle.Result;
|
||||
Far = _farClipHandle.Result;
|
||||
}
|
||||
|
||||
public override void Unload()
|
||||
{
|
||||
if (!_interiorClipHandle.IsValid()) return;
|
||||
|
||||
_interiorClipHandle.Release();
|
||||
_closeClipHandle.Release();
|
||||
_distantClipHandle.Release();
|
||||
_farClipHandle.Release();
|
||||
|
||||
Interior = null;
|
||||
Close = null;
|
||||
Distant = null;
|
||||
Far = null;
|
||||
}
|
||||
|
||||
[SerializeField] private AssetReference interior;
|
||||
[SerializeField] private AssetReference close;
|
||||
[SerializeField] private AssetReference distant;
|
||||
[SerializeField] private AssetReference far;
|
||||
|
||||
public AudioClip Interior { get; private set; }
|
||||
public AudioClip Close { get; private set; }
|
||||
public AudioClip Distant { get; private set; }
|
||||
public AudioClip Far { get; private set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class AudioReferenceSingle : AudioReference
|
||||
{
|
||||
private AsyncOperationHandle<AudioClip> _clipHandle;
|
||||
|
||||
public override async UniTask Load()
|
||||
{
|
||||
if (_clipHandle.IsValid()) return;
|
||||
|
||||
_clipHandle = Addressables.LoadAssetAsync<AudioClip>(clip);
|
||||
|
||||
await _clipHandle.ToUniTask();
|
||||
|
||||
Clip = _clipHandle.Result;
|
||||
}
|
||||
|
||||
public override void Unload()
|
||||
{
|
||||
if (!_clipHandle.IsValid()) return;
|
||||
|
||||
_clipHandle.Release();
|
||||
|
||||
Clip = null;
|
||||
}
|
||||
|
||||
[SerializeField] private AssetReference clip;
|
||||
|
||||
public AudioClip Clip { get; private set; }
|
||||
}
|
||||
[Serializable]
|
||||
public class AudioReferenceRandom : AudioReference
|
||||
{
|
||||
private AsyncOperationHandle<AudioClip>[] _clipHandles;
|
||||
|
||||
public override async UniTask Load()
|
||||
{
|
||||
if (_clipHandles != null) return;
|
||||
|
||||
_clipHandles = new AsyncOperationHandle<AudioClip>[clips.Length];
|
||||
|
||||
for (var i = 0; i < clips.Length; i++)
|
||||
{
|
||||
_clipHandles[i] = Addressables.LoadAssetAsync<AudioClip>(clips[i]);
|
||||
await _clipHandles[i].ToUniTask();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Unload()
|
||||
{
|
||||
if (_clipHandles == null) return;
|
||||
|
||||
for (var i = 0; i < clips.Length; i++) Addressables.Release(_clipHandles[i]);
|
||||
}
|
||||
|
||||
[SerializeField] private AssetReference[] clips;
|
||||
|
||||
public AudioClip Clip => _clipHandles[Random.Range(0, _clipHandles.Length)].Result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4423af0d471f60ef89f8df279e82af2
|
||||
@@ -0,0 +1,14 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
[Config("Configs/Audio/AudioInfo", true, true)]
|
||||
public abstract class AudioInfoConfig : ScriptableObject
|
||||
{
|
||||
public AudioPartition GroupPartition;
|
||||
public int id;
|
||||
|
||||
public abstract AudioReference Reference { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24ed33a7f788429eb32b93b79fcb84bd
|
||||
timeCreated: 1785871082
|
||||
Loaded 100 of 999 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user