54 Commits
Author SHA1 Message Date
ThomasCharester a5ce6e3165 Merge remote-tracking branch 'origin/movement-dev' into Levels2 2025-12-04 19:03:54 +03:00
ThomasCharester d9a1271262 У меня всё работает 2025-12-04 17:43:29 +03:00
MrTorex 4c16a63abd я ксиька :3 2025-12-04 17:38:45 +03:00
MrTorex b4de41894f Убрано НАХУЙ _Recovery, добавлено движение в воздухе, деду добавлен стан как от дэша, так и от слайда, воллран вынесен в конфиг 2025-12-04 17:34:12 +03:00
MrTorex 77fd9af29d Убран бег (просто заменён на ходьбу с такой же скоростью), прошлый слайд заменён на дэщ, добавлен новый слайд 2025-12-04 17:14:24 +03:00
ThomasCharester a1c2c5fd18 Музыка меня отменила 2025-12-03 20:15:34 +03:00
ThomasCharester 485d54f272 Поудалял важные компоненты 2025-12-03 20:07:36 +03:00
ThomasCharester 0d0787b887 Звуки поражения 2025-12-03 19:32:10 +03:00
ThomasCharester 5d856ae162 Получение урона теперь чуть более заметно (плейсхолдер) 2025-12-03 17:39:26 +03:00
ThomasCharester dd1399e015 Урон курьера 2025-12-03 14:13:45 +03:00
ThomasCharester 2b656412d5 Фикс звуков, только аккуратно
Звуки от 0.01 до 1 ставим, иначе +уши
2025-12-03 14:04:08 +03:00
ThomasCharester 36e6bc3bc2 Звуки шагов в моей голове 2025-12-02 21:50:33 +03:00
ThomasCharester 1e31e1e8b1 Фикс трактора 2025-12-02 19:53:02 +03:00
ThomasCharester 2897eb88bf Звуки шагов, ядерный таракан, монстр дед 2025-12-01 18:36:22 +03:00
ThomasCharester 134adda787 Недочин недопил но переполошил аудио 2025-12-01 14:52:19 +03:00
ThomasCharester 2f56a5758d Мобы на уровнях, анимации 2025-12-01 12:59:15 +03:00
ThomasCharester fb9510a6b2 Починка генерации + небольшой прикол дверей 2025-12-01 00:02:00 +03:00
ThomasCharester aa4a9e69dd Подогреваем коллизии 2025-11-29 00:41:07 +03:00
ThomasCharester 34d7fa3791 Блять 2025-11-28 15:13:03 +03:00
ThomasCharester 26804e08f7 Да, теперь нормально 2025-11-28 15:04:56 +03:00
ThomasCharester e96dcf3e0d Merge branch 'Dev' of https://notscam.serveminecraft.net/Tetramino/CourierOld into Dev 2025-11-28 15:04:25 +03:00
ThomasCharester 94f0522f89 Да, теперь нормально 2025-11-28 14:51:38 +03:00
xrust1k eefcf6eabc Merge branch 'Dev' of https://notscam.serveminecraft.net/Tetramino/CourierOld into Dev 2025-11-28 14:48:59 +03:00
xrust1k c85638fda0 Бля ебать рот этих дверей 2025-11-28 14:47:29 +03:00
ThomasCharester 1de117622e Фикс пива 2025-11-28 14:32:37 +03:00
ThomasCharester e2f8984e6f Merge remote-tracking branch 'origin/mobs-and-levels-dev' into Dev 2025-11-28 14:25:02 +03:00
ThomasCharester 32c6e0630a Солнышко 2025-11-28 14:20:51 +03:00
MrTorex 870a4743c6 дрочка лёжа на рельсах 2025-11-28 14:14:55 +03:00
MrTorex 2fc8e249f5 Merge branch 'mobs-and-levels-dev' into Dev 2025-11-28 13:56:35 +03:00
MrTorex 280eb3754c МЕНЯ ТРАХАЛИ ВСЕМ ДЕТДОМОМ 2025-11-28 13:56:02 +03:00
xrust1k 6eff3ef9a9 AAAAAAAAAAAAAAAAAAA 2025-11-28 13:51:32 +03:00
xrust1k 6b4792393a Merge branch 'Dev' of https://notscam.serveminecraft.net/Tetramino/CourierOld into Dev 2025-11-28 13:33:00 +03:00
xrust1k a547c39db7 Комнаты 2025-11-28 13:26:52 +03:00
ThomasCharester 0cab2eda74 Добавлена механика Initial Room 2025-11-28 13:21:56 +03:00
xrust1k 5d075034b5 Я со старой версии запушил снова, ломаться не должно 2025-11-28 12:10:30 +03:00
xrust1k 7f7ba0d9c5 Merge branch 'Dev' of https://notscam.serveminecraft.net/Tetramino/CourierOld into Dev 2025-11-28 11:52:49 +03:00
xrust1k ab0b41a318 Я боюсь 2025-11-28 11:52:15 +03:00
MrTorex a5ce8522ab мержим 2025-11-28 11:46:04 +03:00
MrTorex 97aea0fde1 Merge branch 'Dev' into movement-dev 2025-11-28 11:42:30 +03:00
MrTorex e9e8e091b2 письки 2025-11-28 11:42:08 +03:00
ThomasCharester 9e1c1177e0 Фикс геймплея? 2025-11-28 11:39:59 +03:00
ThomasCharester 07535982ba Dimka Bakery 2025-11-28 11:09:31 +03:00
MrTorex df0c2b3157 Merge branch 'Dev' into movement-dev 2025-11-28 10:49:11 +03:00
MrTorex d51527b7f3 это спермаггедон 2025-11-28 10:47:28 +03:00
xrust1k 13aca5a86f Merge branch 'Dev' of https://notscam.serveminecraft.net/Tetramino/CourierOld into Dev 2025-11-28 10:43:47 +03:00
xrust1k 9cc77d5c67 Уровни (Да ничего я не сделал) 2025-11-28 10:42:00 +03:00
ThomasCharester c1a0e94fe3 Merge branch 'Generator' into Dev 2025-11-28 10:28:10 +03:00
MrTorex d14f9c2a9f анус рвётся не по-детски 2025-11-28 09:45:49 +03:00
MrTorex 4b6909fe84 Допил наклонов (они такое себе)
Хуже, чем были раньше, но лучше, чем ничего. Плавность переходов имеется, и на том спасибо
2025-11-28 01:15:44 +03:00
MrTorex 766609489d Я ненавижу наклоны (не прорвёмся) 2025-11-28 00:51:20 +03:00
ThomasCharester 3782a0b568 Фикс отпуска звуков 2025-11-27 23:01:12 +03:00
MrTorex d10d2cdca6 прорвёмся (добавлен walljump) 2025-11-27 21:36:19 +03:00
MrTorex 01d3b0adec чел не липнет к воздуху 2025-11-27 21:10:23 +03:00
MrTorex b271042137 инишиал титан падать второй мувмент (но пока очень говно) 2025-11-27 20:37:16 +03:00
638 changed files with 956403 additions and 18221 deletions

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
{
"version": "1.0",
"components": [
"Microsoft.VisualStudio.Workload.ManagedGame"
]
}
@@ -15,7 +15,7 @@ MonoBehaviour:
m_DefaultGroup: d447fc60305c17a17bf20948ab295a45 m_DefaultGroup: d447fc60305c17a17bf20948ab295a45
m_currentHash: m_currentHash:
serializedVersion: 2 serializedVersion: 2
Hash: 00000000000000000000000000000000 Hash: 1ec1ee985689145b755c859b69691cb0
m_OptimizeCatalogSize: 0 m_OptimizeCatalogSize: 0
m_BuildRemoteCatalog: 0 m_BuildRemoteCatalog: 0
m_CatalogRequestsTimeout: 0 m_CatalogRequestsTimeout: 0
@@ -32,6 +32,11 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 1cc66c0b13a946e1c9ec37026268e144
m_Address: Audio/Enemies/pl_metal2
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 1d4767c722c05b5d6b96bb226d378c65 - m_GUID: 1d4767c722c05b5d6b96bb226d378c65
m_Address: Assets/Resources_moved/Prefabs/Player/ArmsMesh.prefab m_Address: Assets/Resources_moved/Prefabs/Player/ArmsMesh.prefab
m_ReadOnly: 0 m_ReadOnly: 0
@@ -52,6 +57,11 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 26d4e4c556527924490b8018cd510eda
m_Address: Assets/Resources_moved/Audio/Enemies/bc_bite2.wav
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 28a6c7a4124141341ab7c2b7dfd3e95b - m_GUID: 28a6c7a4124141341ab7c2b7dfd3e95b
m_Address: Assets/Resources_moved/Prefabs/Levels/Level1 2.prefab m_Address: Assets/Resources_moved/Prefabs/Levels/Level1 2.prefab
m_ReadOnly: 0 m_ReadOnly: 0
@@ -67,6 +77,11 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 2c6a984e4a1b42647b48e6b7bc69b158
m_Address: Prefabs/Levels/Level6
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 2ed2d93a9f39d4edba511cb7396c7bb6 - m_GUID: 2ed2d93a9f39d4edba511cb7396c7bb6
m_Address: Assets/Resources_moved/Prefabs/Enemies/Cockroach.prefab m_Address: Assets/Resources_moved/Prefabs/Enemies/Cockroach.prefab
m_ReadOnly: 0 m_ReadOnly: 0
@@ -87,13 +102,8 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 3d195945b1fbf114a88457cba466bc2b - m_GUID: 3f8f2171cc252d953b82083cc16bd1ae
m_Address: Assets/Resources_moved/Rooms/Room2.prefab m_Address: Assets/Resources_moved/Prefabs/Levels/Level6_1.prefab
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 4472dd84628855c4085cacaec19efa29
m_Address: Assets/Resources_moved/Rooms/Room1.prefab
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
@@ -102,13 +112,18 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 4b279429428a13040b6d1713122cd0de
m_Address: Assets/Resources_moved/Audio/SFX/pl_pain5.wav
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 4bd64d1fcecc9c6b09d81e78b7dcfebe - m_GUID: 4bd64d1fcecc9c6b09d81e78b7dcfebe
m_Address: Audio/Dispatcher/take_damage1 m_Address: Audio/Dispatcher/take_damage1
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 4f660559d76c3ed42a7c34a0b16487f7 - m_GUID: 7067a5248027e74478f4f0f53ddf06a4
m_Address: Assets/Resources_moved/Rooms/Room3.prefab m_Address: Prefabs/Rooms/Save1
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
@@ -163,11 +178,26 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 9d78f017876abed4c9cd8957f1e140cb
m_Address: Prefabs/Rooms/Level1_2
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: a306df57f348ce7cf900d0b9431739ee - m_GUID: a306df57f348ce7cf900d0b9431739ee
m_Address: launch_selectmenu m_Address: launch_selectmenu
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: aa138b2e21adfbf4bbbfa5bf9d54b8f2
m_Address: Assets/Resources_moved/Audio/UI/buttonclickrelease.wav
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: ae6ab2c88ae248ce1b6efca892f17659
m_Address: Assets/Resources_moved/Audio/Music/TestDeath.ogg
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: b2e8dc2aeb0311cd8a826b51cf8e94dc - m_GUID: b2e8dc2aeb0311cd8a826b51cf8e94dc
m_Address: GameOver m_Address: GameOver
m_ReadOnly: 0 m_ReadOnly: 0
@@ -178,8 +208,13 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: b3471d165fe389f479380f61034bea57 - m_GUID: b37ea8c61cc322afdad529d678612d22
m_Address: Assets/Resources_moved/Prefabs/Levels/Level1 1.prefab m_Address: Assets/Resources_moved/Audio/Enemies/zo_attack2.wav
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: bf87bc9ac43df86be8c818de81d44a54
m_Address: Assets/Resources_moved/Audio/SFX/pl_step1.wav
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
@@ -188,13 +223,28 @@ MonoBehaviour:
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: c5a0ad8a615841547ac2ee613af526d8
m_Address: Assets/Resources_moved/Audio/SFX/pl_pain2.wav
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: c938de3174f184741925c407a43a47f2
m_Address: Prefabs/Rooms/Level1
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: cab4b1ff78dd6b1fba61aa165aa17b4d - m_GUID: cab4b1ff78dd6b1fba61aa165aa17b4d
m_Address: Audio/Dispatcher/receiving_an_order2 m_Address: Audio/Dispatcher/receiving_an_order2
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
- m_GUID: d4eaf1439c2788c458127b9ba67e4fbf - m_GUID: e3a3840a7963bf841872cddb02e90151
m_Address: Prefabs/Levels/Level1 m_Address: Prefabs/Levels/MainMenu 1
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: e84e3a3c26ccbd50d92f13627403f148
m_Address: Audio/Enemies/rch_walk
m_ReadOnly: 0 m_ReadOnly: 0
m_SerializedLabels: [] m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0 FlaggedDuringContentUpdateRestriction: 0
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 1ce80ea58c1a9154dab0a2f539b9b2a4 guid: d36aab6707c518f5abfd60065165eb35
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
@@ -1,5 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: f01bff5d55306654a99aa04e4a24d1ea guid: d982316b2b4c99747b9e953ae7b9b42f
folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
@@ -1,6 +1,9 @@
using Code.App.StateMachine; using Code.App.StateMachine;
using Code.Audio;
using Code.Gameplay.Player; using Code.Gameplay.Player;
using Code.Input; using Code.Input;
using Code.Scenes;
using Code.Scenes.SceneEnvironments;
using Code.StateMachine; using Code.StateMachine;
using Code.UI; using Code.UI;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
@@ -30,7 +33,11 @@ namespace Code.App.AppStates
Context.InputService.EnableMap(ActionMappings.UI); Context.InputService.EnableMap(ActionMappings.UI);
Context.InputService.DebugBindAction((int)ActionMappings.UI,(int)UIActions.Continue, TryToExit); Context.InputService.DebugBindAction((int)ActionMappings.UI,(int)UIActions.Continue, TryToExit);
GameOver(); Context.AudioService.PlayRandomMusicUntilHumanityWillBeDestroyedForTheySins(MusicType.Death);
Context.AudioService.ApplyStun(5000,0.5f);
GameOver().Forget();
base.EnterState(); base.EnterState();
} }
@@ -45,7 +52,7 @@ namespace Code.App.AppStates
await Context.UIService.AsyncSwitchPanelTo(UIPanel.GameOver); await Context.UIService.AsyncSwitchPanelTo(UIPanel.GameOver);
_gameOverPanel = (GameOverPanel)Context.UIService.CurrentPanel; _gameOverPanel = (GameOverPanel)Context.UIService.CurrentPanel;
_gameOverPanel.Show();
} }
private void ToMainMenu() private void ToMainMenu()
@@ -71,6 +78,8 @@ namespace Code.App.AppStates
Context.InputService.DisableMap(ActionMappings.UI); Context.InputService.DisableMap(ActionMappings.UI);
Context.InputService.DebugUnbindAction((int)ActionMappings.UI,(int)UIActions.Continue, TryToExit); Context.InputService.DebugUnbindAction((int)ActionMappings.UI,(int)UIActions.Continue, TryToExit);
Context.AudioService.GladlyAskToStopMusic(MusicType.Death, callback: Context.AudioFactory.ReleaseDeathMusic);
Context.AudioService.TransitToSnapshot(AudioSnapshotState.None);
base.ExitState(); base.ExitState();
} }
} }
@@ -13,10 +13,12 @@ using Code.StateMachine;
using Code.UI; using Code.UI;
using Code.UI.Panels; using Code.UI.Panels;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using DG.Tweening;
using Reflex.Core; using Reflex.Core;
using Reflex.Extensions; using Reflex.Extensions;
using UnityEngine; using UnityEngine;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace Code.App.AppStates namespace Code.App.AppStates
@@ -42,25 +44,18 @@ namespace Code.App.AppStates
.RegisterLoading(LoadingWork.LoadUI) .RegisterLoading(LoadingWork.LoadUI)
.RegisterLoading(LoadingWork.LoadModelResource) .RegisterLoading(LoadingWork.LoadModelResource)
.RegisterLoading(LoadingWork.LoadAudio); .RegisterLoading(LoadingWork.LoadAudio);
//_playerHealth = Context.PlayerFactory.CreatePlayerHealth();
//_playerHealth.OnDamage += PlayerDamageTaken;
//_playerHealth.OnDeath += EndGame;
Context.AudioService.TransitToSnapshot(AudioSnapshotState.None); Context.AudioService.TransitToSnapshot(AudioSnapshotState.None);
Context.InputService.EnableMap(ActionMappings.Gameplay); Context.InputService.EnableMap(ActionMappings.Gameplay);
Context.InputService.DebugBindAction((int)ActionMappings.Debug, (int)DebugActions.Debug1, InstaKillDEBUG); Context.InputService.DebugBindAction((int)ActionMappings.Debug, (int)DebugActions.Debug1, InstaKillDEBUG);
Context.InputService.DebugBindAction((int)ActionMappings.Debug, (int)DebugActions.Debug4, RoomPassedDEBUG); Context.InputService.DebugBindAction((int)ActionMappings.Debug, (int)DebugActions.Debug4, TakeGamageDEBUG);
Context.SceneLoaderService.LoadSceneAsyncAwaitable((int)SceneIds.DevGen); Context.SceneLoaderService.LoadSceneAsyncAwaitable((int)SceneIds.DevGen);
Context.LoadingManager.OnLoadingEnded += AfterSceneLoaded; Context.LoadingManager.OnLoadingEnded += AfterSceneLoaded;
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed WaitForLoad().Forget();
WaitForLoad();
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
} }
private async UniTask WaitForPlayerCharacterLoad() => _playerCharacter = await Context.PlayerFactory.CreatePlayer(); private async UniTask WaitForPlayerCharacterLoad() => _playerCharacter = await Context.PlayerFactory.CreatePlayer();
@@ -69,8 +64,11 @@ namespace Code.App.AppStates
await UniTask.WhenAll( await UniTask.WhenAll(
Context.UIService.AsyncSwitchPanelTo(UIPanel.Gameplay), Context.UIService.AsyncSwitchPanelTo(UIPanel.Gameplay),
Context.AudioFactory.WarmGameplayMusic(), Context.AudioFactory.WarmGameplayMusic(),
Context.AudioFactory.WarmDeathMusic(),
Context.AudioFactory.WarmSFX(), Context.AudioFactory.WarmSFX(),
Context.AudioFactory.WarmDispatcher() Context.AudioFactory.WarmDispatcher(),
Context.AudioFactory.WarmEnemies(),
Context.AudioFactory.WarmCourier()
); );
Context.LoadingManager Context.LoadingManager
@@ -86,9 +84,12 @@ namespace Code.App.AppStates
{ {
Context.LoadingManager Context.LoadingManager
.RegisterLoading(LoadingWork.LoadModelResource); .RegisterLoading(LoadingWork.LoadModelResource);
Context.LoadingManager.OnLoadingEnded -= AfterSceneLoaded; Context.LoadingManager.OnLoadingEnded -= AfterSceneLoaded;
Context.LoadingManager.OnLoadingEnded += AfterPlayerLoaded; Context.LoadingManager.OnLoadingEnded += AfterPlayerLoaded;
Context.PlayerProvider = SceneManager.GetActiveScene().GetSceneContainer().Resolve<IPlayerProvider>();
Context.PlayerFactory = SceneManager.GetActiveScene().GetSceneContainer().Resolve<IPlayerFactory>();
await UniTask.WhenAll( await UniTask.WhenAll(
WaitForPlayerArmsToInitialize(), WaitForPlayerArmsToInitialize(),
@@ -111,6 +112,8 @@ namespace Code.App.AppStates
GameplaySceneEnvironment sceneEnvironment = SceneEnvironmentVariables(sceneContainer); GameplaySceneEnvironment sceneEnvironment = SceneEnvironmentVariables(sceneContainer);
_volume = sceneEnvironment.volume;
PlayerInitialize(sceneEnvironment); PlayerInitialize(sceneEnvironment);
CameraInitialize(); CameraInitialize();
@@ -152,16 +155,31 @@ namespace Code.App.AppStates
private void PlayerDamageTaken(int damage, PlayerHealth health) private void PlayerDamageTaken(int damage, PlayerHealth health)
{ {
Context.AudioService.PlayDispatcher((DispatcherSounds)Random.Range((int)DispatcherSounds.TakeDamage1,(int)DispatcherSounds.TakeDamage4)); Context.AudioService.PlayDispatcher((DispatcherSounds)Random.Range((int)DispatcherSounds.TakeDamage1,(int)DispatcherSounds.TakeDamage4));
Context.AudioService.PlayCourier((CourierSounds)Random.Range((int)CourierSounds.Damage1,(int)CourierSounds.Damage2));
DamageEffectProcess().Forget();
}
// TODO В конфиг
private async UniTaskVoid DamageEffectProcess()
{
_damagePanel.Show();
Context.AudioService.ApplyStun(200, 0.5f);
DOTween.To(() => _volume.weight, x => _volume.weight = x, 1f, 0.5f);
await UniTask.WaitForSeconds(3f);
DOTween.To(() => _volume.weight, x => _volume.weight = x, 0f, 1f);
Context.AudioService.ApplyStun(5000, 1f);
_damagePanel.Hide();
} }
// DEBUG // DEBUG
private void InstaKillDEBUG(InputAction.CallbackContext context) private void InstaKillDEBUG(InputAction.CallbackContext context)
{ {
_playerHealth.InstaKill(); _playerHealth.InstaKill();
} }
private void RoomPassedDEBUG(InputAction.CallbackContext context) private void TakeGamageDEBUG(InputAction.CallbackContext context)
{ {
_orderService.RoomPassed(); _playerHealth.GetDamage(1);
} }
// DEBUG // DEBUG
private bool _tickEnabled; private bool _tickEnabled;
public override void Tick() public override void Tick()
@@ -194,12 +212,16 @@ namespace Code.App.AppStates
Context.AudioService.OnDispatcherEnded -= _gameplayPanel.CloseDispatcher; Context.AudioService.OnDispatcherEnded -= _gameplayPanel.CloseDispatcher;
Context.InputService.DisableMap(ActionMappings.Gameplay); Context.InputService.DisableMap(ActionMappings.Gameplay);
Context.AudioService.GladlyAskToStopMusic(MusicType.Action, callback: Context.AudioFactory.ReleaseActionMusic); Context.AudioService.GladlyAskToStopMusic(MusicType.Action, time: 0f, callback: Context.AudioFactory.ReleaseActionMusic);
Context.AudioService.GladlyAskToStopMusic(MusicType.Peaceful, callback: Context.AudioFactory.ReleasePeacefulMusic); Context.AudioService.GladlyAskToStopMusic(MusicType.Peaceful, time: 0f, callback: Context.AudioFactory.ReleasePeacefulMusic);
Context.AudioFactory.ReleaseCourier();
Context.AudioFactory.ReleaseDispatcher();
Context.AudioFactory.ReleaseEnemies();
Context.AudioFactory.ReleaseSFX();
Context.InputService.DebugUnbindAction((int)ActionMappings.Debug, (int)DebugActions.Debug1, InstaKillDEBUG); Context.InputService.DebugUnbindAction((int)ActionMappings.Debug, (int)DebugActions.Debug1, InstaKillDEBUG);
Context.InputService.DebugUnbindAction((int)ActionMappings.Debug, (int)DebugActions.Debug4, RoomPassedDEBUG); Context.InputService.DebugUnbindAction((int)ActionMappings.Debug, (int)DebugActions.Debug4, TakeGamageDEBUG);
base.ExitState(); base.ExitState();
} }
@@ -216,13 +238,15 @@ namespace Code.App.AppStates
private GameplayPanel _gameplayPanel; private GameplayPanel _gameplayPanel;
private ArmsMeshProvider _armsMesh; private ArmsMeshProvider _armsMesh;
private DamagePanel _damagePanel;
private void UIInitialize() private void UIInitialize()
{ {
_gameplayPanel = (GameplayPanel)Context.UIService.CurrentPanel; _gameplayPanel = (GameplayPanel)Context.UIService.CurrentPanel;
_gameplayPanel.Initialize(_playerScore, _playerHealth, _orderService); _gameplayPanel.Initialize(_playerScore, _playerHealth, _orderService);
Context.AudioService.OnDispatcherStarted += _gameplayPanel.SummonDispatcher; Context.AudioService.OnDispatcherStarted += _gameplayPanel.SummonDispatcher;
Context.AudioService.OnDispatcherEnded += _gameplayPanel.CloseDispatcher; Context.AudioService.OnDispatcherEnded += _gameplayPanel.CloseDispatcher;
_damagePanel = _gameplayPanel.DamagePanel;
} }
private void MusicInitialize() private void MusicInitialize()
{ {
@@ -244,10 +268,12 @@ namespace Code.App.AppStates
_orderService.OnOrderDelivered += OrderDelivered; _orderService.OnOrderDelivered += OrderDelivered;
_orderService.OnOrderFailure += OrderFailure; _orderService.OnOrderFailure += OrderFailure;
} }
private Volume _volume;
private GameplaySceneEnvironment SceneEnvironmentVariables(Container sceneContainer) private GameplaySceneEnvironment SceneEnvironmentVariables(Container sceneContainer)
{ {
var sceneEnvironment = (GameplaySceneEnvironment)sceneContainer.Resolve<CurrentSceneEnvironment>(); var sceneEnvironment = (GameplaySceneEnvironment)sceneContainer.Resolve<CurrentSceneEnvironment>();
return sceneEnvironment; return sceneEnvironment;
} }
} }
@@ -33,11 +33,7 @@ namespace Code.App
containerBuilder.AddSingleton(typeof(LoadingManager), typeof(ILoadingManager)); containerBuilder.AddSingleton(typeof(LoadingManager), typeof(ILoadingManager));
containerBuilder.AddSingleton(typeof(InputService), typeof(IInputService)); containerBuilder.AddSingleton(typeof(InputService), typeof(IInputService));
// Перенести нахуй в контейнер геймплея
containerBuilder.AddSingleton(typeof(PlayerFactory), typeof(IPlayerFactory));
containerBuilder.AddSingleton(typeof(EnemyFactory), typeof(IEnemyFactory));
containerBuilder.AddSingleton(typeof(PlayerProvider), typeof(IPlayerProvider));
//
InitializeCamera(containerBuilder, staticDataService); InitializeCamera(containerBuilder, staticDataService);
containerBuilder.AddSingleton(typeof(UIFactory), typeof(IUIFactory)); containerBuilder.AddSingleton(typeof(UIFactory), typeof(IUIFactory));
@@ -71,6 +67,7 @@ namespace Code.App
containerBuilder.AddSingleton(infrastructureUnit.AddComponent<CameraStateMachine>()); containerBuilder.AddSingleton(infrastructureUnit.AddComponent<CameraStateMachine>());
} }
// TODO Часть в сцены
private void InstallStaticData(ContainerBuilder containerBuilder, out IStaticDataService staticDataService) private void InstallStaticData(ContainerBuilder containerBuilder, out IStaticDataService staticDataService)
{ {
staticDataService = new StaticDataService(); staticDataService = new StaticDataService();
@@ -97,9 +94,12 @@ namespace Code.App
containerBuilder.AddSingleton(staticDataService.SoundtrackListConfig, typeof(SoundtrackListConfig)); containerBuilder.AddSingleton(staticDataService.SoundtrackListConfig, typeof(SoundtrackListConfig));
containerBuilder.AddSingleton(staticDataService.AudioTestClipsConfig, typeof(AudioTestClipsConfig)); containerBuilder.AddSingleton(staticDataService.AudioTestClipsConfig, typeof(AudioTestClipsConfig));
containerBuilder.AddSingleton(staticDataService.SFXListConfig, typeof(SFXListConfig)); containerBuilder.AddSingleton(staticDataService.SFXListConfig, typeof(SFXListConfig));
containerBuilder.AddSingleton(staticDataService.CourierSoundListConfig, typeof(CourierSoundListConfig));
containerBuilder.AddSingleton(staticDataService.DispatcherSoundListConfig, typeof(DispatcherSoundListConfig)); containerBuilder.AddSingleton(staticDataService.DispatcherSoundListConfig, typeof(DispatcherSoundListConfig));
containerBuilder.AddSingleton(staticDataService.EnemiesSoundListConfig, typeof(EnemiesSoundListConfig)); containerBuilder.AddSingleton(staticDataService.EnemiesSoundListConfig, typeof(EnemiesSoundListConfig));
containerBuilder.AddSingleton(staticDataService.AudioSourceSettingsConfigs, typeof(Dictionary<AudioSourceType, AudioSourceSettingsConfig>)); containerBuilder.AddSingleton(staticDataService.AudioSourceSettingsConfigs, typeof(Dictionary<AudioSourceType, AudioSourceSettingsConfig>));
containerBuilder.AddSingleton(staticDataService.DefaultAudioSettingsConfig, typeof(DefaultAudioSettingsConfig));
containerBuilder.AddSingleton(staticDataService.OrderServiceConfig, typeof(OrderServiceConfig)); containerBuilder.AddSingleton(staticDataService.OrderServiceConfig, typeof(OrderServiceConfig));
containerBuilder.AddSingleton(staticDataService.OrderBoxConfig, typeof(OrderBoxConfig)); containerBuilder.AddSingleton(staticDataService.OrderBoxConfig, typeof(OrderBoxConfig));
@@ -119,9 +119,7 @@ namespace Code.App
AttributeInjector.Inject(cameraStateMachine.StateMachineContext, container); AttributeInjector.Inject(cameraStateMachine.StateMachineContext, container);
cameraStateMachine.Initialize(); cameraStateMachine.Initialize();
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed BootstrapFinish(container).Forget();
BootstrapFinish(container);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
} }
private async UniTaskVoid BootstrapFinish(Container container) private async UniTaskVoid BootstrapFinish(Container container)
{ {
@@ -1,4 +1,5 @@
using Code.App.Loading; using Code.App.Loading;
using Code.Gameplay.Enemies;
using Code.Gameplay.Orders.Order; using Code.Gameplay.Orders.Order;
using Code.Gameplay.Player; using Code.Gameplay.Player;
using Code.Generator; using Code.Generator;
@@ -21,6 +22,9 @@ namespace Code.App.SceneInstallers
containerBuilder.AddScoped(typeof(PlayerScore), typeof(IPlayerScore)); containerBuilder.AddScoped(typeof(PlayerScore), typeof(IPlayerScore));
containerBuilder.AddScoped(typeof(OrderService), typeof(IOrderService)); containerBuilder.AddScoped(typeof(OrderService), typeof(IOrderService));
containerBuilder.AddScoped(typeof(RoomGeneratorFactory), typeof(IRoomGeneratorFactory)); containerBuilder.AddScoped(typeof(RoomGeneratorFactory), typeof(IRoomGeneratorFactory));
containerBuilder.AddScoped(typeof(PlayerProvider), typeof(IPlayerProvider));
containerBuilder.AddScoped(typeof(PlayerFactory), typeof(IPlayerFactory));
containerBuilder.AddScoped(typeof(EnemyFactory), typeof(IEnemyFactory));
containerBuilder.AddScoped(typeof(RoomGenerator)); containerBuilder.AddScoped(typeof(RoomGenerator));
containerBuilder.OnContainerBuilt += Initialize; containerBuilder.OnContainerBuilt += Initialize;
@@ -37,14 +41,14 @@ namespace Code.App.SceneInstallers
loadingManager loadingManager
.UnregisterLoading(LoadingWork.LoadScene); .UnregisterLoading(LoadingWork.LoadScene);
LoadRooms(container,loadingManager); LoadRooms(container,loadingManager).Forget();
} }
private async UniTaskVoid LoadRooms(Container container, ILoadingManager loadingManager) private async UniTaskVoid LoadRooms(Container container, ILoadingManager loadingManager)
{ {
await container.Resolve<IRoomGeneratorFactory>().PreloadRooms(container.Resolve<IOrderService>()); // await container.Resolve<IRoomGeneratorFactory>().PreloadRooms(container.Resolve<IOrderService>());
container.Resolve<RoomGenerator>().Initialize(); // container.Resolve<RoomGenerator>().Initialize();
loadingManager.UnregisterLoading(LoadingWork.LoadModelResource); loadingManager.UnregisterLoading(LoadingWork.LoadModelResource);
} }
@@ -19,10 +19,10 @@ namespace Code.App.StateMachine
[Inject] public AppStateMachine StateMachine { get; private set; } [Inject] public AppStateMachine StateMachine { get; private set; }
[Inject] public CameraStateMachine CameraStateMachine { get; private set; } [Inject] public CameraStateMachine CameraStateMachine { get; private set; }
[Inject] public IUIService UIService { get; private set; } [Inject] public IUIService UIService { get; private set; }
[Inject] public IPlayerFactory PlayerFactory { get; private set; }
[Inject] public IPlayerProvider PlayerProvider { get; private set; }
[Inject] public IAudioFactory AudioFactory { get; private set; } [Inject] public IAudioFactory AudioFactory { get; private set; }
[Inject] public IAudioService AudioService { get; private set; } [Inject] public IAudioService AudioService { get; private set; }
[Inject] public IEnemyFactory EnemyFactory { get; private set; } /*[Inject]*/public IPlayerFactory PlayerFactory { get; set; }
/*[Inject]*/public IPlayerProvider PlayerProvider { get; set; }
// [Inject] public IEnemyFactory EnemyFactory { get; private set; }
} }
} }
@@ -11,8 +11,10 @@ namespace Code.Audio
} }
public enum EnemiesSounds public enum EnemiesSounds
{ {
Bastard, GrandpaAttack,
Bravo RoachAttack,
RoachStep,
GrandpaStep
} }
public enum DispatcherSounds public enum DispatcherSounds
{ {
@@ -28,4 +30,10 @@ namespace Code.Audio
Late4, Late4,
Late5 Late5
} }
public enum CourierSounds
{
Step,
Damage1,
Damage2
}
} }
@@ -19,24 +19,28 @@ namespace Code.Audio
private AssetReference[] _audioTestClipsReferences; private AssetReference[] _audioTestClipsReferences;
private AssetReference[] _peacefulSoundtrack; private AssetReference[] _peacefulSoundtrack;
private AssetReference[] _actionSoundtrack; private AssetReference[] _actionSoundtrack;
private AssetReference[] _deathSoundtrack;
private AssetReference[] _menuSoundtrack; private AssetReference[] _menuSoundtrack;
private AssetReference[] _SFX; private AssetReference[] _SFX;
private AssetReference[] _enemies; private AssetReference[] _enemies;
private AssetReference[] _dispatcher; private AssetReference[] _dispatcher;
private AssetReference[] _character; private AssetReference[] _courier;
private AsyncOperationHandle<IList<AudioClip>> _audioTestClipsHandle; private AsyncOperationHandle<IList<AudioClip>> _audioTestClipsHandle;
private AsyncOperationHandle<IList<AudioClip>> _menuMusicHandle; private AsyncOperationHandle<IList<AudioClip>> _menuMusicHandle;
private AsyncOperationHandle<IList<AudioClip>> _deathMusicHandle;
private AsyncOperationHandle<IList<AudioClip>> _actionMusicHandle; private AsyncOperationHandle<IList<AudioClip>> _actionMusicHandle;
private AsyncOperationHandle<IList<AudioClip>> _peacefulMusicHandle; private AsyncOperationHandle<IList<AudioClip>> _peacefulMusicHandle;
private AsyncOperationHandle<IList<AudioClip>> _SFXHandle; private AsyncOperationHandle<IList<AudioClip>> _SFXHandle;
private AsyncOperationHandle<IList<AudioClip>> _enemiesHandle; private AsyncOperationHandle<IList<AudioClip>> _enemiesHandle;
private AsyncOperationHandle<IList<AudioClip>> _dispatcherHandle; private AsyncOperationHandle<IList<AudioClip>> _dispatcherHandle;
private AsyncOperationHandle<IList<AudioClip>> _courierHandle;
public Dictionary<AudioType, AudioClip> AudioTestClips { get; private set; } = new(); public Dictionary<AudioType, AudioClip> AudioTestClips { get; private set; } = new();
public Dictionary<MusicType, List<AudioClip>> MusicDictionary { get; private set; } = new(); public Dictionary<MusicType, List<AudioClip>> MusicDictionary { get; private set; } = new();
public List<AudioClip> SFXAudios { get; private set; } = new(); public List<AudioClip> SFXAudios { get; private set; } = new();
public List<AudioClip> EnemiesAudios { get; private set; } = new(); public List<AudioClip> EnemiesAudios { get; private set; } = new();
public List<AudioClip> CourierAudios { get; private set; } = new();
public List<AudioClip> DispatcherAudios { get; private set; } = new(); public List<AudioClip> DispatcherAudios { get; private set; } = new();
public AudioFactory(AudioMixerConfig audioMixerConfig, public AudioFactory(AudioMixerConfig audioMixerConfig,
@@ -44,7 +48,8 @@ namespace Code.Audio
SFXListConfig sfxListConfig, SFXListConfig sfxListConfig,
EnemiesSoundListConfig enemiesSoundListConfig, EnemiesSoundListConfig enemiesSoundListConfig,
DispatcherSoundListConfig dispatcherSoundListConfig, DispatcherSoundListConfig dispatcherSoundListConfig,
AudioTestClipsConfig audioTestClipsConfig AudioTestClipsConfig audioTestClipsConfig,
CourierSoundListConfig courierSoundListConfig
) )
{ {
AudioMixer = audioMixerConfig.audioMixerAsset; AudioMixer = audioMixerConfig.audioMixerAsset;
@@ -52,15 +57,18 @@ namespace Code.Audio
_peacefulSoundtrack = soundtrackListConfig.peacefulSoundtrack; _peacefulSoundtrack = soundtrackListConfig.peacefulSoundtrack;
_actionSoundtrack = soundtrackListConfig.actionSoundtrack; _actionSoundtrack = soundtrackListConfig.actionSoundtrack;
_deathSoundtrack = soundtrackListConfig.deathSoundtrack;
_menuSoundtrack = soundtrackListConfig.menuSoundtrack; _menuSoundtrack = soundtrackListConfig.menuSoundtrack;
_SFX = sfxListConfig.SFX; _SFX = sfxListConfig.SFX;
_enemies = enemiesSoundListConfig.enemies; _enemies = enemiesSoundListConfig.enemies;
_dispatcher = dispatcherSoundListConfig.dispatcher; _dispatcher = dispatcherSoundListConfig.dispatcher;
_courier = courierSoundListConfig.courierSounds;
_audioTestClipsReferences = audioTestClipsConfig.audioTestClips; _audioTestClipsReferences = audioTestClipsConfig.audioTestClips;
MusicDictionary.Add(MusicType.Menu, new ()); MusicDictionary.Add(MusicType.Menu, new ());
MusicDictionary.Add(MusicType.Peaceful, new ()); MusicDictionary.Add(MusicType.Death, new ());
MusicDictionary.Add(MusicType.Action, new ()); MusicDictionary.Add(MusicType.Action, new ());
MusicDictionary.Add(MusicType.Peaceful, new ());
} }
public async UniTask LoadAudioSourcePrefab(Action<GameObject> callback) => public async UniTask LoadAudioSourcePrefab(Action<GameObject> callback) =>
@@ -112,6 +120,16 @@ namespace Code.Audio
// foreach (var assetReference in _menuSoundtrack) assetReference.ReleaseAsset(); // foreach (var assetReference in _menuSoundtrack) assetReference.ReleaseAsset();
_menuMusicHandle.Release(); _menuMusicHandle.Release();
} }
public async UniTask WarmDeathMusic()
{
_deathMusicHandle = Addressables.LoadAssetsAsync<AudioClip>(_deathSoundtrack, OnDeathTrackLoaded, Addressables.MergeMode.Union);
await _deathMusicHandle.ToUniTask();
}
public void ReleaseDeathMusic()
{
MusicDictionary[MusicType.Death].Clear();
_deathMusicHandle.Release();
}
public async UniTask WarmSFX( ) public async UniTask WarmSFX( )
{ {
_SFXHandle = Addressables.LoadAssetsAsync<AudioClip>(_SFX, OnSFXLoaded, Addressables.MergeMode.Union); _SFXHandle = Addressables.LoadAssetsAsync<AudioClip>(_SFX, OnSFXLoaded, Addressables.MergeMode.Union);
@@ -137,6 +155,18 @@ namespace Code.Audio
EnemiesAudios.Clear(); EnemiesAudios.Clear();
_enemiesHandle.Release(); _enemiesHandle.Release();
} }
public async UniTask WarmCourier()
{
_courierHandle = Addressables.LoadAssetsAsync<AudioClip>(_courier, OnCourierLoaded, Addressables.MergeMode.Union);
await _courierHandle.ToUniTask();
}
public void ReleaseCourier()
{
CourierAudios.Clear();
_courierHandle.Release();
}
public async UniTask WarmDispatcher( ) public async UniTask WarmDispatcher( )
{ {
@@ -156,6 +186,10 @@ namespace Code.Audio
{ {
MusicDictionary[MusicType.Menu].Add(audioClip); MusicDictionary[MusicType.Menu].Add(audioClip);
} }
private void OnDeathTrackLoaded(AudioClip audioClip)
{
MusicDictionary[MusicType.Death].Add(audioClip);
}
// private int _audioTestClipCounter; // private int _audioTestClipCounter;
private void OnAudioTestClipLoaded(AudioClip audioClip) private void OnAudioTestClipLoaded(AudioClip audioClip)
@@ -182,5 +216,9 @@ namespace Code.Audio
{ {
DispatcherAudios.Add(audioClip); DispatcherAudios.Add(audioClip);
} }
private void OnCourierLoaded(AudioClip audioClip)
{
CourierAudios.Add(audioClip);
}
} }
} }
+90 -182
View File
@@ -22,134 +22,104 @@ namespace Code.Audio
private AudioSource _actionMusicSource; private AudioSource _actionMusicSource;
private AudioSource _peacefulMusicSource; private AudioSource _peacefulMusicSource;
private AudioMixerGroup _masterGroup, private Dictionary<AudioType, AudioMixerGroup> _audioMixerGroups = new();
// _musicGroup,
_actionMusicGroup,
_menuMusicGroup,
_peacefulMusicGroup,
_SFXGroup,
_creaturesGroup,
_dispatcherGroup,
_courierGroup,
_enemiesGroup;
private readonly AudioSourcePool _audioSourcePool; private readonly AudioSourcePool _audioSourcePool;
private Dictionary<AudioSnapshotState, AudioMixerSnapshot> _snapshots = new(); // Юнити не может - говнокод поможет.
private Dictionary<AudioSnapshotState, Dictionary<AudioType, float>> _snapshotsVolumes = new();
private Dictionary<AudioSourceType, AudioSourceSettingsConfig> _settings; private Dictionary<AudioSourceType, AudioSourceSettingsConfig> _settings;
public AudioService(IAudioFactory audioFactory, Dictionary<AudioSourceType, AudioSourceSettingsConfig> settings) public AudioService(IAudioFactory audioFactory,
Dictionary<AudioSourceType, AudioSourceSettingsConfig> settings,
DefaultAudioSettingsConfig defaultAudioSettingsConfig)
{ {
_audioFactory = audioFactory; _audioFactory = audioFactory;
_audioSourcePool = new(settings); _audioSourcePool = new(settings);
_settings = settings; _settings = settings;
_snapshotsVolumes.Add(AudioSnapshotState.None,defaultAudioSettingsConfig.noneVolume);
_snapshotsVolumes.Add(AudioSnapshotState.Menu,defaultAudioSettingsConfig.menuVolume);
_snapshotsVolumes.Add(AudioSnapshotState.Action,defaultAudioSettingsConfig.actionVolume);
_snapshotsVolumes.Add(AudioSnapshotState.Peaceful,defaultAudioSettingsConfig.peacefulVolume);
} }
// TODO Грязно, убрать снапшоты НАХУЙ
public float GetSetting(AudioType type) public float GetSetting(AudioType type)
{ {
float value; _mixer.GetFloat(_audioMixerGroups[type].name, out float value);
switch (type)
{
case AudioType.SFX:
_snapshots[AudioSnapshotState.Peaceful].audioMixer.GetFloat(_SFXGroup.name, out value);
break;
case AudioType.Master:
_snapshots[AudioSnapshotState.Menu].audioMixer.GetFloat(_masterGroup.name, out value);
break;
case AudioType.Creatures:
_snapshots[AudioSnapshotState.Peaceful].audioMixer.GetFloat(_creaturesGroup.name, out value);
break;
case AudioType.GameplayMusic:
_snapshots[AudioSnapshotState.Peaceful].audioMixer.GetFloat(_peacefulMusicGroup.name, out value);
break;
case AudioType.MenuMusic:
_snapshots[AudioSnapshotState.Menu].audioMixer.GetFloat(_menuMusicGroup.name, out value);
break;
case AudioType.DispatcherSounds:
_snapshots[AudioSnapshotState.Action].audioMixer.GetFloat(_dispatcherGroup.name, out value);
break;
default:
value = 1;
break;
}
value = Mathf.Pow(10f, value / 20); value = Mathf.Pow(10f, value / 20);
return value; return value;
} }
// TODO Грязно, убрать снапшоты НАХУЙ
public void ChangeSetting(AudioType type, float value) public void ChangeSetting(AudioType type, float value)
{ {
float volume = Mathf.Log10(value) * 20; float volume = Mathf.Log10(value) * 20;
switch (type) switch (type)
{ {
case AudioType.SFX: case AudioType.DeathMusic:
_snapshots[AudioSnapshotState.Peaceful].audioMixer.SetFloat(_SFXGroup.name, volume);
_snapshots[AudioSnapshotState.Action].audioMixer.SetFloat(_SFXGroup.name, volume);
break;
case AudioType.Master: case AudioType.Master:
_snapshots[AudioSnapshotState.Menu].audioMixer.SetFloat(_masterGroup.name, volume); _snapshotsVolumes[AudioSnapshotState.Menu][type] = value;
_snapshots[AudioSnapshotState.Peaceful].audioMixer.SetFloat(_masterGroup.name, volume); _snapshotsVolumes[AudioSnapshotState.Action][type] = value;
_snapshots[AudioSnapshotState.Action].audioMixer.SetFloat(_masterGroup.name, volume); _snapshotsVolumes[AudioSnapshotState.Peaceful][type] = value;
_mixer.SetFloat(_audioMixerGroups[type].name, volume);
break; break;
case AudioType.Creatures: case AudioType.ActionMusic:
_snapshots[AudioSnapshotState.Peaceful].audioMixer.SetFloat(_creaturesGroup.name, volume); _snapshotsVolumes[AudioSnapshotState.Action][type] = value;
_snapshots[AudioSnapshotState.Action].audioMixer.SetFloat(_creaturesGroup.name, volume); _mixer.SetFloat(_audioMixerGroups[type].name, volume);
break; break;
case AudioType.GameplayMusic: case AudioType.PeacefulMusic:
_snapshots[AudioSnapshotState.Peaceful].audioMixer.SetFloat(_peacefulMusicGroup.name, volume); _snapshotsVolumes[AudioSnapshotState.Peaceful][type] = value;
_snapshots[AudioSnapshotState.Action].audioMixer.SetFloat(_actionMusicGroup.name, volume); _mixer.SetFloat(_audioMixerGroups[type].name, volume);
break; break;
case AudioType.MenuMusic: case AudioType.MenuMusic:
_snapshots[AudioSnapshotState.Menu].audioMixer.SetFloat(_menuMusicGroup.name, volume); _snapshotsVolumes[AudioSnapshotState.Menu][type] = value;
break; _mixer.SetFloat(_audioMixerGroups[type].name, volume);
case AudioType.DispatcherSounds: break;
_snapshots[AudioSnapshotState.Peaceful].audioMixer.SetFloat(_dispatcherGroup.name, volume); case AudioType.SFX:
_snapshots[AudioSnapshotState.Action].audioMixer.SetFloat(_dispatcherGroup.name, volume); case AudioType.Dispatcher:
case AudioType.Courier:
case AudioType.Enemies:
_snapshotsVolumes[AudioSnapshotState.Action][type] = value;
_snapshotsVolumes[AudioSnapshotState.Peaceful][type] = value;
_mixer.SetFloat(_audioMixerGroups[type].name, volume);
break; break;
} }
// _mixer.FindSnapshot("Action").audioMixer.SetFloat("music", volume);
} }
public async UniTask Initialize() public async UniTask Initialize()
{ {
// _mixer = await _audioFactory.CreateMixer();
_mixer = _audioFactory.AudioMixer; _mixer = _audioFactory.AudioMixer;
_masterGroup = _mixer.FindMatchingGroups(AudioGroups.MasterGroup)[0];
_menuMusicGroup = _mixer.FindMatchingGroups(AudioGroups.MenuMusicGroup)[0];
_actionMusicGroup = _mixer.FindMatchingGroups(AudioGroups.ActionMusicGroup)[0];
_peacefulMusicGroup = _mixer.FindMatchingGroups(AudioGroups.PeacefulMusicGroup)[0];
// _musicGroup = _mixer.FindMatchingGroups(AudioGroups.MusicGroup)[0];
_musicAudioGroups.Add(MusicType.Menu, _mixer.FindMatchingGroups(AudioGroups.MenuMusicGroup)[0]); _musicAudioGroups.Add(MusicType.Menu, _mixer.FindMatchingGroups(AudioGroups.MenuMusicGroup)[0]);
_musicAudioGroups.Add(MusicType.Death, _mixer.FindMatchingGroups(AudioGroups.DeathMusicGroup)[0]);
_musicAudioGroups.Add(MusicType.Action, _mixer.FindMatchingGroups(AudioGroups.ActionMusicGroup)[0]); _musicAudioGroups.Add(MusicType.Action, _mixer.FindMatchingGroups(AudioGroups.ActionMusicGroup)[0]);
_musicAudioGroups.Add(MusicType.Peaceful, _mixer.FindMatchingGroups(AudioGroups.PeacefulMusicGroup)[0]); _musicAudioGroups.Add(MusicType.Peaceful, _mixer.FindMatchingGroups(AudioGroups.PeacefulMusicGroup)[0]);
_cancellationTokenSources.Add(MusicType.Menu, new()); _cancellationTokenSources.Add(MusicType.Menu, new());
_cancellationTokenSources.Add(MusicType.Death, new());
_cancellationTokenSources.Add(MusicType.Action, new()); _cancellationTokenSources.Add(MusicType.Action, new());
_cancellationTokenSources.Add(MusicType.Peaceful, new()); _cancellationTokenSources.Add(MusicType.Peaceful, new());
_musicAudioSources.Add(MusicType.Menu, null); _musicAudioSources.Add(MusicType.Menu, null);
_musicAudioSources.Add(MusicType.Death, null);
_musicAudioSources.Add(MusicType.Action, null); _musicAudioSources.Add(MusicType.Action, null);
_musicAudioSources.Add(MusicType.Peaceful, null); _musicAudioSources.Add(MusicType.Peaceful, null);
_SFXGroup = _mixer.FindMatchingGroups(AudioGroups.SFXGroup)[0]; _audioMixerGroups.Add(AudioType.Master, _mixer.FindMatchingGroups(AudioGroups.MasterGroup)[0]);
_creaturesGroup = _mixer.FindMatchingGroups(AudioGroups.CreaturesGroup)[0]; _audioMixerGroups.Add(AudioType.SFX, _mixer.FindMatchingGroups(AudioGroups.SFXGroup)[0]);
_dispatcherGroup = _mixer.FindMatchingGroups(AudioGroups.DispatcherMusicGroup)[0]; _audioMixerGroups.Add(AudioType.Dispatcher, _mixer.FindMatchingGroups(AudioGroups.DispatcherMusicGroup)[0]);
_courierGroup = _mixer.FindMatchingGroups(AudioGroups.CourierMusicGroup)[0]; _audioMixerGroups.Add(AudioType.Courier, _mixer.FindMatchingGroups(AudioGroups.CourierGroup)[0]);
_enemiesGroup = _mixer.FindMatchingGroups(AudioGroups.EnemiesMusicGroup)[0]; _audioMixerGroups.Add(AudioType.Enemies, _mixer.FindMatchingGroups(AudioGroups.EnemiesGroup)[0]);
_audioMixerGroups.Add(AudioType.MenuMusic, _musicAudioGroups[MusicType.Menu]);
_audioMixerGroups.Add(AudioType.DeathMusic, _musicAudioGroups[MusicType.Death]);
_audioMixerGroups.Add(AudioType.ActionMusic, _musicAudioGroups[MusicType.Action]);
_audioMixerGroups.Add(AudioType.PeacefulMusic, _musicAudioGroups[MusicType.Peaceful]);
_snapshots[AudioSnapshotState.None] = _mixer.FindSnapshot(AudioGroups.NoneSnapshot);
_snapshots[AudioSnapshotState.Peaceful] = _mixer.FindSnapshot(AudioGroups.PeacefulSnapshot);
_snapshots[AudioSnapshotState.Action] = _mixer.FindSnapshot(AudioGroups.ActionSnapshot);
_snapshots[AudioSnapshotState.Menu] = _mixer.FindSnapshot(AudioGroups.MenuSnapshot);
await _audioFactory.LoadAudioSourcePrefab(_audioSourcePool.Initialize); await _audioFactory.LoadAudioSourcePrefab(_audioSourcePool.Initialize);
} }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
private Dictionary<MusicType, CancellationTokenSource> _cancellationTokenSources = new(); private Dictionary<MusicType, CancellationTokenSource> _cancellationTokenSources = new();
private Dictionary<MusicType, AudioSource> _musicAudioSources = new(); private Dictionary<MusicType, AudioSource> _musicAudioSources = new();
private Dictionary<MusicType, AudioMixerGroup> _musicAudioGroups = new(); private Dictionary<MusicType, AudioMixerGroup> _musicAudioGroups = new();
@@ -169,19 +139,13 @@ namespace Code.Audio
_musicAudioSources[musicType].Play(); _musicAudioSources[musicType].Play();
// await UniTask.WaitUntilValueChanged(_musicAudioSources[musicType],
// _ => !_musicAudioSources[musicType].isPlaying,
// cancellationToken: _cancellationTokenSources[musicType].Token);
await UniTask.NextFrame(); await UniTask.NextFrame();
// Debug.Log($"Playing {musicType}");
var (isCanceled, _) = await UniTask.WaitUntilValueChanged(_musicAudioSources[musicType], var (isCanceled, _) = await UniTask.WaitUntilValueChanged(_musicAudioSources[musicType],
_ => !_musicAudioSources[musicType].isPlaying, _ => !_musicAudioSources[musicType].isPlaying,
cancellationToken: _cancellationTokenSources[musicType].Token).SuppressCancellationThrow(); cancellationToken: _cancellationTokenSources[musicType].Token).SuppressCancellationThrow();
// Debug.Log($"Finished {musicType}"); Debug.LogError("Music skipping");
if (isCanceled) if (isCanceled)
{ {
// Debug.Log($"Cancelled {musicType}");
_cancellationTokenSources[musicType].Dispose(); _cancellationTokenSources[musicType].Dispose();
_cancellationTokenSources[musicType] = new(); _cancellationTokenSources[musicType] = new();
@@ -191,13 +155,13 @@ namespace Code.Audio
return; return;
} }
PlayRandomMusicUntilHumanityWillBeDestroyedForTheySins(musicType); PlayRandomMusicUntilHumanityWillBeDestroyedForTheySins(musicType).Forget();
} }
public async UniTaskVoid GladlyAskToStopMusic(MusicType musicType, public async UniTaskVoid GladlyAskToStopMusic(MusicType musicType,
AudioSnapshotState audioSnapshotState = AudioSnapshotState.None, float time = 1f, Action callback = null) AudioSnapshotState audioSnapshotState = AudioSnapshotState.None, float time = 1f, Action callback = null)
{ {
TransitToSnapshot(audioSnapshotState, time); //TransitToSnapshot(audioSnapshotState, time);
await UniTask.WaitForSeconds(time); await UniTask.WaitForSeconds(time);
@@ -205,39 +169,56 @@ namespace Code.Audio
callback?.Invoke(); callback?.Invoke();
} }
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
public void StopMusic() public void StopMusic()
{ {
_peacefulMusicSource.Stop(); _peacefulMusicSource.Stop();
_actionMusicSource.Stop(); _actionMusicSource.Stop();
_cancellationTokenSources[MusicType.Peaceful].Cancel();
_cancellationTokenSources[MusicType.Action].Cancel();
} }
public void GladlyAskToStopMusic(Action callback = null) public void GladlyAskToStopMusic(Action callback = null)
{ {
TransitToSnapshot(AudioSnapshotState.None); // TransitToSnapshot(AudioSnapshotState.None);
_peacefulMusicSource.Stop(); _peacefulMusicSource.Stop();
_actionMusicSource.Stop(); _actionMusicSource.Stop();
callback?.Invoke(); callback?.Invoke();
} }
public void TransitToSnapshot(AudioSnapshotState state, float time = 1f) public void TransitToSnapshot(AudioSnapshotState state, float time = 1)
{ {
_snapshots[state].TransitionTo(time); foreach (var key in _audioMixerGroups.Keys)
_mixer.DOSetFloat(_audioMixerGroups[key].name, Mathf.Log10(_snapshotsVolumes[state][key]) * 20, time);
} }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
public void PlaySFX(SFXSounds sfxId, Vector3 position) public void PlaySFX(SFXSounds sfxId, Vector3 position)
{ {
_audioSourcePool.PlayOneShot(_audioFactory.SFXAudios[(int)sfxId], position, _SFXGroup); _audioSourcePool
.PlayOneShot(_audioFactory.SFXAudios[(int)sfxId], position, _audioMixerGroups[AudioType.SFX]).Forget();
}
public void ApplyStun(float value, float time)
{
_mixer.DOSetFloat("Stun", value, time);
} }
public void PlayEnemy(EnemiesSounds enemySoundId, Vector3 position) public void PlayEnemy(EnemiesSounds enemySoundId, Vector3 position)
{ {
_audioSourcePool.PlayOneShot(_audioFactory.EnemiesAudios[(int)enemySoundId], position, _enemiesGroup); _audioSourcePool.PlayOneShot(_audioFactory.EnemiesAudios[(int)enemySoundId], position,
_audioMixerGroups[AudioType.Enemies]).Forget();
} }
public AudioSource GetSourceOfGroup(AudioType group)
{
AudioSource source = _audioSourcePool.GetSource();
source.outputAudioMixerGroup = _audioMixerGroups[group];
return source;
}
public void ReleaseSourceOfGroup(AudioSource source) => _audioSourcePool.ReleaseSource(source);
// Чинить долго и дорого пусть Артёмов будет много, ведь он наш друг // Чинить долго и дорого пусть Артёмов будет много, ведь он наш друг
public event IAudioService.OnAudioPlayingDelegate OnDispatcherStarted; public event IAudioService.OnAudioPlayingDelegate OnDispatcherStarted;
public event IAudioService.OnAudioPlayingDelegate OnDispatcherEnded; public event IAudioService.OnAudioPlayingDelegate OnDispatcherEnded;
@@ -245,108 +226,35 @@ namespace Code.Audio
public void PlayDispatcher(DispatcherSounds dispatcherSoundId) public void PlayDispatcher(DispatcherSounds dispatcherSoundId)
{ {
OnDispatcherStarted?.Invoke(); OnDispatcherStarted?.Invoke();
_audioSourcePool.PlayOneShot(_audioFactory.DispatcherAudios[(int)dispatcherSoundId], _dispatcherGroup, _audioSourcePool.PlayOneShot(_audioFactory.DispatcherAudios[(int)dispatcherSoundId],
AudioSourceType.NoBlend, () => OnDispatcherEnded?.Invoke()); _audioMixerGroups[AudioType.Dispatcher],
AudioSourceType.NoBlend, () => OnDispatcherEnded?.Invoke()).Forget();
} }
public void PlayCourier(CourierSounds courierSounds)
{
_audioSourcePool.PlayOneShot(_audioFactory.CourierAudios[(int)courierSounds],
_audioMixerGroups[AudioType.Courier],
AudioSourceType.NoBlend).Forget();
}
private CancellationTokenSource _testClipCancellationTokenSource = new(); private CancellationTokenSource _testClipCancellationTokenSource = new();
private void ResetCurrentTestAudioSource() => _currentTestClipAudioType = AudioType.Master; private void ResetCurrentTestAudioSource() => _currentTestClipAudioType = AudioType.Master;
private AudioType _currentTestClipAudioType;
// TODO Засунуть в словарь // TODO Засунуть в словарь
public void PlayTestClip(AudioType audioType) public void PlayTestClip(AudioType audioType)
{ {
if(_currentTestClipAudioType == audioType) return; if (_currentTestClipAudioType == audioType) return;
_testClipCancellationTokenSource.Cancel(); _testClipCancellationTokenSource.Cancel();
_testClipCancellationTokenSource = new(); _testClipCancellationTokenSource = new();
_currentTestClipAudioType = audioType; _currentTestClipAudioType = audioType;
switch (audioType) _audioSourcePool.PlayOneShot(_audioFactory.AudioTestClips[audioType],
{ _audioMixerGroups[audioType], _testClipCancellationTokenSource,
case AudioType.SFX: AudioSourceType.NoBlend, ResetCurrentTestAudioSource).Forget();
_audioSourcePool.PlayOneShot(_audioFactory.AudioTestClips[audioType],
_SFXGroup, _testClipCancellationTokenSource,
AudioSourceType.NoBlend, ResetCurrentTestAudioSource);
break;
case AudioType.Master:
_audioSourcePool.PlayOneShot(_audioFactory.AudioTestClips[audioType],
_masterGroup, _testClipCancellationTokenSource,
AudioSourceType.NoBlend, ResetCurrentTestAudioSource);
break;
case AudioType.Creatures:
_audioSourcePool.PlayOneShot( _audioFactory.AudioTestClips[audioType],
_creaturesGroup, _testClipCancellationTokenSource,
AudioSourceType.NoBlend, ResetCurrentTestAudioSource);
break;
case AudioType.GameplayMusic:
_audioSourcePool.PlayOneShot(_audioFactory.AudioTestClips[audioType],
_actionMusicGroup, _testClipCancellationTokenSource,
AudioSourceType.NoBlend, ResetCurrentTestAudioSource);
break;
case AudioType.MenuMusic:
_audioSourcePool.PlayOneShot(_audioFactory.AudioTestClips[audioType],
_menuMusicGroup, _testClipCancellationTokenSource,
AudioSourceType.NoBlend, ResetCurrentTestAudioSource);
break;
case AudioType.DispatcherSounds:
_audioSourcePool.PlayOneShot(_audioFactory.AudioTestClips[audioType],
_dispatcherGroup, _testClipCancellationTokenSource,
AudioSourceType.NoBlend, ResetCurrentTestAudioSource);
break;
}
}
private AudioSource _testClipAudioSource;
private AudioType _currentTestClipAudioType;
// Эффективно и просто, может не так хитровыебано
private void ReleaseTestAudioClipSource()
{
_testClipAudioSource = null;
}
// TODO Засунуть в словарь
public void PlayTestClipDeprecated(AudioType audioType)
{
if (!_testClipAudioSource) _testClipAudioSource = _audioSourcePool.GetSource();
else if (_currentTestClipAudioType != audioType) _testClipAudioSource.Stop();
else return;
_currentTestClipAudioType = audioType;
switch (audioType)
{
case AudioType.SFX:
_audioSourcePool.PlayOneShot(_testClipAudioSource, _audioFactory.AudioTestClips[audioType],
_SFXGroup,
AudioSourceType.NoBlend, ReleaseTestAudioClipSource);
break;
case AudioType.Master:
_audioSourcePool.PlayOneShot(_testClipAudioSource, _audioFactory.AudioTestClips[audioType],
_masterGroup,
AudioSourceType.NoBlend, ReleaseTestAudioClipSource);
break;
case AudioType.Creatures:
_audioSourcePool.PlayOneShot(_testClipAudioSource, _audioFactory.AudioTestClips[audioType],
_creaturesGroup,
AudioSourceType.NoBlend, ReleaseTestAudioClipSource);
break;
case AudioType.GameplayMusic:
_audioSourcePool.PlayOneShot(_testClipAudioSource, _audioFactory.AudioTestClips[audioType],
_actionMusicGroup,
AudioSourceType.NoBlend, ReleaseTestAudioClipSource);
break;
case AudioType.MenuMusic:
_audioSourcePool.PlayOneShot(_testClipAudioSource, _audioFactory.AudioTestClips[audioType],
_menuMusicGroup,
AudioSourceType.NoBlend, ReleaseTestAudioClipSource);
break;
case AudioType.DispatcherSounds:
_audioSourcePool.PlayOneShot(_testClipAudioSource, _audioFactory.AudioTestClips[audioType],
_dispatcherGroup,
AudioSourceType.NoBlend, ReleaseTestAudioClipSource);
break;
}
} }
} }
} }
@@ -14,6 +14,7 @@ namespace Code.Audio
List<AudioClip> SFXAudios { get; } List<AudioClip> SFXAudios { get; }
List<AudioClip> EnemiesAudios { get; } List<AudioClip> EnemiesAudios { get; }
List<AudioClip> DispatcherAudios { get; } List<AudioClip> DispatcherAudios { get; }
List<AudioClip> CourierAudios { get; }
UniTask LoadAudioSourcePrefab(Action<GameObject> callback); UniTask LoadAudioSourcePrefab(Action<GameObject> callback);
UniTask WarmGameplayMusic( ); UniTask WarmGameplayMusic( );
void ReleaseActionMusic(); void ReleaseActionMusic();
@@ -28,5 +29,9 @@ namespace Code.Audio
void ReleaseEnemies(); void ReleaseEnemies();
UniTask WarmDispatcher( ); UniTask WarmDispatcher( );
void ReleaseDispatcher(); void ReleaseDispatcher();
UniTask WarmCourier();
void ReleaseCourier();
UniTask WarmDeathMusic( );
void ReleaseDeathMusic();
} }
} }
@@ -23,5 +23,9 @@ namespace Code.Audio
void ChangeSetting(AudioType type, float value); void ChangeSetting(AudioType type, float value);
float GetSetting(AudioType type); float GetSetting(AudioType type);
void PlayTestClip(AudioType audioType); void PlayTestClip(AudioType audioType);
AudioSource GetSourceOfGroup(AudioType group);
void ReleaseSourceOfGroup(AudioSource source);
void PlayCourier(CourierSounds range);
void ApplyStun(float value, float time);
} }
} }
+10 -6
View File
@@ -4,15 +4,19 @@ namespace Code.Audio
{ {
Menu, Menu,
Peaceful, Peaceful,
Action Action,
Death
} }
public enum AudioType public enum AudioType
{ {
Master, Master,
MenuMusic, MenuMusic,
GameplayMusic, Dispatcher,
Creatures, SFX,
DispatcherSounds, Courier,
SFX Enemies,
ActionMusic,
PeacefulMusic,
DeathMusic
} }
} }
@@ -1,6 +1,6 @@
using UnityEngine; using UnityEngine;
using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets;
using UnityEngine.Audio; using UnityEngine.Audio;
namespace Code.Configs namespace Code.Configs
{ {
@@ -5,37 +5,42 @@ namespace Code.Configs
[CreateAssetMenu(fileName = "CharacterConfig", menuName = "Config/CharacterConfig")] [CreateAssetMenu(fileName = "CharacterConfig", menuName = "Config/CharacterConfig")]
public class CharacterConfig : ScriptableObject public class CharacterConfig : ScriptableObject
{ {
// Основное движение по земле
public float public float
maxStableMoveSpeed = 8f, // Максимальная скорость движения по устойчивой поверхности maxStableMoveSpeed = 12f,
stableMovementSharpness = 15f, // Резкость изменения скорости движения (чем выше - тем резче) stableMovementSharpness = 15f,
orientationSharpness = 10f, // Резкость изменения вращения персонажа (чем выше - тем резче) orientationSharpness = 10f,
jumpSpeed = 10f; // Скорость прыжка jumpSpeed = 10f;
// Спринт public float
dashSpeed = 20f,
dashDuration = 0.35f,
dashCooldown = 1.2f;
public AnimationCurve slideVelocityCurve = new(
new Keyframe(0.0f, 1.0f),
new Keyframe(0.3f, 1.4f),
new Keyframe(1.0f, 0.2f)
);
public float
slideMinVelocityThreshold = 3f,
slideCooldown = 1.5f;
public float public float
sprintMoveSpeed = 12f, // Максимальная скорость спринта leanAngle = 25f,
sprintAngleThreshold = 90f; // Максимальный угол (в градусах) от направления вперёд, при котором разрешён спринт leanThreshold = 0.3f,
leanSmoothSpeed = 10f;
// Слайд public Vector3 gravity = new(0f, -30f, 0f);
public float public float
slideSpeed = 20f, // Скорость слайда maxAirSpeed = 10f,
slideDuration = 0.8f, // Длительность слайда в секундах airControlSharpness = 8f;
slideCooldown = 1.5f; // Время перезарядки слайда в секундах
// Залазание на стены
public float
wallClimbSpeedFactor = 0.8f, // Коэффициент преобразования горизонтальной скорости в вертикальную при залазании на стену
minWallClimbSpeed = 9f, // Минимальная горизонтальная скорость для начала залазания на стену
wallDetectionAngleThreshold = 80f; // Максимальный угол (в градусах) от вертикали, при котором поверхность считается "стеной"
// Наклон при залазании на стены public float
public float wallRunMaxTime = 1.75f,
maxWallLeanAngle = 45f, // Максимальный угол наклона от стены (в градусах) wallRunSpeed = 15f,
wallLeanSharpness = 50f, // Скорость наклона/выпрямления (чем выше — тем резче) wallRunAcceleration = 25f,
wallLeanHeightScale = 0.1f; // Множитель: на сколько метров подъёма = 1 единица "наклона" wallRunGravityScale = 0.25f,
wallDetachImpulse = 7f,
// Гравитация wallContactAngleThreshold = 45f;
public Vector3 gravity = new(0f, -30f, 0f); // Вектор, отвечающий за применение гравитации
} }
} }
@@ -1,11 +0,0 @@
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace Code.Configs
{
[CreateAssetMenu(menuName = "Config/Audio/CharacterSoundList", fileName = "CharacterSoundListConfig")]
public class CharacterSoundListConfig : ScriptableObject
{
public AssetReference[] character;
}
}
@@ -0,0 +1,11 @@
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace Code.Configs
{
[CreateAssetMenu(menuName = "Config/Audio/CourierSoundListConfig", fileName = "CourierSoundListConfig")]
public class CourierSoundListConfig : ScriptableObject
{
public AssetReference[] courierSounds;
}
}
@@ -0,0 +1,27 @@
using System.Collections.Generic;
using AYellowpaper.SerializedCollections;
using UnityEngine;
using AudioType = Code.Audio.AudioType;
namespace Code.Configs
{
[CreateAssetMenu(fileName = "DefaultAudioSettingsConfig", menuName = "Audio/DefaultAudioSettings")]
public class DefaultAudioSettingsConfig : ScriptableObject
{
[Header("Menu")]
[SerializedDictionary("AudioType", "Volume")]
public SerializedDictionary<Audio.AudioType, float> menuVolume = new();
[Header("Action")]
[SerializedDictionary("AudioType", "Volume")]
public SerializedDictionary<Audio.AudioType, float> actionVolume = new();
[Header("Peaceful")]
[SerializedDictionary("AudioType", "Volume")]
public SerializedDictionary<Audio.AudioType, float> peacefulVolume = new();
[Header("None")]
[SerializedDictionary("AudioType", "Volume")]
public SerializedDictionary<Audio.AudioType, float> noneVolume = new();
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 36d35c52933d4d4ba836f75b05c4810f
timeCreated: 1764754933
@@ -0,0 +1,10 @@
using UnityEngine;
namespace Code.Configs
{
[CreateAssetMenu(menuName = "Config/Audio/MusicPlayer", fileName = "MusicPlayerConfig")]
public class MusicPlayerConfig : ScriptableObject
{
public float threshold = 0.5f;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8708e3c129d241b08563f1a170bd3a44
timeCreated: 1764585060
@@ -8,6 +8,7 @@ namespace Code.Configs
{ {
public AssetReference[] peacefulSoundtrack; public AssetReference[] peacefulSoundtrack;
public AssetReference[] actionSoundtrack; public AssetReference[] actionSoundtrack;
public AssetReference[] deathSoundtrack;
public AssetReference[] menuSoundtrack; public AssetReference[] menuSoundtrack;
} }
} }
@@ -19,13 +19,14 @@ namespace Code.Constants
public const string PeacefulMusicGroup = "Peaceful"; public const string PeacefulMusicGroup = "Peaceful";
public const string ActionMusicGroup = "Action"; public const string ActionMusicGroup = "Action";
public const string DispatcherMusicGroup = "Dispatcher"; public const string DispatcherMusicGroup = "Dispatcher";
public const string CourierMusicGroup = "Courier"; public const string CourierGroup = "Courier";
public const string EnemiesMusicGroup = "Enemies"; public const string EnemiesGroup = "Enemies";
public const string PeacefulSnapshot = "Peaceful"; public const string PeacefulSnapshot = "Peaceful";
public const string ActionSnapshot = "Action"; public const string ActionSnapshot = "Action";
public const string NoneSnapshot = "None"; public const string NoneSnapshot = "None";
public const string MenuSnapshot = "Menu"; public const string MenuSnapshot = "Menu";
public const string MenuMusicGroup = "Menu"; public const string MenuMusicGroup = "Menu";
public const string DeathMusicGroup = "Death";
} }
} }
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bb5ad0cc3a72448a93ee2adb560c35ad
timeCreated: 1764345160
@@ -0,0 +1,12 @@
using UnityEngine;
namespace Code.DebugAndTest
{
public class TriggerTest : MonoBehaviour
{
private void OnTriggerEnter(Collider other)
{
Debug.Log(gameObject.name + " found " + other.name);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6bb3c649d82049079d00b843a76aced8
timeCreated: 1764345168
@@ -24,6 +24,8 @@ namespace Code.Gameplay.Camera.CameraStates
CurrentDistance = 0f; CurrentDistance = 0f;
Camera.fieldOfView = Context.CameraSettingsConfigs[CameraMode.FirstPerson].fov; Camera.fieldOfView = Context.CameraSettingsConfigs[CameraMode.FirstPerson].fov;
Cursor.lockState = CursorLockMode.Locked;
} }
protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation) protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
@@ -11,6 +11,7 @@ namespace Code.Gameplay.Camera.CameraStates
base.EnterState(); base.EnterState();
Camera.fieldOfView = Context.CameraSettingsConfigs[CameraMode.MainMenu].fov; Camera.fieldOfView = Context.CameraSettingsConfigs[CameraMode.MainMenu].fov;
Cursor.lockState = CursorLockMode.None;
} }
protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation) protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
@@ -12,6 +12,7 @@ namespace Code.Gameplay.Camera.CameraStates
base.EnterState(); base.EnterState();
Camera.fieldOfView = Context.CameraSettingsConfigs[CameraMode.Static].fov; Camera.fieldOfView = Context.CameraSettingsConfigs[CameraMode.Static].fov;
Cursor.lockState = CursorLockMode.None;
} }
protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation) protected override void HandlePosition(float deltaTime, float zoomInput, Quaternion targetRotation)
@@ -0,0 +1,82 @@
using UnityEngine;
using Code.Gameplay.Camera;
using KinematicCharacterController;
namespace Code.Gameplay.Character.Controller.Abilities
{
public class DashMechanic
{
private readonly float _dashSpeed;
private readonly float _dashDuration;
private readonly float _dashCooldown;
private float _dashTimer;
private float _dashCooldownTimer;
private Vector3 _dashDirection;
private bool _dashRequested;
public bool IsDashing { get; private set; }
public DashMechanic(float dashSpeed, float dashDuration, float dashCooldown)
{
_dashSpeed = dashSpeed;
_dashDuration = dashDuration;
_dashCooldown = dashCooldown;
}
public void TickCooldown(float deltaTime)
{
if (_dashCooldownTimer > 0f) _dashCooldownTimer -= deltaTime;
}
public void RequestDash(bool dashPressed)
{
if (dashPressed && !_dashRequested && _dashCooldownTimer <= 0f)
_dashRequested = true;
}
public void TryStartDash(KinematicCharacterMotor motor,
CameraMode currentCameraMode,
Quaternion firstPersonCameraRotation,
Vector3 lookInputVector)
{
if (!_dashRequested || !motor.GroundingStatus.IsStableOnGround || _dashCooldownTimer > 0f)
{
_dashRequested = false;
return;
}
IsDashing = true;
_dashTimer = _dashDuration;
var dir = currentCameraMode == CameraMode.FirstPerson
? firstPersonCameraRotation * Vector3.forward
: lookInputVector;
_dashDirection = Vector3.ProjectOnPlane(dir, motor.CharacterUp).normalized;
if (_dashDirection.sqrMagnitude < 0.01f) _dashDirection = motor.CharacterForward;
_dashCooldownTimer = _dashCooldown;
_dashRequested = false;
}
public void HandleDash(ref Vector3 currentVelocity, float deltaTime, KinematicCharacterMotor motor)
{
_dashTimer -= deltaTime;
if (_dashTimer <= 0f || !motor.GroundingStatus.IsStableOnGround)
{
EndDash();
return;
}
currentVelocity = _dashDirection * _dashSpeed;
currentVelocity += motor.CharacterUp * 1.5f;
}
public void EndDash()
{
IsDashing = false;
_dashTimer = 0f;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6d62efb53e0c4d49be9fc658484e2575
timeCreated: 1764856437
@@ -1,122 +1,91 @@
using UnityEngine;
using Code.Gameplay.Camera; using Code.Gameplay.Camera;
using KinematicCharacterController; using KinematicCharacterController;
using UnityEngine;
namespace Code.Gameplay.Character.Controller.Abilities namespace Code.Gameplay.Character.Controller.Abilities
{ {
/*
* Механика слайда для персонажа
* Отвечает за управление состоянием, таймерами и скоростью слайда
*/
public class SlideMechanic public class SlideMechanic
{ {
// Скорость слайда private readonly AnimationCurve _velocityCurve;
private readonly float _slideSpeed; private readonly float _minVelocityThreshold;
// Длительность слайда в секундах private readonly float _cooldown;
private readonly float _slideDuration;
// Время перезарядки слайда
private readonly float _slideCooldown;
// Таймер слайда private float _slideTime;
private float _slideTimer; private float _cooldownTimer;
// Таймер перезарядки слайда
private float _slideCooldownTimer;
// Направление слайда
private Vector3 _slideDirection; private Vector3 _slideDirection;
// Флаг запроса слайда
private bool _slideRequested; private bool _slideRequested;
private float _initialSpeed;
// Свойство-флаг, активен ли слайд
public bool IsSliding { get; private set; } public bool IsSliding { get; private set; }
// Конструктор механики слайда public SlideMechanic(AnimationCurve velocityCurve, float minVelocityThreshold, float cooldown)
public SlideMechanic(float slideSpeed, float slideDuration, float slideCooldown)
{ {
_slideSpeed = slideSpeed; _velocityCurve = velocityCurve;
_slideDuration = slideDuration; _minVelocityThreshold = minVelocityThreshold;
_slideCooldown = slideCooldown; _cooldown = cooldown;
} }
// Обновляем таймер перезарядки слайда
public void TickCooldown(float deltaTime) public void TickCooldown(float deltaTime)
{ {
if (_slideCooldownTimer > 0f) if (_cooldownTimer > 0f) _cooldownTimer -= deltaTime;
{
_slideCooldownTimer -= deltaTime;
}
} }
// Обработка слайда
public void RequestSlide(bool slidePressed) public void RequestSlide(bool slidePressed)
{ {
if (slidePressed && !_slideRequested && _slideCooldownTimer <= 0f) if (slidePressed && !_slideRequested && _cooldownTimer <= 0f)
{
_slideRequested = true; _slideRequested = true;
}
} }
// Начало слайда
public void TryStartSlide(KinematicCharacterMotor motor, public void TryStartSlide(KinematicCharacterMotor motor,
CameraMode currentCameraMode, CameraMode currentCameraMode,
Quaternion firstPersonCameraRotation, Quaternion firstPersonCameraRotation,
Vector3 lookInputVector) Vector3 lookInputVector)
{ {
// Проверяем условия для старта слайда if (!_slideRequested || !motor.GroundingStatus.IsStableOnGround || _cooldownTimer > 0f)
if (!_slideRequested || !motor.GroundingStatus.IsStableOnGround || _slideCooldownTimer > 0f)
{ {
_slideRequested = false; _slideRequested = false;
return; return;
} }
IsSliding = true; IsSliding = true;
_slideTimer = _slideDuration; _slideTime = 0f;
// НАПРАВЛЕНИЕ СЛАЙДА - ВСЕГДА ВПЕРЕД ПО КАМЕРЕ
// Используем направление камеры, но проецируем на горизонтальную плоскость
var slideDir = currentCameraMode == CameraMode.FirstPerson ?
firstPersonCameraRotation * Vector3.forward :
lookInputVector;
// Проецируем на горизонтальную плоскость и нормализуем
_slideDirection = Vector3.ProjectOnPlane(slideDir, motor.CharacterUp).normalized;
// Если направление нулевое (персонаж стоит на месте), используем направление вперед
if (_slideDirection.sqrMagnitude < 0.01f)
{
_slideDirection = motor.CharacterForward;
}
// Устанавливаем перезарядку var dir = currentCameraMode == CameraMode.FirstPerson
_slideCooldownTimer = _slideCooldown; ? firstPersonCameraRotation * Vector3.forward
: lookInputVector;
_slideDirection = Vector3.ProjectOnPlane(dir, motor.CharacterUp).normalized;
if (_slideDirection.sqrMagnitude < 0.01f) _slideDirection = motor.CharacterForward;
_initialSpeed = motor.Velocity.magnitude;
if (_initialSpeed < 12f) _initialSpeed = 12f; // fallback
_cooldownTimer = _cooldown;
_slideRequested = false; _slideRequested = false;
} }
// Обработка слайда
public void HandleSlide(ref Vector3 currentVelocity, float deltaTime, KinematicCharacterMotor motor) public void HandleSlide(ref Vector3 currentVelocity, float deltaTime, KinematicCharacterMotor motor)
{ {
// Уменьшаем таймер слайда if (!IsSliding) return;
_slideTimer -= deltaTime;
_slideTime += deltaTime;
// Если время слайда вышло, персонаж в воздухе - заканчиваем слайд var t = Mathf.Clamp01(_slideTime / 2.5f);
if (_slideTimer <= 0f || !motor.GroundingStatus.IsStableOnGround) var speedMult = _velocityCurve.Evaluate(t);
{
var targetSpeed = _initialSpeed * speedMult;
currentVelocity = _slideDirection * targetSpeed;
currentVelocity += motor.CharacterUp * 1f;
if (targetSpeed < _minVelocityThreshold || !motor.GroundingStatus.IsStableOnGround)
EndSlide(); EndSlide();
return;
}
// Устанавливаем скорость слайда вперед
// Используем прямую установку скорости вместо сложных вычислений
currentVelocity = _slideDirection * _slideSpeed;
// Добавляем небольшую вертикальную компоненту для лучшего скольжения по неровностям
currentVelocity += motor.CharacterUp * 2f;
} }
// Завершение слайда
public void EndSlide() public void EndSlide()
{ {
IsSliding = false; IsSliding = false;
_slideTimer = 0f; _slideTime = 0f;
} }
} }
} }
@@ -1,147 +1,78 @@
using UnityEngine; using UnityEngine;
using KinematicCharacterController;
namespace Code.Gameplay.Character.Controller.Abilities namespace Code.Gameplay.Character.Controller.Abilities
{ {
/*
* Механика наклона персонажа при контакте со стеной
* Управляет визуальным наклоном модели в зависимости от высоты подъёма по стене
*/
public class WallLeanMechanic public class WallLeanMechanic
{ {
private readonly float _maxLeanAngle; private readonly float _leanAngle;
private readonly float _leanSharpness; private readonly float _threshold;
private readonly float _heightScale; private readonly float _smoothSpeed;
private Transform _characterTransform;
private Vector3 _lastWallNormal;
private float _lastWallContactHeight;
private float _leanFactor;
private float _leanSign;
private Vector3 _leanDirection;
private Vector3 _lastWallContactPoint;
private bool _isLeaningOnWall;
private const float WallProximityThreshold = 0.6f;
public WallLeanMechanic(float maxLeanAngle, float leanSharpness, float heightScale) private Transform _model;
public WallLeanMechanic(
float leanAngle,
float threshold,
float smoothSpeed)
{ {
_maxLeanAngle = maxLeanAngle; _leanAngle = leanAngle;
_leanSharpness = leanSharpness; _threshold = threshold;
_heightScale = heightScale; _smoothSpeed = smoothSpeed;
} }
// Назначаем трансформ визуальной модели один раз public void SetModel(Transform model) => _model = model;
public void SetCharacterTransform(Transform transform)
public void Update(bool isWallRunning, Vector3 wallNormal, Vector3 characterForward)
{ {
_characterTransform = transform; if (!_model)
}
// Вызывается из OnMovementHit
public void OnWallContact(KinematicCharacterMotor motor, Vector3 wallNormal, float contactHeight)
{
// Только если это действительно стена (не пол/потолок)
var dotWithUp = Vector3.Dot(wallNormal, motor.CharacterUp);
if (Mathf.Abs(dotWithUp) > 0.7f) // ~45°, можно настроить
return;
_lastWallNormal = wallNormal;
_lastWallContactHeight = contactHeight;
_lastWallContactPoint = motor.TransientPosition;
// Пересчитываем направление наклона
_leanDirection = -_lastWallNormal;
_leanDirection = Vector3.ProjectOnPlane(_leanDirection, motor.CharacterUp).normalized;
_leanSign = 1;
// what the fuck
if (_leanDirection.x != 0)
{ {
switch (_leanDirection.x) _model.localRotation = Quaternion.identity;
{
case -1 or 1 when motor.CharacterRight.x > 0.1f:
_leanSign = -1;
break;
case -1 or 1 when Mathf.Abs(motor.CharacterRight.x) < 0.1f:
_leanDirection = new Vector3(0, 0, -1);
break;
}
}
else
{
switch (_leanDirection.z)
{
case 1 when Mathf.Abs(motor.CharacterRight.z) < 0.1f:
_leanSign = -1;
break;
case -1 when motor.CharacterRight.z < -0.1f:
case 1 when motor.CharacterRight.z > 0.1f:
_leanDirection = new Vector3(-1, 0, 0);
break;
case -1 when motor.CharacterRight.z > 0.1f:
case 1 when motor.CharacterRight.z < -0.1f:
_leanDirection = new Vector3(1, 0, 0);
break;
}
}
_isLeaningOnWall = true;
}
// Обновление каждый кадр
public void UpdateLean(KinematicCharacterMotor motor, float deltaTime)
{
if (!_characterTransform) return;
var currentPosition = motor.TransientPosition;
var isStillNearWall = false;
if (_isLeaningOnWall && _lastWallNormal != Vector3.zero)
{
var toWall = currentPosition - _lastWallContactPoint;
var distanceToWallPlane = Mathf.Abs(Vector3.Dot(toWall, _lastWallNormal));
isStillNearWall = distanceToWallPlane <= WallProximityThreshold;
}
if (_isLeaningOnWall)
{
var isBelowContactHeight = currentPosition.y < _lastWallContactHeight;
if (!isStillNearWall || isBelowContactHeight)
{
_isLeaningOnWall = false;
}
else
{
var heightDelta = currentPosition.y - _lastWallContactHeight;
var targetLeanFactor = Mathf.Clamp01(heightDelta * _heightScale);
_leanFactor = Mathf.Lerp(_leanFactor, targetLeanFactor, 1f - Mathf.Exp(-_leanSharpness * deltaTime));
}
}
if (!_isLeaningOnWall)
{
_leanFactor = Mathf.Lerp(_leanFactor, 0f, 1f - Mathf.Exp(-_leanSharpness * deltaTime));
}
ApplyLeanRotation(motor);
}
private void ApplyLeanRotation(KinematicCharacterMotor motor)
{
if (_leanFactor <= 0.01f)
{
_characterTransform.localRotation = Quaternion.identity;
return; return;
} }
if (_leanDirection.sqrMagnitude < 0.01f) return; var targetRotation = Quaternion.identity;
var leanAngle = _leanSign * _leanFactor * _maxLeanAngle; if (isWallRunning)
var leanAxis = Vector3.Cross(motor.CharacterUp, _leanDirection); {
var leanRotation = Quaternion.AngleAxis(leanAngle, leanAxis); var n = new Vector3(wallNormal.x, 0f, wallNormal.z).normalized;
_characterTransform.localRotation = leanRotation; if (n.sqrMagnitude < 0.001f) n = Vector3.forward;
var bodyRight = Vector3.Cross(Vector3.up, characterForward).normalized;
var side = Vector3.Dot(n, bodyRight);
var front = Vector3.Dot(n, characterForward);
var axis = Vector3.right;
var angle = 0f;
if (side > _threshold)
{
axis = Vector3.forward;
angle = -_leanAngle;
}
else if (side < -_threshold)
{
axis = Vector3.forward;
angle = _leanAngle;
}
else if (front > _threshold)
{
axis = Vector3.right;
angle = -_leanAngle;
}
else if (front < -_threshold)
{
axis = Vector3.right;
angle = _leanAngle;
}
targetRotation = Quaternion.AngleAxis(angle, axis);
}
_model.localRotation = Quaternion.Slerp(
_model.localRotation,
targetRotation,
1f - Mathf.Exp(-_smoothSpeed * Time.deltaTime)
);
} }
} }
} }
@@ -0,0 +1,233 @@
using Code.Gameplay.Character.Controller.Input;
using Code.Gameplay.Character.Core;
using KinematicCharacterController;
using UnityEngine;
namespace Code.Gameplay.Character.Controller.Abilities
{
public class WallRunningMechanic
{
private readonly float _maxWallRunTime;
private readonly float _wallRunSpeed;
private readonly float _wallRunAcceleration;
private readonly float _wallRunGravityScale;
private readonly float _wallDetachImpulse;
private readonly float _wallContactAngleThreshold;
private float _wallRunTimer;
private Vector3 _wallNormal;
private Vector3 _wallTangentRight;
private Vector3 _wallTangentUp;
private Vector3 _wallContactPoint;
private Vector3 _lastMoveInputInWallSpace;
private float _surfaceAngleCos;
private bool _canWallRun;
private KinematicCharacterMotor _motor;
private CharacterInputHandler _inputHandler;
public bool IsWallRunning { get; private set; }
public WallRunningMechanic(
float maxWallRunTime,
float wallRunSpeed,
float wallRunAcceleration,
float wallRunGravityScale,
float wallDetachImpulse,
float wallContactAngleThreshold)
{
_maxWallRunTime = maxWallRunTime;
_wallRunSpeed = wallRunSpeed;
_wallRunAcceleration = wallRunAcceleration;
_wallRunGravityScale = wallRunGravityScale;
_wallDetachImpulse = wallDetachImpulse;
_wallContactAngleThreshold = wallContactAngleThreshold;
}
public void Initialize(KinematicCharacterMotor motor, CharacterInputHandler inputHandler)
{
_motor = motor;
_inputHandler = inputHandler;
_surfaceAngleCos = Mathf.Cos(Mathf.Deg2Rad * _wallContactAngleThreshold);
}
public void Tick(float deltaTime)
{
if (!IsWallRunning) return;
_wallRunTimer += deltaTime;
if (_wallRunTimer > _maxWallRunTime)
{
DetachFromWall(false);
}
}
public bool TryStartWallRun(Vector3 hitNormal, Vector3 hitPoint)
{
if (IsWallRunning) return false;
var dotWithUp = Vector3.Dot(hitNormal, _motor.CharacterUp);
var isWall = Mathf.Abs(dotWithUp) < _surfaceAngleCos;
if (!isWall) return false;
if (_motor.GroundingStatus.IsStableOnGround) return false;
var velocityIntoWall = Vector3.Dot(_motor.Velocity, -hitNormal);
if (velocityIntoWall < 1f) return false;
StartWallRun(hitNormal, hitPoint);
return true;
}
private void StartWallRun(Vector3 wallNormal, Vector3 contactPoint)
{
IsWallRunning = true;
_wallRunTimer = 0f;
_wallNormal = wallNormal.normalized;
_wallContactPoint = contactPoint;
if (_wallTangentUp.sqrMagnitude < 0.01f) _wallTangentUp = Vector3.up;
_wallTangentRight = Vector3.Cross(_wallNormal, _wallTangentUp).normalized;
_wallTangentUp = Vector3.Cross(_wallTangentRight, _wallNormal).normalized;
if (Vector3.Dot(_wallTangentUp, Vector3.up) < 0)
_wallTangentUp = -_wallTangentUp;
_motor.ForceUnground();
}
public void HandleWallRun(ref Vector3 currentVelocity, CharacterInputs inputs, float deltaTime)
{
if (!IsWallRunning) return;
if (!IsWallStillPresent()) { DetachFromWall(false); return; }
var moveInputWorld = _inputHandler.MoveInputVector;
var moveInWallPlane = Vector3.ProjectOnPlane(moveInputWorld, _wallNormal);
var wsMove = Vector3.Project(moveInWallPlane, _wallTangentRight);
var ad = inputs.MoveAxisRight;
var sideDot = Vector3.Dot(_wallNormal, _motor.CharacterRight);
if (sideDot < 0)
ad = -ad;
var adMove = _wallTangentUp * (-ad);
var finalMove = wsMove + adMove;
finalMove = finalMove.normalized * moveInputWorld.magnitude;
var targetVelocity = finalMove * _wallRunSpeed;
currentVelocity = Vector3.Lerp(
currentVelocity,
targetVelocity,
1f - Mathf.Exp(-_wallRunAcceleration * deltaTime)
);
currentVelocity += Physics.gravity * (_wallRunGravityScale * deltaTime);
var distanceToWall = Vector3.Dot(_motor.TransientPosition - _wallContactPoint, _wallNormal);
if (Mathf.Abs(distanceToWall) > 0.8f)
{
DetachFromWall(false);
return;
}
if (inputs.JumpPressed)
{
DetachFromWall(true);
}
}
private bool IsWallStillPresent()
{
if (!_motor) return false;
var characterCenter = _motor.TransientPosition;
var characterRight = _motor.CharacterRight;
var characterUp = _motor.CharacterUp;
const float checkDistance = 0.45f;
var rayOrigin = characterCenter + characterUp * 0.2f;
var rayDir = -_wallNormal;
Vector3[] offsets = {
Vector3.zero,
characterUp * 0.3f,
-characterUp * 0.3f,
characterRight * 0.2f,
-characterRight * 0.2f
};
foreach (var offset in offsets)
{
if (!Physics.Raycast(rayOrigin + offset, rayDir, out var hit, checkDistance,
_motor.CollidableLayers, QueryTriggerInteraction.Ignore)) continue;
var dotWithUp = Mathf.Abs(Vector3.Dot(hit.normal, characterUp));
if (!(dotWithUp < _surfaceAngleCos)) continue;
_wallNormal = hit.normal.normalized;
_wallContactPoint = hit.point;
return true;
}
return false;
}
private void DetachFromWall(bool withImpulse)
{
if (!IsWallRunning) return;
IsWallRunning = false;
if (!withImpulse || !_motor) return;
var detachImpulse = -_wallNormal * _wallDetachImpulse;
_motor.BaseVelocity += detachImpulse;
}
public Vector3 GetWallNormal() => _wallNormal;
public void PerformWallJump(CharacterInputs inputs, Quaternion cameraRotation)
{
if (!IsWallRunning || !_motor) return;
IsWallRunning = false;
var wallAway = _wallNormal;
var wallUp = _wallTangentUp;
var playerForward = cameraRotation * Vector3.forward;
var forwardInWallPlane = Vector3.ProjectOnPlane(playerForward, _wallNormal).normalized;
if (forwardInWallPlane.sqrMagnitude < 0.01f) forwardInWallPlane = _wallTangentRight;
var jumpDirection =
forwardInWallPlane * 0.2f +
wallAway * 0.4f +
wallUp * 0.4f;
jumpDirection = jumpDirection.normalized;
var wallJumpForce = _wallDetachImpulse * 2f;
var jumpImpulse = jumpDirection * wallJumpForce;
_motor.BaseVelocity += jumpImpulse;
_motor.SetPosition(_motor.TransientPosition + wallAway * 0.07f);
if (_motor.CharacterController is CustomCharacterController controller)
{
controller.BlockAbilities(0.12f);
}
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4bef67aa9cf14753a63ea07eecc5ff67
timeCreated: 1764263348
@@ -15,7 +15,7 @@ namespace Code.Gameplay.Character.Controller
* Реализует физическое движение персонажа с использованием Kinematic Character Controller * Реализует физическое движение персонажа с использованием Kinematic Character Controller
* Обрабатывает ввод пользователя, применяет движение и вращение с учетом поверхности * Обрабатывает ввод пользователя, применяет движение и вращение с учетом поверхности
* *
* Источник: Tvtig, https://www.youtube.com/watch?v=9ibpY64wBYM * Источник: Tvtig, https://www.youtube.com/watch?v=9ibpY64wBYM
*/ */
public class CustomCharacterController : MonoBehaviour, ICharacterController public class CustomCharacterController : MonoBehaviour, ICharacterController
{ {
@@ -27,118 +27,92 @@ namespace Code.Gameplay.Character.Controller
// Подсистемы // Подсистемы
private CharacterInputHandler _inputHandler; private CharacterInputHandler _inputHandler;
private DashMechanic _dashMechanic;
private SlideMechanic _slideMechanic; private SlideMechanic _slideMechanic;
private WallClimbMechanic _wallClimbMechanic; // private WallClimbMechanic _wallClimbMechanic;
private WallRunningMechanic _wallRunningMechanic;
private WallLeanMechanic _wallLeanMechanic; private WallLeanMechanic _wallLeanMechanic;
private GroundMovementSystem _groundMovement; private GroundMovementSystem _groundMovement;
private AirMovementSystem _airMovement; private AirMovementSystem _airMovement;
public bool IsSliding => _slideMechanic.IsSliding; public bool IsSliding => _slideMechanic.IsSliding;
public bool IsDashing => _dashMechanic.IsDashing;
public bool IsWallRunning => _wallRunningMechanic.IsWallRunning;
private float abilityBlockTimer; private float abilityBlockTimer;
private bool isAbilitiesBlocked; private bool isAbilitiesBlocked;
private CharacterInputs _lastInputs;
public void SetPosition(Vector3 position) => motor.SetPosition(position); public void SetPosition(Vector3 position) => motor.SetPosition(position);
public void SetRotation(Quaternion rotation) => motor.SetRotation(rotation); public void SetRotation(Quaternion rotation) => motor.SetRotation(rotation);
// Инициализация контроллера
// private void Awake()
// {
// // Инициализация подсистем с параметрами из конфига
// _inputHandler = new CharacterInputHandler(
// _characterConfig.sprintAngleThreshold
// );
// _slideMechanic = new SlideMechanic(
// _characterConfig.slideSpeed,
// _characterConfig.slideDuration,
// _characterConfig.slideCooldown
// );
// _wallClimbMechanic = new WallClimbMechanic(
// _characterConfig.wallClimbSpeedFactor,
// _characterConfig.minWallClimbSpeed,
// _characterConfig.wallDetectionAngleThreshold
// );
// _wallLeanMechanic = new WallLeanMechanic(
// _characterConfig.maxWallLeanAngle,
// _characterConfig.wallLeanSharpness,
// _characterConfig.wallLeanHeightScale
// );
// _groundMovement = new GroundMovementSystem(
// _characterConfig.maxStableMoveSpeed,
// _characterConfig.sprintMoveSpeed,
// _characterConfig.stableMovementSharpness,
// _characterConfig.jumpSpeed
// );
// _airMovement = new AirMovementSystem(_characterConfig.gravity);
// }
[Inject] [Inject]
private void Construct(CharacterConfig characterConfig) private void Construct(CharacterConfig characterConfig)
{ {
_characterConfig = characterConfig; _characterConfig = characterConfig;
// Инициализация подсистем с параметрами из конфига // Инициализация подсистем с параметрами из конфига
_inputHandler = new CharacterInputHandler( _inputHandler = new CharacterInputHandler();
_characterConfig.sprintAngleThreshold _dashMechanic = new DashMechanic(
_characterConfig.dashSpeed,
_characterConfig.dashDuration,
_characterConfig.dashCooldown
); );
_slideMechanic = new SlideMechanic( _slideMechanic = new SlideMechanic(
_characterConfig.slideSpeed, _characterConfig.slideVelocityCurve,
_characterConfig.slideDuration, _characterConfig.slideMinVelocityThreshold,
_characterConfig.slideCooldown _characterConfig.slideCooldown
); );
_wallClimbMechanic = new WallClimbMechanic( _wallRunningMechanic = new WallRunningMechanic(
_characterConfig.wallClimbSpeedFactor, _characterConfig.wallRunMaxTime,
_characterConfig.minWallClimbSpeed, _characterConfig.wallRunSpeed,
_characterConfig.wallDetectionAngleThreshold _characterConfig.wallRunAcceleration,
_characterConfig.wallRunGravityScale,
_characterConfig.wallDetachImpulse,
_characterConfig.wallContactAngleThreshold
); );
_wallLeanMechanic = new WallLeanMechanic( _wallLeanMechanic = new WallLeanMechanic(
_characterConfig.maxWallLeanAngle, _characterConfig.leanAngle,
_characterConfig.wallLeanSharpness, _characterConfig.leanThreshold,
_characterConfig.wallLeanHeightScale _characterConfig.leanSmoothSpeed
); );
_groundMovement = new GroundMovementSystem( _groundMovement = new GroundMovementSystem(
_characterConfig.maxStableMoveSpeed, _characterConfig.maxStableMoveSpeed,
_characterConfig.sprintMoveSpeed,
_characterConfig.stableMovementSharpness, _characterConfig.stableMovementSharpness,
_characterConfig.jumpSpeed _characterConfig.jumpSpeed
); );
_airMovement = new AirMovementSystem(_characterConfig.gravity); _airMovement = new AirMovementSystem(
_characterConfig.gravity,
_characterConfig.maxAirSpeed,
_characterConfig.airControlSharpness
);
motor.CharacterController = this; // Регистрация этого контроллера в движке motor.CharacterController = this; // Регистрация этого контроллера в движке
_inputHandler.FirstPersonCameraRotation = _inputHandler.FirstPersonCameraRotation =
motor.Transform.rotation; // Начальное вращение совпадает с персонажемс motor.Transform.rotation; // Начальное вращение совпадает с персонажемс
_wallLeanMechanic.SetCharacterTransform(characterTransform); _wallLeanMechanic.SetModel(characterTransform);
_wallRunningMechanic.Initialize(motor, _inputHandler);
} }
// Текущий режим камеры для адаптации поведения // Текущий режим камеры для адаптации поведения
private CameraMode _currentCameraMode = CameraMode.FirstPerson; private CameraMode _currentCameraMode = CameraMode.FirstPerson;
// Инициализация контроллера
// private void Start()
// {
// motor.CharacterController = this; // Регистрация этого контроллера в движке
// _inputHandler.FirstPersonCameraRotation =
// motor.Transform.rotation; // Начальное вращение совпадает с персонажемс
// _wallLeanMechanic.SetCharacterTransform(characterTransform);
// }
// Обработка и преобразование входных данных от персонажа
public void SetInputs(ref CharacterInputs inputs) public void SetInputs(ref CharacterInputs inputs)
{ {
// Обновляем таймер перезарядки слайда _lastInputs = inputs;
_dashMechanic.TickCooldown(Time.deltaTime);
_slideMechanic.TickCooldown(Time.deltaTime); _slideMechanic.TickCooldown(Time.deltaTime);
_wallClimbMechanic.TickCooldown(Time.deltaTime); _wallRunningMechanic.Tick(Time.deltaTime);
// Если активен слайд - игнорируем весь остальной ввод // Если активен слайд - игнорируем весь остальной ввод
if (_slideMechanic.IsSliding) if (_dashMechanic.IsDashing || _slideMechanic.IsSliding)
{ {
// Во время слайда не обрабатываем движение, прыжки и спринт
_inputHandler.MoveInputVector = Vector3.zero; _inputHandler.MoveInputVector = Vector3.zero;
_inputHandler.LookInputVector = Vector3.one; _inputHandler.LookInputVector = Vector3.one;
_inputHandler.IsSprinting = false;
_groundMovement.RequestJump(inputs.JumpPressed); _groundMovement.RequestJump(inputs.JumpPressed);
return; return;
} }
// Сохраняем текущий режим камеры
_currentCameraMode = inputs.CameraMode; _currentCameraMode = inputs.CameraMode;
if (isAbilitiesBlocked) if (isAbilitiesBlocked)
@@ -150,53 +124,44 @@ namespace Code.Gameplay.Character.Controller
} }
else else
{ {
inputs.SprintPressed = false; inputs.DashPressed = false;
inputs.SlidePressed = false; inputs.SlidePressed = false;
} }
} }
// Обработка слайда _dashMechanic.RequestDash(inputs.DashPressed);
_slideMechanic.RequestSlide(inputs.SlidePressed); _slideMechanic.RequestSlide(inputs.SlidePressed);
// Обработка остального ввода // Обработка остального ввода
_inputHandler.ProcessInputs(ref inputs, motor); _inputHandler.ProcessInputs(ref inputs, motor);
// Передаём запрос прыжка напрямую в систему движения по земле // Передаём запрос прыжка
_groundMovement.RequestJump(inputs.JumpPressed); _groundMovement.RequestJump(inputs.JumpPressed);
} }
// Обновление вращения персонажа на основе входных данных
public void UpdateRotation(ref Quaternion currentRotation, float deltaTime) public void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
{ {
if (_slideMechanic.IsSliding || _wallClimbMechanic.IsClimbingActive) return; if (_slideMechanic.IsSliding) return;
switch (_currentCameraMode) switch (_currentCameraMode)
{ {
// В FirstPerson режиме применяем вращение камеры напрямую к персонажу (только горизонталь)
case CameraMode.FirstPerson when _inputHandler.ShouldApplyCameraRotation: case CameraMode.FirstPerson when _inputHandler.ShouldApplyCameraRotation:
// Немедленно применяем горизонтальное вращение камеры к персонажу
currentRotation = _inputHandler.FirstPersonCameraRotation; currentRotation = _inputHandler.FirstPersonCameraRotation;
break; break;
// В ThirdPerson режиме плавно поворачиваем персонаж в направлении движения
case CameraMode.ThirdPerson: case CameraMode.ThirdPerson:
{ {
// Вращение применяется только если есть направление движения и разрешена резкость вращения
if (_inputHandler.LookInputVector.sqrMagnitude > 0 && _characterConfig.orientationSharpness > 0) if (_inputHandler.LookInputVector.sqrMagnitude > 0 && _characterConfig.orientationSharpness > 0)
{ {
// Плавная интерполяция текущего направления к целевому с экспоненциальным сглаживанием
var smoothedLookInputDirection = Vector3.Slerp( var smoothedLookInputDirection = Vector3.Slerp(
motor.CharacterForward, motor.CharacterForward,
_inputHandler.LookInputVector, _inputHandler.LookInputVector,
1f - Mathf.Exp(-_characterConfig.orientationSharpness * deltaTime) 1f - Mathf.Exp(-_characterConfig.orientationSharpness * deltaTime)
).normalized; ).normalized;
// Установка нового вращения смотря в сглаженном направлении
currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, motor.CharacterUp); currentRotation = Quaternion.LookRotation(smoothedLookInputDirection, motor.CharacterUp);
} }
break; break;
} }
// Заготовка на будущее (если понадобится)
case CameraMode.Static: case CameraMode.Static:
case CameraMode.Cinematic: case CameraMode.Cinematic:
default: default:
@@ -204,38 +169,54 @@ namespace Code.Gameplay.Character.Controller
} }
} }
// Обновление скорости движения персонажа
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime) public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{ {
// Если во время слайда запрошен прыжок — прерываем слайд if (_dashMechanic.IsDashing && _groundMovement.JumpRequested)
_dashMechanic.EndDash();
if (_slideMechanic.IsSliding && _groundMovement.JumpRequested) if (_slideMechanic.IsSliding && _groundMovement.JumpRequested)
{
_slideMechanic.EndSlide(); _slideMechanic.EndSlide();
if (!_dashMechanic.IsDashing)
_dashMechanic.TryStartDash(motor, _currentCameraMode, _inputHandler.FirstPersonCameraRotation, _inputHandler.LookInputVector);
else
{
_dashMechanic.HandleDash(ref currentVelocity, deltaTime, motor);
return;
} }
// Проверяем запрос слайда и запускаем его если можно
if (!_slideMechanic.IsSliding) if (!_slideMechanic.IsSliding)
{ _slideMechanic.TryStartSlide(motor, _currentCameraMode, _inputHandler.FirstPersonCameraRotation, _inputHandler.LookInputVector);
_slideMechanic.TryStartSlide(motor, _currentCameraMode, _inputHandler.FirstPersonCameraRotation,
_inputHandler.LookInputVector);
}
// Если активен слайд - обрабатываем отдельно
else else
{ {
_slideMechanic.HandleSlide(ref currentVelocity, deltaTime, motor); _slideMechanic.HandleSlide(ref currentVelocity, deltaTime, motor);
return; return;
} }
// === WALL RUNNING: обработка состояния ===
if (_wallRunningMechanic.IsWallRunning)
{
// 🔄 Передаём актуальные данные для walljump
if (_groundMovement.JumpRequested) // или _lastInputs.JumpPressed — зависит от логики
{
_wallRunningMechanic.PerformWallJump(_lastInputs, _inputHandler.FirstPersonCameraRotation);
_groundMovement.CancelJumpRequest(); // сброс, чтобы не сработало дважды
}
else
{
_wallRunningMechanic.HandleWallRun(ref currentVelocity, _lastInputs, deltaTime);
}
return;
}
// Если персонаж находится на земле // Если персонаж находится на земле
if (motor.GroundingStatus.IsStableOnGround) if (motor.GroundingStatus.IsStableOnGround)
{ {
_groundMovement.UpdateVelocity(ref currentVelocity, _inputHandler, motor, deltaTime); _groundMovement.UpdateVelocity(ref currentVelocity, _inputHandler, motor, deltaTime);
} }
// Если персонаж не находится на земле // Если персонаж не на земле — стандартное воздушное движение
else else
{ {
_airMovement.UpdateVelocity(ref currentVelocity, deltaTime); _airMovement.UpdateVelocity(ref currentVelocity, _inputHandler, motor, deltaTime);
// Отменяем прыжок (фикс проблемы с двойным прыжком после приземления)
_groundMovement.CancelJumpRequest(); _groundMovement.CancelJumpRequest();
} }
} }
@@ -246,60 +227,51 @@ namespace Code.Gameplay.Character.Controller
abilityBlockTimer = duration; abilityBlockTimer = duration;
} }
// Метод вызывается перед обновлением персонажа (можно использовать для подготовки)
public void BeforeCharacterUpdate(float deltaTime) public void BeforeCharacterUpdate(float deltaTime)
{ {
} }
// Метод вызывается после обработки столкновения с землей
public void PostGroundingUpdate(float deltaTime) public void PostGroundingUpdate(float deltaTime)
{ {
// Если во время слайда персонаж оторвался от земли - заканчиваем слайд if (_dashMechanic.IsDashing && !motor.GroundingStatus.IsStableOnGround)
_dashMechanic.EndDash();
if (_slideMechanic.IsSliding && !motor.GroundingStatus.IsStableOnGround) if (_slideMechanic.IsSliding && !motor.GroundingStatus.IsStableOnGround)
{
_slideMechanic.EndSlide(); _slideMechanic.EndSlide();
}
if (motor.GroundingStatus.IsStableOnGround)
{
_wallClimbMechanic.ResetWallClimbSession();
}
} }
// Метод вызывается после обновления персонажа
public void AfterCharacterUpdate(float deltaTime) public void AfterCharacterUpdate(float deltaTime)
{ {
_wallLeanMechanic.UpdateLean(motor, deltaTime); _wallLeanMechanic.Update(
_wallRunningMechanic.IsWallRunning,
_wallRunningMechanic.GetWallNormal(),
motor.CharacterForward
);
} }
// Проверка валидности коллайдера для обработки столкновений
public bool IsColliderValidForCollisions(Collider coll) public bool IsColliderValidForCollisions(Collider coll)
{ {
return true; // Все коллайдеры считаются валидными для столкновений return true;
} }
// Обработка столкновения с землей (вызывается при приземлении)
public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, public void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
ref HitStabilityReport hitStabilityReport) ref HitStabilityReport hitStabilityReport)
{ {
} }
// Обработка столкновения при движении (вызывается при ударе о препятствие)
public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, public void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
ref HitStabilityReport hitStabilityReport) ref HitStabilityReport hitStabilityReport)
{ {
if (_wallClimbMechanic.TryClimbWall(motor, hitNormal)) if (_wallRunningMechanic.TryStartWallRun(hitNormal, hitPoint))
_wallLeanMechanic.OnWallContact(motor, hitNormal, motor.TransientPosition.y); {
}
} }
// Обработка отчета о стабильности столкновения
public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, public void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint,
Vector3 atCharacterPosition, Vector3 atCharacterPosition,
Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport) Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
{ {
} }
// Обработка дискретных столкновений (для триггеров и специальных коллайдеров)
public void OnDiscreteCollisionDetected(Collider hitCollider) public void OnDiscreteCollisionDetected(Collider hitCollider)
{ {
} }
@@ -11,40 +11,23 @@ namespace Code.Gameplay.Character.Controller.Input
*/ */
public class CharacterInputHandler public class CharacterInputHandler
{ {
// Косинус порогового угла для спринта (предвычислен)
private readonly float _sprintAngleThresholdCos;
// Векторы движения и направления взгляда // Векторы движения и направления взгляда
public Vector3 MoveInputVector { get; set; } public Vector3 MoveInputVector { get; set; }
public Vector3 LookInputVector { get; set; } public Vector3 LookInputVector { get; set; }
// Флаг-свойство указывающий, что активен режим спринта
public bool IsSprinting { get; set; }
// Вращение камеры в FirstPerson режиме для синхронизации (только горизонтальная компонента) // Вращение камеры в FirstPerson режиме для синхронизации (только горизонтальная компонента)
public Quaternion FirstPersonCameraRotation { get; set; } public Quaternion FirstPersonCameraRotation { get; set; }
// Флаг-свойство указывающий, что нужно применить вращение камеры к персонажу // Флаг-свойство указывающий, что нужно применить вращение камеры к персонажу
public bool ShouldApplyCameraRotation { get; private set; } public bool ShouldApplyCameraRotation { get; private set; }
// Конструктор с пороговым углом
public CharacterInputHandler(float sprintAngleThreshold)
{
// Предвычисляем косинус порогового угла для эффективности
// Угол в градусах → радианы → косинус
// Чем меньше угол — тем строже условие
_sprintAngleThresholdCos = Mathf.Cos(Mathf.Deg2Rad * sprintAngleThreshold);
}
// Обработка и преобразование входных данных от персонажа // Обработка и преобразование входных данных от персонажа
public void ProcessInputs(ref CharacterInputs inputs, KinematicCharacterMotor motor) public void ProcessInputs(ref CharacterInputs inputs, KinematicCharacterMotor motor)
{ {
// Сохраняем текущий режим камеры // Сохраняем текущий режим камеры
var currentCameraMode = inputs.CameraMode; var currentCameraMode = inputs.CameraMode;
// Обработка спринта
IsSprinting = inputs.SprintPressed && inputs.MoveAxisForward > _sprintAngleThresholdCos; // Спринт только при движении на заданный в конфиге угол
// Нормализация вектора движения и ограничение его величины до 1 // Нормализация вектора движения и ограничение его величины до 1
var moveInputVector = var moveInputVector =
Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0, inputs.MoveAxisForward), 1f); Vector3.ClampMagnitude(new Vector3(inputs.MoveAxisRight, 0, inputs.MoveAxisForward), 1f);
@@ -1,26 +1,38 @@
using UnityEngine; using UnityEngine;
using Code.Gameplay.Character.Controller.Input;
using KinematicCharacterController;
namespace Code.Gameplay.Character.Controller.Movement namespace Code.Gameplay.Character.Controller.Movement
{ {
/*
* Система движения персонажа в воздухе
*/
public class AirMovementSystem public class AirMovementSystem
{ {
// Вектор, отвечающий за применение гравитации
private readonly Vector3 _gravity; private readonly Vector3 _gravity;
private readonly float _maxAirSpeed;
// Конструктор системы движения в воздухе private readonly float _airControlSharpness;
public AirMovementSystem(Vector3 gravity)
public AirMovementSystem(Vector3 gravity, float maxAirSpeed, float airControlSharpness)
{ {
_gravity = gravity; _gravity = gravity;
_maxAirSpeed = maxAirSpeed;
_airControlSharpness = airControlSharpness;
} }
// Обновление скорости движения персонажа в воздухе public void UpdateVelocity(ref Vector3 currentVelocity, CharacterInputHandler inputHandler, KinematicCharacterMotor motor, float deltaTime)
public void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{ {
// Применяем гравитацию
currentVelocity += _gravity * deltaTime; currentVelocity += _gravity * deltaTime;
var horizontalVelocity = Vector3.ProjectOnPlane(currentVelocity, motor.CharacterUp);
var verticalVelocity = Vector3.Dot(currentVelocity, motor.CharacterUp) * motor.CharacterUp;
var desiredHorizontalMovement = Vector3.ProjectOnPlane(inputHandler.MoveInputVector, motor.CharacterUp).normalized * _maxAirSpeed;
horizontalVelocity = Vector3.Lerp(
horizontalVelocity,
desiredHorizontalMovement,
1f - Mathf.Exp(-_airControlSharpness * deltaTime)
);
currentVelocity = horizontalVelocity + verticalVelocity;
} }
} }
} }
@@ -11,8 +11,6 @@ namespace Code.Gameplay.Character.Controller.Movement
{ {
// Максимальная скорость движения по устойчивой поверхности // Максимальная скорость движения по устойчивой поверхности
private readonly float _maxStableMoveSpeed; private readonly float _maxStableMoveSpeed;
// Максимальная скорость спринта
private readonly float _sprintMoveSpeed;
// Резкость изменения скорости движения (чем выше - тем резче) // Резкость изменения скорости движения (чем выше - тем резче)
private readonly float _stableMovementSharpness; private readonly float _stableMovementSharpness;
// Скорость прыжка // Скорость прыжка
@@ -22,10 +20,9 @@ namespace Code.Gameplay.Character.Controller.Movement
public bool JumpRequested { get; private set; } public bool JumpRequested { get; private set; }
// Конструктор системы движения на земле // Конструктор системы движения на земле
public GroundMovementSystem(float maxStableMoveSpeed, float sprintMoveSpeed, float stableMovementSharpness, float jumpSpeed) public GroundMovementSystem(float maxStableMoveSpeed, float stableMovementSharpness, float jumpSpeed)
{ {
_maxStableMoveSpeed = maxStableMoveSpeed; _maxStableMoveSpeed = maxStableMoveSpeed;
_sprintMoveSpeed = sprintMoveSpeed;
_stableMovementSharpness = stableMovementSharpness; _stableMovementSharpness = stableMovementSharpness;
_jumpSpeed = jumpSpeed; _jumpSpeed = jumpSpeed;
} }
@@ -66,8 +63,7 @@ namespace Code.Gameplay.Character.Controller.Movement
inputHandler.MoveInputVector.magnitude; inputHandler.MoveInputVector.magnitude;
// Расчет целевой скорости движения с учетом ограничения максимальной скорости и спринта // Расчет целевой скорости движения с учетом ограничения максимальной скорости и спринта
var targetSpeed = inputHandler.IsSprinting ? _sprintMoveSpeed : _maxStableMoveSpeed; var targetMovementVelocity = reorientedInput * _maxStableMoveSpeed;
var targetMovementVelocity = reorientedInput * targetSpeed;
// Плавная интерполяция текущей скорости к целевой с экспоненциальным сглаживанием // Плавная интерполяция текущей скорости к целевой с экспоненциальным сглаживанием
currentVelocity = Vector3.Lerp( currentVelocity = Vector3.Lerp(
@@ -45,8 +45,8 @@ namespace Code.Gameplay.Character.Core
inputs.MoveAxisForward = moveInput.y; // Vertical ось (W/S или Up/Down) inputs.MoveAxisForward = moveInput.y; // Vertical ось (W/S или Up/Down)
inputs.MoveAxisRight = moveInput.x; // Horizontal ось (A/D или Left/Right) inputs.MoveAxisRight = moveInput.x; // Horizontal ось (A/D или Left/Right)
inputs.JumpPressed = _inputService.JumpPressed; // Прыжки (Space) inputs.JumpPressed = _inputService.JumpPressed; // Прыжки (Space)
inputs.SprintPressed = _inputService.SprintPressed; // Спринт (Shift)
inputs.SlidePressed = _inputService.SlidePressed; // Слайд (Ctrl) inputs.SlidePressed = _inputService.SlidePressed; // Слайд (Ctrl)
inputs.DashPressed = _inputService.DashPressed; // Слайд (Ctrl)
inputs.CameraMode = ((ICameraState)_cameraStateMachine.CurrentBaseState).GetCameraMode(); inputs.CameraMode = ((ICameraState)_cameraStateMachine.CurrentBaseState).GetCameraMode();
// Передаем информацию о камере для адаптивного поведения // Передаем информацию о камере для адаптивного поведения
@@ -15,7 +15,7 @@ namespace Code.Gameplay.Character.Core
public CameraMode CameraMode; // Текущий режим камеры для адаптации поведения public CameraMode CameraMode; // Текущий режим камеры для адаптации поведения
public Vector3 CameraPlanarDirection; // Направление камеры в горизонтальной плоскости public Vector3 CameraPlanarDirection; // Направление камеры в горизонтальной плоскости
public bool JumpPressed; // Флаг указывающий, нажата ли кнопка прыжка public bool JumpPressed; // Флаг указывающий, нажата ли кнопка прыжка
public bool SprintPressed; // Флаг указывающий, нажата ли кнопка спринта public bool DashPressed;
public bool SlidePressed; // Флаг указывающий, нажата ли кнопка слайда public bool SlidePressed; // Флаг указывающий, нажата ли кнопка слайда
} }
} }
@@ -38,7 +38,7 @@ namespace Code.Gameplay.Character.Core
inputs.MoveAxisForward = moveInput.y; // Vertical ось (W/S или Up/Down) inputs.MoveAxisForward = moveInput.y; // Vertical ось (W/S или Up/Down)
inputs.MoveAxisRight = moveInput.x; // Horizontal ось (A/D или Left/Right) inputs.MoveAxisRight = moveInput.x; // Horizontal ось (A/D или Left/Right)
inputs.JumpPressed = _inputService.JumpPressed; // Прыжки (Space) inputs.JumpPressed = _inputService.JumpPressed; // Прыжки (Space)
inputs.SprintPressed = true;//_inputService.SprintPressed; // Спринт (Shift) inputs.DashPressed = _inputService.DashPressed;
inputs.SlidePressed = _inputService.SlidePressed; // Слайд (Ctrl) inputs.SlidePressed = _inputService.SlidePressed; // Слайд (Ctrl)
inputs.CameraMode = ((ICameraState)_cameraStateMachine.CurrentBaseState).GetCameraMode(); inputs.CameraMode = ((ICameraState)_cameraStateMachine.CurrentBaseState).GetCameraMode();
@@ -1,9 +1,13 @@
using UnityEngine; using DG.Tweening;
using UnityEngine;
namespace Code.Gameplay.Door namespace Code.Gameplay.Door
{ {
public class Door : MonoBehaviour public class Door : MonoBehaviour
{ {
[SerializeField] private Transform doorPolotno;
private Vector3 _doorInitialPosition;
private Quaternion _doorInitialRotation;
[SerializeField] private Transform hingeJointAnchor; [SerializeField] private Transform hingeJointAnchor;
[SerializeField] private HingeJoint hingeJoint; [SerializeField] private HingeJoint hingeJoint;
[SerializeField] private Rigidbody rigidbody; [SerializeField] private Rigidbody rigidbody;
@@ -15,9 +19,19 @@ namespace Code.Gameplay.Door
rigidbody.isKinematic = true; rigidbody.isKinematic = true;
return; return;
} }
_doorInitialPosition = doorPolotno.position;
_doorInitialRotation = doorPolotno.rotation;
rigidbody.isKinematic = false; rigidbody.isKinematic = false;
hingeJoint.autoConfigureConnectedAnchor = false; hingeJoint.autoConfigureConnectedAnchor = false;
hingeJoint.connectedAnchor = hingeJointAnchor.position; hingeJoint.connectedAnchor = hingeJointAnchor.position;
} }
public void CloseTheDoor()
{
TranslationMode(true);
doorPolotno.DORotate(_doorInitialRotation.eulerAngles, 0.5f);
doorPolotno.DOMove(_doorInitialPosition, 0.5f);
}
} }
} }
@@ -0,0 +1,53 @@
using System;
using DG.Tweening;
using UnityEngine;
namespace Code.Gameplay.Door
{
public class DoorDebug : MonoBehaviour
{
[SerializeField] private Transform doorSelf;
[SerializeField] private Transform doorPolotno;
private Vector3 _doorInitialPosition;
private Quaternion _doorInitialRotation;
[SerializeField] private Transform hingeJointAnchor;
[SerializeField] private HingeJoint hingeJoint;
[SerializeField] private Rigidbody rigidbody;
[SerializeField] private bool debug;
[SerializeField] private bool closed;
private void Start()
{
_doorInitialPosition = doorPolotno.position;
_doorInitialRotation = doorPolotno.rotation;
}
private void Update()
{
if(debug && !closed)
{
CloseTheDoor();
}
}
public void TranslationMode(bool on)
{
if (on)
{
rigidbody.isKinematic = true;
return;
}
_doorInitialPosition = doorPolotno.position;
_doorInitialRotation = doorPolotno.rotation;
rigidbody.isKinematic = false;
hingeJoint.autoConfigureConnectedAnchor = false;
hingeJoint.connectedAnchor = hingeJointAnchor.position;
}
public void CloseTheDoor()
{
// TranslationMode(true);
doorPolotno.DORotate(_doorInitialRotation.eulerAngles, 0.5f);
doorPolotno.DOMove(_doorInitialPosition, 0.5f);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ed06ed70c7924ca9bc59f33ee7e6cdfa
timeCreated: 1764533216
@@ -0,0 +1,7 @@
namespace Code.Gameplay.Door
{
public class DoorPooler
{
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: acfad6f51f224b51abb761fc22e4356f
timeCreated: 1764521809
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f17ace0fa75741f2a730ff21181c6e8c
timeCreated: 1764575680
@@ -0,0 +1,23 @@
using UnityEngine;
using UnityEngine.AI;
namespace Code.Gameplay.Enemies.Animators
{
public class EnemyAnimator : MonoBehaviour
{
private static readonly int Velocity = Animator.StringToHash("Velocity");
[SerializeField] private Animator animator;
[SerializeField] private NavMeshAgent agent;
private void SetVelocity(float velocity)
{
animator.SetFloat(Velocity, velocity);
}
private void Update()
{
if(agent) SetVelocity(agent.velocity.magnitude);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 936125a7ed844674b0e0586a484253ce
timeCreated: 1764575708
@@ -1,8 +1,10 @@
using Code.Audio;
using UnityEngine; using UnityEngine;
using UnityEngine.AI; using UnityEngine.AI;
using Code.Gameplay.Player; using Code.Gameplay.Player;
using Code.Gameplay.Character.Controller; using Code.Gameplay.Character.Controller;
using Code.Gameplay.Character.Core; using Code.Gameplay.Character.Core;
using Code.Gameplay.Enemies.Animators;
using Reflex.Attributes; using Reflex.Attributes;
using Reflex.Core; using Reflex.Core;
using Reflex.Injectors; using Reflex.Injectors;
@@ -12,7 +14,8 @@ namespace Code.Gameplay.Enemies
public abstract class BaseEnemy : MonoBehaviour public abstract class BaseEnemy : MonoBehaviour
{ {
[SerializeField] protected NavMeshAgent agent; [SerializeField] protected NavMeshAgent agent;
[SerializeField] protected Collider enemyCollider; [SerializeField] protected Collider enemyCollider;
[Inject] protected IAudioService audioService;
protected int Damage; protected int Damage;
protected float AttackCooldown; protected float AttackCooldown;
@@ -35,7 +38,7 @@ namespace Code.Gameplay.Enemies
private bool _isStunned; private bool _isStunned;
private float _currentStunTimer; private float _currentStunTimer;
private bool _canAttack = true; protected bool _canAttack = true;
private float _attackCooldownTimer; private float _attackCooldownTimer;
private enum IdleState { Moving, Paused } private enum IdleState { Moving, Paused }
@@ -50,16 +53,17 @@ namespace Code.Gameplay.Enemies
protected virtual void Awake() protected virtual void Awake()
{ {
if (_playerProvider == null) // // TODO Мешает
{ // if (_playerProvider == null)
AttributeInjector.Inject(this, Container.ProjectContainer); // {
} // AttributeInjector.Inject(this, Container.ProjectContainer);
// }
} }
protected virtual void Update() protected virtual void Update()
{ {
if (!Player) return; if (!Player) return;
HandleStun(); HandleStun();
HandleAttackCooldown(); HandleAttackCooldown();
if (_isStunned) return; if (_isStunned) return;
@@ -164,19 +168,19 @@ namespace Code.Gameplay.Enemies
protected virtual void HandleAttackCooldown() protected virtual void HandleAttackCooldown()
{ {
if (!_canAttack) if (_canAttack) return;
_attackCooldownTimer -= Time.deltaTime;
if (_attackCooldownTimer <= 0)
{ {
_attackCooldownTimer -= Time.deltaTime; _canAttack = true;
if (_attackCooldownTimer <= 0)
{
_canAttack = true;
}
} }
} }
protected virtual void DealDamage() protected virtual void DealDamage()
{ {
if (!_canAttack || PlayerHealth == null) return; if (PlayerHealth == null) return;
PlayerHealth.GetDamage(Damage); PlayerHealth.GetDamage(Damage);
ApplyEffectsToPlayer(); ApplyEffectsToPlayer();
@@ -184,11 +188,10 @@ namespace Code.Gameplay.Enemies
_canAttack = false; _canAttack = false;
_attackCooldownTimer = AttackCooldown; _attackCooldownTimer = AttackCooldown;
} }
protected virtual void ApplyEffectsToPlayer() protected virtual void ApplyEffectsToPlayer()
{ {
if (PlayerController) if (PlayerController)
PlayerController.BlockAbilities(3f); PlayerController.BlockAbilities(3f); // TODO в конфиг
} }
private void OnDrawGizmosSelected() private void OnDrawGizmosSelected()
@@ -1,3 +1,4 @@
using Code.Audio;
using Code.Configs; using Code.Configs;
using Reflex.Attributes; using Reflex.Attributes;
using UnityEngine; using UnityEngine;
@@ -35,7 +36,7 @@ namespace Code.Gameplay.Enemies
{ {
base.Awake(); base.Awake();
if (agent == null) return; if (!agent) return;
var walkableArea = NavMesh.GetAreaFromName("Cockroach"); var walkableArea = NavMesh.GetAreaFromName("Cockroach");
agent.areaMask = 1 << walkableArea; agent.areaMask = 1 << walkableArea;
@@ -43,12 +44,14 @@ namespace Code.Gameplay.Enemies
protected override void HandleAttack() protected override void HandleAttack()
{ {
if (!Player) return; if (!Player || !_canAttack) return;
var distance = Vector3.Distance(transform.position, Player.transform.position); var distance = Vector3.Distance(transform.position, Player.transform.position);
if (!(distance <= AttackRange)) return; if (!(distance <= AttackRange)) return;
audioService.PlayEnemy(EnemiesSounds.RoachAttack, agent.transform.position);
DealDamage(); DealDamage();
} }
} }
@@ -1,4 +1,6 @@
using Code.Audio;
using Code.Configs; using Code.Configs;
using Code.Gameplay.Enemies.Animators;
using Reflex.Attributes; using Reflex.Attributes;
using UnityEngine; using UnityEngine;
using UnityEngine.AI; using UnityEngine.AI;
@@ -38,18 +40,19 @@ namespace Code.Gameplay.Enemies
if (agent == null) return; if (agent == null) return;
var walkableArea = NavMesh.GetAreaFromName("Walkable"); var walkableArea = NavMesh.GetAreaFromName("Walkable");
agent.areaMask = 1 << walkableArea; agent.areaMask = 1 << walkableArea;
} }
protected override void HandleAttack() protected override void HandleAttack()
{ {
if (!Player) return; if (!Player || !_canAttack) return;
var distance = Vector3.Distance(transform.position, Player.transform.position); var distance = Vector3.Distance(transform.position, Player.transform.position);
if (!(distance <= AttackRange)) return; if (!(distance <= AttackRange)) return;
if (Player.CustomCharacterController.IsSliding) audioService.PlayEnemy(EnemiesSounds.GrandpaAttack,agent.transform.position);
if (Player.CustomCharacterController.IsDashing || Player.CustomCharacterController.IsSliding)
ApplyStun(); ApplyStun();
else else
DealDamage(); DealDamage();
@@ -0,0 +1,34 @@
using Code.Audio;
using Reflex.Attributes;
using UnityEngine;
namespace Code.Gameplay.Enemies
{
public class EnemyAudio : MonoBehaviour
{
private IAudioService _audioService;
private IAudioFactory _audioFactory;
[SerializeField] private AudioSource _audioSource;
[SerializeField] private EnemiesSounds stepId;
[Inject]
private void Construct(IAudioService audioService, IAudioFactory audioFactory)
{
_audioService = audioService;
_audioSource = audioService.GetSourceOfGroup(Audio.AudioType.Enemies);
_audioSource.transform.position = transform.position;
_audioSource.spatialBlend = 0;
_audioFactory = audioFactory;
}
public void PlayStep()
{
_audioSource.transform.position = transform.position;
_audioSource.PlayOneShot(_audioFactory.EnemiesAudios[(int)stepId]);
}
private void OnDestroy()
{
_audioService.ReleaseSourceOfGroup(_audioSource);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 91cb250df1b24fc4825ee791a12dda11
timeCreated: 1764695102
@@ -3,9 +3,11 @@ using Code.Configs;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using Reflex.Attributes; using Reflex.Attributes;
using Reflex.Core; using Reflex.Core;
using Reflex.Extensions;
using Reflex.Injectors; using Reflex.Injectors;
using UnityEngine; using UnityEngine;
using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets;
using UnityEngine.SceneManagement;
namespace Code.Gameplay.Enemies namespace Code.Gameplay.Enemies
{ {
@@ -27,14 +29,14 @@ namespace Code.Gameplay.Enemies
) )
.ToUniTask(); .ToUniTask();
AttributeInjector.Inject(enemyObj, Container.ProjectContainer); GameObjectInjector.InjectRecursive(enemyObj, SceneManager.GetActiveScene().GetSceneContainer());
return enemyObj.GetComponent<BaseEnemy>(); return enemyObj.GetComponent<BaseEnemy>();
} }
public void ReleaseEnemy(BaseEnemy enemy) public void ReleaseEnemy(BaseEnemy enemy)
{ {
if (enemy == null) return; if (!enemy) return;
enemy.gameObject.SetActive(false); enemy.gameObject.SetActive(false);
@@ -1,8 +1,6 @@
using Code.Gameplay.Player; using Code.Gameplay.Player;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
using Reflex.Attributes; using Reflex.Attributes;
using Reflex.Core;
using Reflex.Injectors;
using UnityEngine; using UnityEngine;
namespace Code.Gameplay.Enemies namespace Code.Gameplay.Enemies
@@ -20,13 +18,14 @@ namespace Code.Gameplay.Enemies
private bool _isSpawning; private bool _isSpawning;
private bool _isPlayerInRange; private bool _isPlayerInRange;
private void Awake() // GameObjectSelfInjector существует
{ // private void Awake()
if (_playerProvider == null || _enemyFactory == null) // {
{ // if (_playerProvider == null || _enemyFactory == null)
AttributeInjector.Inject(this, Container.ProjectContainer); // {
} // AttributeInjector.Inject(this, Container.ProjectContainer);
} // }
// }
private void Update() private void Update()
{ {
@@ -64,9 +63,14 @@ namespace Code.Gameplay.Enemies
_isSpawning = false; _isSpawning = false;
} }
private void OnDestroy()
{
Despawn();
}
private void Despawn() private void Despawn()
{ {
if (_spawnedEnemy == null) return; if (!_spawnedEnemy) return;
_enemyFactory.ReleaseEnemy(_spawnedEnemy); _enemyFactory.ReleaseEnemy(_spawnedEnemy);
_spawnedEnemy = null; _spawnedEnemy = null;
@@ -10,7 +10,7 @@ namespace Code.Gameplay.Orders.Order
private bool _playerEntered; private bool _playerEntered;
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other)
{ {
if (_playerEntered) return; if (_playerEntered ) return;
_playerEntered = true; _playerEntered = true;
_orderService.OrderDelivered(); _orderService.OrderDelivered();
@@ -9,7 +9,7 @@ namespace Code.Gameplay.Orders.Order
private bool _playerEntered; private bool _playerEntered;
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other)
{ {
if (_playerEntered) return; if (_playerEntered ) return;
_playerEntered = true; _playerEntered = true;
_orderService.OrderGive(); _orderService.OrderGive();
@@ -9,7 +9,7 @@ namespace Code.Gameplay.Orders.Order
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other)
{ {
if (_playerEntered || !other.CompareTag("Player")) return; if (_playerEntered ) return;
orderDispenser.ThrowOrder(); orderDispenser.ThrowOrder();
_playerEntered = true; _playerEntered = true;
} }
@@ -0,0 +1,32 @@
using Code.Audio;
using Reflex.Attributes;
using UnityEngine;
using AudioType = Code.Audio.AudioType;
namespace Code.Gameplay.Player
{
public class PlayerAudio : MonoBehaviour
{
private IAudioService _audioService;
private IAudioFactory _audioFactory;
private AudioSource _audioSource;
[Inject]
private void Construct(IAudioService audioService, IAudioFactory audioFactory)
{
_audioService = audioService;
_audioSource = audioService.GetSourceOfGroup(AudioType.Courier);
_audioFactory = audioFactory;
}
public void PlayStep()
{
_audioSource.PlayOneShot(_audioFactory.CourierAudios[(int)CourierSounds.Step]);
}
private void OnDestroy()
{
_audioService.ReleaseSourceOfGroup(_audioSource);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 64f99dccce9d41df98accae0f355dbca
timeCreated: 1764584350
@@ -21,7 +21,7 @@ namespace Code.Gameplay.Player
if (count < 0) count = _playerConfig.maxHealth; if (count < 0) count = _playerConfig.maxHealth;
return new(count); return new(count);
} }
public async UniTask<CharacterProvider> CreatePlayer() public async UniTask<CharacterProvider> CreatePlayer()
{ {
@@ -42,7 +42,13 @@ namespace Code.Gameplay.Player
Addressables.ReleaseInstance(characterProvider.gameObject); Addressables.ReleaseInstance(characterProvider.gameObject);
} }
public async UniTask<ArmsMeshProvider> CreateArms(Transform papochka) => (await Addressables.InstantiateAsync(_playerConfig.armsMeshPrefab, papochka).ToUniTask()).GetComponent<ArmsMeshProvider>(); public async UniTask<ArmsMeshProvider> CreateArms(Transform papochka)
{
var armsMesh = (await Addressables.InstantiateAsync(_playerConfig.armsMeshPrefab, papochka).ToUniTask());
GameObjectInjector.InjectRecursive(armsMesh, Container.ProjectContainer);
return armsMesh.GetComponent<ArmsMeshProvider>();
}
public void ReleaseArms(ArmsMeshProvider arms) => Addressables.ReleaseInstance(arms.gameObject); public void ReleaseArms(ArmsMeshProvider arms) => Addressables.ReleaseInstance(arms.gameObject);
} }
} }
@@ -12,5 +12,6 @@ namespace Code.Generator
Room CreateRoomByIndex(int index, RoomType roomType); Room CreateRoomByIndex(int index, RoomType roomType);
void ReleaseRooms(); void ReleaseRooms();
GameObject GetRandomCachedPrefabOfType(RoomType roomType, out int index); GameObject GetRandomCachedPrefabOfType(RoomType roomType, out int index);
int GetRandomIndexOfType(RoomType roomType);
} }
} }
@@ -0,0 +1,9 @@
using UnityEngine;
namespace Code.Generator
{
public class InitialRoom : Room
{
public Transform playerSpawn;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4245aa5c87c7455ebad11edaad3b649e
timeCreated: 1764324045
+16 -17
View File
@@ -1,33 +1,32 @@
using System; using System;
using Code.Gameplay.Door; using Code.Gameplay.Door;
using Code.Gameplay.Orders.Order;
using Code.UI; using Code.UI;
using UnityEngine; using UnityEngine;
namespace Code.Generator namespace Code.Generator
{ {
[RequireComponent(typeof(Transform))] // Для написания нормальной системы комнат нужен другой подход в корне, это уже не исправить, только залатать большие дыры
public class Room : MonoBehaviour public class Room : MonoBehaviour
{ {
[SerializeField] private RoomType roomType; [SerializeField] protected RoomType roomType;
public RoomType RoomType => roomType; public RoomType RoomType => roomType;
[SerializeField] private float roomTimer; [SerializeField] protected float roomTimer;
public float RoomTimer => roomTimer; public float RoomTimer => roomTimer;
[SerializeField] private Transform enterMarker; [SerializeField] protected Transform enterMarker;
public Transform EnterMarker => enterMarker; public Transform EnterMarker => enterMarker;
[SerializeField] private Transform exitMarker; [SerializeField] protected Transform exitMarker;
[SerializeField] protected Transform doorSlot;
public Transform ExitMarker => exitMarker; public Transform ExitMarker => exitMarker;
[SerializeField] private Door door; [SerializeField] protected Door door;
private void Awake() public void Initialize(IOrderService orderService)
{ {
if (EnterMarker == null || ExitMarker == null) door.TranslationMode(false);
{
Debug.LogError($"Але маркеры не найдены у комнаты {gameObject.name}"); if(roomTrigger) roomTrigger.OrderService = orderService;
}
} }
public void Seal() => door.CloseTheDoor();
public void Initialize() => door.TranslationMode(false); [SerializeField] public RoomTrigger roomTrigger;
//PIZDEC
} }
} }
@@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Code.Gameplay.Orders.Order; using Code.Gameplay.Orders.Order;
using Cysharp.Threading.Tasks; using Code.Scenes;
using Code.Scenes.SceneEnvironments;
using Reflex.Attributes; using Reflex.Attributes;
using UnityEngine; using UnityEngine;
@@ -13,7 +14,7 @@ namespace Code.Generator
[Inject] private GeneratorConfig generatorConfig; [Inject] private GeneratorConfig generatorConfig;
[Inject] private IRoomGeneratorFactory _factory; [Inject] private IRoomGeneratorFactory _factory;
private List<RoomIndex> _roomIndexesStack; private List<RoomIndex> _roomIndexesStack;
private struct RoomIndex private struct RoomIndex
@@ -34,52 +35,30 @@ namespace Code.Generator
public void Initialize() public void Initialize()
{ {
// _orderService.OrderGive();
_spawnedRooms = new List<Room>(); _spawnedRooms = new List<Room>();
_roomIndexesStack = new(); _roomIndexesStack = new();
Debug.LogWarning($"КОТЛЫ ГЕНЕРАЛЬСКИЕ{_orderService.DeliveryTimer}");
// CreateRoomsStack();
// SpawnInitialRoomsAsync();
_orderService.OnOrderGiven += CreateRoomsStack; _orderService.OnOrderGiven += CreateRoomsStack;
RoomTrigger.PlayerEnteredRoom += OnPlayerEntered; CreateInitialRoom();
CreateSaveRoom();
SpawnNextRoomAsync();
} }
private void OnEnable() private void OnPlayerEntered()
{ {
RoomTrigger.PlayerEnteredRoom += OnPlayerEntered; SpawnNextRoom();
}
private void OnDisable()
{
RoomTrigger.PlayerEnteredRoom -= OnPlayerEntered;
}
public void OnPlayerEntered()
{
SpawnNextRoomAsync();
if (_spawnedRooms.Count > 3) if (_spawnedRooms.Count > 3)
{ {
Room roomToRemove = _spawnedRooms[0]; Room roomToRemove = _spawnedRooms[0];
_spawnedRooms.RemoveAt(0); _spawnedRooms.RemoveAt(0);
// _factory.ReleaseRoom(roomToRemove);
Object.Destroy(roomToRemove.gameObject); Object.Destroy(roomToRemove.gameObject);
} }
} }
private void CreateRoomsStack(float timer) private void CreateRoomsStack(float timer)
{ {
var currentSaveRoom = _roomIndexesStack[^1]; _nextRoomStackIndex = 0;
_roomIndexesStack.Clear(); _roomIndexesStack.Clear();
_roomIndexesStack.Add(currentSaveRoom);
var remainingTime = timer; var remainingTime = timer;
@@ -91,35 +70,48 @@ namespace Code.Generator
_roomIndexesStack.Add(new(RoomType.Basic, roomIndex)); _roomIndexesStack.Add(new(RoomType.Basic, roomIndex));
remainingTime -= room.RoomTimer; remainingTime -= room.RoomTimer;
Debug.Log($"комната {room.name} время {room.RoomTimer} осталось: {remainingTime}");
} }
AddPickupRoom(); AddPickupRoom();
CreateSaveRoom(); AddSaveRoom();
SpawnNextRoom();
}
private void AddSaveRoom()
{
int saveRoomIndex = _factory.GetRandomIndexOfType(RoomType.Save);
Debug.Log($"стек комнат: {_roomIndexesStack.Count}"); _roomIndexesStack.Add(new(RoomType.Save, saveRoomIndex));
} }
private void CreateSaveRoom() private void AddPickupRoom()
{ {
var prefab = _factory.GetRandomCachedPrefabOfType(RoomType.Save, out int roomIndex); int pickupIndex = _factory.GetRandomIndexOfType(RoomType.PickUp);
Room saveRoom = prefab.GetComponent<Room>();
_roomIndexesStack.Add(new(RoomType.Save, roomIndex));
Debug.Log($"Первая комната: {saveRoom.name}"); int insertPos = Random.Range(1, _roomIndexesStack.Count + 1);
_roomIndexesStack.Insert(insertPos, new(RoomType.PickUp, pickupIndex));
} }
private async UniTask SpawnInitialRoomsAsync() [Inject] private CurrentSceneEnvironment _currentSceneEnvironment;
private void CreateInitialRoom()
{ {
_nextRoomStackIndex = 0; GameplaySceneEnvironment gameplaySceneEnvironment = (GameplaySceneEnvironment)_currentSceneEnvironment;
SpawnNextRoomAsync(); int roomIndex = _factory.GetRandomIndexOfType(RoomType.Initial);
SpawnNextRoomAsync(); InitialRoom instantiated = _factory.CreateRoomByIndex(roomIndex, RoomType.Initial).GetComponent<InitialRoom>();
} _spawnedRooms.Add(instantiated);
instantiated.transform.position = Vector3.zero;
private void SpawnNextRoomAsync() instantiated.transform.rotation = Quaternion.identity;
gameplaySceneEnvironment.playerSpawnPoint = instantiated.playerSpawn;
instantiated.Initialize(_orderService);
}
private void SpawnNextRoom()
{ {
if (_nextRoomStackIndex >= _roomIndexesStack.Count) if (_nextRoomStackIndex >= _roomIndexesStack.Count)
return; return;
@@ -138,28 +130,14 @@ namespace Code.Generator
PlaceRoom(room, previousRoom); PlaceRoom(room, previousRoom);
} }
// Отписываться можно, но Хатико никогда не дождётся вызова уничтоженного объекта.
room.roomTrigger.OnEnter += OnPlayerEntered;
room.roomTrigger.OnExit += _spawnedRooms[^1].Seal;
_spawnedRooms.Add(room); _spawnedRooms.Add(room);
_nextRoomStackIndex++; _nextRoomStackIndex++;
} }
private void AddPickupRoom()
{
var prefab = _factory.GetRandomCachedPrefabOfType(RoomType.PickUp, out int pickupIndex);
Room pickupRoom = prefab.GetComponent<Room>();
if (_roomIndexesStack.Count == 0)
{
Debug.LogWarning("Стек пуст, нет позиции после первой");
return;
}
int insertPos = Random.Range(1, _roomIndexesStack.Count + 1);
_roomIndexesStack.Insert(insertPos, new(RoomType.PickUp, pickupIndex));
Debug.Log($"PickUp комната '{pickupRoom.name}' позиция {insertPos}");
}
private void PlaceRoom(Room current, Room previous) private void PlaceRoom(Room current, Room previous)
{ {
@@ -210,18 +188,8 @@ namespace Code.Generator
segmentOriginPosition.y -= randomDoorOriginPosition.y; segmentOriginPosition.y -= randomDoorOriginPosition.y;
current.transform.position = segmentOriginPosition; current.transform.position = segmentOriginPosition;
current.transform.rotation = Quaternion.Euler(0, segmentOriginYRotation, 0); current.transform.rotation = Quaternion.Euler(0, segmentOriginYRotation, 0);
// locationSegment.isNeedSomeDoors = true; current.Initialize(_orderService);
// locationSegment.AddBadDoorId(locationSegment.LocationSegment.GetDoorOrigins.IndexOf(randomDoorOrigin));
current.Initialize();
float frameOnTheBallRotation = segmentOriginYRotation + randomDoorOriginRotation.eulerAngles.y;
if (frameOnTheBallRotation > 305f) frameOnTheBallRotation -= 360f;
else if (frameOnTheBallRotation < -45f) frameOnTheBallRotation += 360f;
// heOnTheBall.AddSlaveLocationSegment(locationSegment.Id);
// heOnTheBall.ReplaceSlaveSegmentDoorOriginYRotation(frameOnTheBallRotation);
// heOnTheBall.isGotOnTheBall = false;
} }
} }
} }
@@ -30,6 +30,7 @@ namespace Code.Generator
_cashedRooms.Add(RoomType.Basic, new()); _cashedRooms.Add(RoomType.Basic, new());
_cashedRooms.Add(RoomType.Save, new ()); _cashedRooms.Add(RoomType.Save, new ());
_cashedRooms.Add(RoomType.PickUp, new ()); _cashedRooms.Add(RoomType.PickUp, new ());
_cashedRooms.Add(RoomType.Initial, new ());
} }
public async UniTask PreloadRooms(IOrderService orderService) public async UniTask PreloadRooms(IOrderService orderService)
@@ -58,6 +59,7 @@ namespace Code.Generator
index = Random.Range(0, _cashedRooms[roomType].Count); index = Random.Range(0, _cashedRooms[roomType].Count);
return _cashedRooms[roomType][index]; return _cashedRooms[roomType][index];
} }
public int GetRandomIndexOfType(RoomType roomType) => Random.Range(0, _cashedRooms[roomType].Count);
public Room CreateRoomByIndex(int index, RoomType roomType) public Room CreateRoomByIndex(int index, RoomType roomType)
{ {
@@ -1,33 +1,36 @@
using System; using System;
using Code.Gameplay.Orders.Order; using Code.Gameplay.Orders.Order;
using Reflex.Attributes;
using UnityEngine; using UnityEngine;
namespace Code.Generator namespace Code.Generator
{ {
public class RoomTrigger : MonoBehaviour public class RoomTrigger : MonoBehaviour
{ {
[Inject] private IOrderService _orderService; public IOrderService OrderService;
public event Action OnEnter;
public static event Action PlayerEnteredRoom; public event Action OnExit;
private bool _playerEntered; private bool _playerEntered, _playerExited;
// [Inject]
// private void Construct(IOrderService orderService)
// {
// _orderService = orderService;
// }
private void OnTriggerEnter(Collider other) private void OnTriggerEnter(Collider other)
{ {
if (_playerEntered) return; if (_playerEntered) return;
if (!other.CompareTag("Player")) return;
_playerEntered = true; _playerEntered = true;
_orderService.RoomPassed(); OrderService.RoomPassed();
OnEnter?.Invoke();
}
private void OnTriggerExit(Collider other)
{
if (_playerExited) return;
Debug.Log(other.name);
PlayerEnteredRoom?.Invoke(); _playerExited = true;
OnExit?.Invoke();
} }
} }
} }
@@ -1,3 +1,3 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 4207b7568dc3482393ac1860a31909b4 guid: 0d6940d73d544f0a8e4a45d956bc2364
timeCreated: 1764087485 timeCreated: 1764525516
@@ -3,8 +3,8 @@ namespace Code.Generator
public enum RoomType public enum RoomType
{ {
Basic, Basic,
Ladder,
Save, Save,
PickUp PickUp,
Initial
} }
} }
@@ -16,8 +16,8 @@ namespace Code.Input
// Для управления движением персонажа // Для управления движением персонажа
Vector2 MoveInput { get; } Vector2 MoveInput { get; }
bool JumpPressed { get; } bool JumpPressed { get; }
bool SprintPressed { get; }
bool SlidePressed { get; } bool SlidePressed { get; }
bool DashPressed { get; }
// Для переключения режима камеры // Для переключения режима камеры
bool ToggleCameraModePressed { get; } bool ToggleCameraModePressed { get; }
@@ -13,8 +13,8 @@ namespace Code.Input
public float ZoomInput { get; private set; } public float ZoomInput { get; private set; }
public Vector2 MoveInput { get; private set; } public Vector2 MoveInput { get; private set; }
public bool JumpPressed { get; private set; } public bool JumpPressed { get; private set; }
public bool SprintPressed { get; private set; }
public bool SlidePressed { get; private set; } public bool SlidePressed { get; private set; }
public bool DashPressed { get; private set; }
public bool ToggleCameraModePressed { get; private set; } public bool ToggleCameraModePressed { get; private set; }
public InputService(InputActionAsset inputActionAsset) public InputService(InputActionAsset inputActionAsset)
@@ -69,14 +69,6 @@ namespace Code.Input
jumpAction.canceled += OnJumpCanceled; jumpAction.canceled += OnJumpCanceled;
} }
// Обработка спринта (персонаж)
var sprintAction = gameplayMap.FindAction("Sprint");
if (sprintAction != null)
{
sprintAction.performed += OnSprintPerformed;
sprintAction.canceled += OnSprintCanceled;
}
// Обработка слайда (персонаж) // Обработка слайда (персонаж)
var slideAction = gameplayMap.FindAction("Slide"); var slideAction = gameplayMap.FindAction("Slide");
if (slideAction != null) if (slideAction != null)
@@ -85,6 +77,14 @@ namespace Code.Input
slideAction.canceled += OnSlideCanceled; slideAction.canceled += OnSlideCanceled;
} }
// Обработка слайда (персонаж)
var dashAction = gameplayMap.FindAction("Dash");
if (dashAction != null)
{
dashAction.performed += OnDashPerformed;
dashAction.canceled += OnDashCanceled;
}
// Обработка переключения режима камеры // Обработка переключения режима камеры
var toggleCameraModeAction = gameplayMap.FindAction("ToggleCameraMode"); var toggleCameraModeAction = gameplayMap.FindAction("ToggleCameraMode");
if (toggleCameraModeAction != null) if (toggleCameraModeAction != null)
@@ -134,16 +134,6 @@ namespace Code.Input
JumpPressed = false; JumpPressed = false;
} }
private void OnSprintPerformed(InputAction.CallbackContext context)
{
SprintPressed = true;
}
private void OnSprintCanceled(InputAction.CallbackContext context)
{
SprintPressed = false;
}
private void OnSlidePerformed(InputAction.CallbackContext context) private void OnSlidePerformed(InputAction.CallbackContext context)
{ {
SlidePressed = true; SlidePressed = true;
@@ -154,6 +144,16 @@ namespace Code.Input
SlidePressed = false; SlidePressed = false;
} }
private void OnDashPerformed(InputAction.CallbackContext context)
{
DashPressed = true;
}
private void OnDashCanceled(InputAction.CallbackContext context)
{
DashPressed = false;
}
private void OnToggleCameraModePerformed(InputAction.CallbackContext context) private void OnToggleCameraModePerformed(InputAction.CallbackContext context)
{ {
ToggleCameraModePressed = true; ToggleCameraModePressed = true;
@@ -189,12 +189,12 @@ namespace Code.Input
gameplayMap.FindAction("Jump").performed -= OnJumpPerformed; gameplayMap.FindAction("Jump").performed -= OnJumpPerformed;
gameplayMap.FindAction("Jump").canceled -= OnJumpCanceled; gameplayMap.FindAction("Jump").canceled -= OnJumpCanceled;
gameplayMap.FindAction("Sprint").performed -= OnSprintPerformed;
gameplayMap.FindAction("Sprint").canceled -= OnSprintCanceled;
gameplayMap.FindAction("Slide").performed -= OnSlidePerformed; gameplayMap.FindAction("Slide").performed -= OnSlidePerformed;
gameplayMap.FindAction("Slide").canceled -= OnSlideCanceled; gameplayMap.FindAction("Slide").canceled -= OnSlideCanceled;
gameplayMap.FindAction("Dash").performed -= OnDashPerformed;
gameplayMap.FindAction("Dash").canceled -= OnDashCanceled;
gameplayMap.FindAction("ToggleCameraMode").performed -= OnToggleCameraModePerformed; gameplayMap.FindAction("ToggleCameraMode").performed -= OnToggleCameraModePerformed;
gameplayMap.FindAction("ToggleCameraMode").canceled -= OnToggleCameraModeCanceled; gameplayMap.FindAction("ToggleCameraMode").canceled -= OnToggleCameraModeCanceled;
} }
@@ -1,5 +1,6 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 20994ffe841c70949a3d2fd4c4a13d7a guid: e76fbbe72ad97cc4f9dfe770ddc79857
folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
@@ -0,0 +1,54 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
public class LightProbeRuntime : MonoBehaviour
{
public Color m_Ambient;
Light[] m_Lights;
// Start is called before the first frame update
IEnumerator Start()
{
yield return null;
m_Lights = FindObjectsOfType<Light>();
SphericalHarmonicsL2[] bakedProbes = LightmapSettings.lightProbes.bakedProbes;
Vector3[] probePositions = LightmapSettings.lightProbes.positions;
int probeCount = LightmapSettings.lightProbes.count;
// Clear all probes
for (int i = 0; i < probeCount; i++)
bakedProbes[i].Clear();
// Add ambient light to all probes
for (int i = 0; i < probeCount; i++)
bakedProbes[i].AddAmbientLight(m_Ambient);
// Add directional and point lights' contribution to all probes
foreach (Light l in m_Lights)
{
if (l.type == LightType.Directional)
{
for (int i = 0; i < probeCount; i++)
bakedProbes[i].AddDirectionalLight(-l.transform.forward, l.color, l.intensity);
}
else if (l.type == LightType.Point)
{
for (int i = 0; i < probeCount; i++)
SHAddPointLight(probePositions[i], l.transform.position, l.range, l.color, l.intensity, ref bakedProbes[i]);
}
}
LightmapSettings.lightProbes.bakedProbes = bakedProbes;
}
void SHAddPointLight(Vector3 probePosition, Vector3 position, float range, Color color, float intensity, ref SphericalHarmonicsL2 sh)
{
// From the point of view of an SH probe, point light looks no different than a directional light,
// just attenuated and coming from the right direction.
Vector3 probeToLight = position - probePosition;
float attenuation = 1.0F / (1.0F + 25.0F * probeToLight.sqrMagnitude / (range * range));
sh.AddDirectionalLight(probeToLight.normalized, color, intensity * attenuation);
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9643888b3364f55439c6adf3309cc447
@@ -0,0 +1,295 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
[ExecuteAlways]
public class PrefabLightmapData : MonoBehaviour
{
[Tooltip("Reassigns shaders when applying the baked lightmaps. Might conflict with some shaders like transparent HDRP.")]
public bool releaseShaders = true;
[System.Serializable]
struct RendererInfo
{
public Renderer renderer;
public int lightmapIndex;
public Vector4 lightmapOffsetScale;
}
[System.Serializable]
struct LightInfo
{
public Light light;
public int lightmapBaketype;
public int mixedLightingMode;
}
[SerializeField]
RendererInfo[] m_RendererInfo;
[SerializeField]
Texture2D[] m_Lightmaps;
[SerializeField]
Texture2D[] m_LightmapsDir;
[SerializeField]
Texture2D[] m_ShadowMasks;
[SerializeField]
LightInfo[] m_LightInfo;
void Awake()
{
Init();
}
void Init()
{
if (m_RendererInfo == null || m_RendererInfo.Length == 0)
return;
var lightmaps = LightmapSettings.lightmaps;
int[] offsetsindexes = new int[m_Lightmaps.Length];
int counttotal = lightmaps.Length;
List<LightmapData> combinedLightmaps = new List<LightmapData>();
for (int i = 0; i < m_Lightmaps.Length; i++)
{
bool exists = false;
for (int j = 0; j < lightmaps.Length; j++)
{
if (m_Lightmaps[i] == lightmaps[j].lightmapColor)
{
exists = true;
offsetsindexes[i] = j;
}
}
if (!exists)
{
offsetsindexes[i] = counttotal;
var newlightmapdata = new LightmapData
{
lightmapColor = m_Lightmaps[i],
lightmapDir = m_LightmapsDir.Length == m_Lightmaps.Length ? m_LightmapsDir[i] : default(Texture2D),
shadowMask = m_ShadowMasks.Length == m_Lightmaps.Length ? m_ShadowMasks[i] : default(Texture2D),
};
combinedLightmaps.Add(newlightmapdata);
counttotal += 1;
}
}
var combinedLightmaps2 = new LightmapData[counttotal];
lightmaps.CopyTo(combinedLightmaps2, 0);
combinedLightmaps.ToArray().CopyTo(combinedLightmaps2, lightmaps.Length);
bool directional=true;
foreach(Texture2D t in m_LightmapsDir)
{
if (t == null)
{
directional = false;
break;
}
}
LightmapSettings.lightmapsMode = (m_LightmapsDir.Length == m_Lightmaps.Length && directional) ? LightmapsMode.CombinedDirectional : LightmapsMode.NonDirectional;
ApplyRendererInfo(m_RendererInfo, offsetsindexes, m_LightInfo);
LightmapSettings.lightmaps = combinedLightmaps2;
}
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
// called second
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Init();
}
// called when the game is terminated
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void ApplyRendererInfo(RendererInfo[] infos, int[] lightmapOffsetIndex, LightInfo[] lightsInfo)
{
for (int i = 0; i < infos.Length; i++)
{
var info = infos[i];
info.renderer.lightmapIndex = lightmapOffsetIndex[info.lightmapIndex];
info.renderer.lightmapScaleOffset = info.lightmapOffsetScale;
if (releaseShaders)
{
// You have to release shaders.
Material[] mat = info.renderer.sharedMaterials;
for (int j = 0; j < mat.Length; j++)
{
if (mat[j] != null && Shader.Find(mat[j].shader.name) != null)
{
mat[j].shader = Shader.Find(mat[j].shader.name);
}
}
}
}
for (int i = 0; i < lightsInfo.Length; i++)
{
LightBakingOutput bakingOutput = new LightBakingOutput();
bakingOutput.isBaked = true;
bakingOutput.lightmapBakeType = (LightmapBakeType)lightsInfo[i].lightmapBaketype;
bakingOutput.mixedLightingMode = (MixedLightingMode)lightsInfo[i].mixedLightingMode;
lightsInfo[i].light.bakingOutput = bakingOutput;
}
}
#if UNITY_EDITOR
[UnityEditor.MenuItem("Assets/Bake Prefab Lightmaps")]
static void GenerateLightmapInfo()
{
if (UnityEditor.Lightmapping.giWorkflowMode != UnityEditor.Lightmapping.GIWorkflowMode.OnDemand)
{
Debug.LogError("ExtractLightmapData requires that you have baked you lightmaps and Auto mode is disabled.");
return;
}
UnityEditor.Lightmapping.Bake();
PrefabLightmapData[] prefabs = FindObjectsOfType<PrefabLightmapData>();
foreach (var instance in prefabs)
{
var gameObject = instance.gameObject;
var rendererInfos = new List<RendererInfo>();
var lightmaps = new List<Texture2D>();
var lightmapsDir = new List<Texture2D>();
var shadowMasks = new List<Texture2D>();
var lightsInfos = new List<LightInfo>();
GenerateLightmapInfo(gameObject, rendererInfos, lightmaps, lightmapsDir, shadowMasks, lightsInfos);
instance.m_RendererInfo = rendererInfos.ToArray();
instance.m_Lightmaps = lightmaps.ToArray();
instance.m_LightmapsDir = lightmapsDir.ToArray();
instance.m_LightInfo = lightsInfos.ToArray();
instance.m_ShadowMasks = shadowMasks.ToArray();
#if UNITY_2018_3_OR_NEWER
var targetPrefab = PrefabUtility.GetCorrespondingObjectFromOriginalSource(instance.gameObject) as GameObject;
if (targetPrefab != null)
{
GameObject root = PrefabUtility.GetOutermostPrefabInstanceRoot(instance.gameObject);// 根结点
//如果当前预制体是是某个嵌套预制体的一部分(IsPartOfPrefabInstance)
if (root != null)
{
GameObject rootPrefab = PrefabUtility.GetCorrespondingObjectFromSource(instance.gameObject);
string rootPath = AssetDatabase.GetAssetPath(rootPrefab);
//打开根部预制体
PrefabUtility.UnpackPrefabInstanceAndReturnNewOutermostRoots(root, PrefabUnpackMode.OutermostRoot);
try
{
//Apply各个子预制体的改变
PrefabUtility.ApplyPrefabInstance(instance.gameObject, InteractionMode.AutomatedAction);
}
catch { }
finally
{
//重新更新根预制体
PrefabUtility.SaveAsPrefabAssetAndConnect(root, rootPath, InteractionMode.AutomatedAction);
}
}
else
{
PrefabUtility.ApplyPrefabInstance(instance.gameObject, InteractionMode.AutomatedAction);
}
}
#else
var targetPrefab = UnityEditor.PrefabUtility.GetPrefabParent(gameObject) as GameObject;
if (targetPrefab != null)
{
//UnityEditor.Prefab
UnityEditor.PrefabUtility.ReplacePrefab(gameObject, targetPrefab);
}
#endif
}
}
static void GenerateLightmapInfo(GameObject root, List<RendererInfo> rendererInfos, List<Texture2D> lightmaps, List<Texture2D> lightmapsDir, List<Texture2D> shadowMasks, List<LightInfo> lightsInfo)
{
var renderers = root.GetComponentsInChildren<MeshRenderer>();
foreach (MeshRenderer renderer in renderers)
{
if (renderer.lightmapIndex != -1)
{
RendererInfo info = new RendererInfo();
info.renderer = renderer;
if (renderer.lightmapScaleOffset != Vector4.zero)
{
//1ibrium's pointed out this issue : https://docs.unity3d.com/ScriptReference/Renderer-lightmapIndex.html
if(renderer.lightmapIndex < 0 || renderer.lightmapIndex == 0xFFFE) continue;
info.lightmapOffsetScale = renderer.lightmapScaleOffset;
Texture2D lightmap = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapColor;
Texture2D lightmapDir = LightmapSettings.lightmaps[renderer.lightmapIndex].lightmapDir;
Texture2D shadowMask = LightmapSettings.lightmaps[renderer.lightmapIndex].shadowMask;
info.lightmapIndex = lightmaps.IndexOf(lightmap);
if (info.lightmapIndex == -1)
{
info.lightmapIndex = lightmaps.Count;
lightmaps.Add(lightmap);
lightmapsDir.Add(lightmapDir);
shadowMasks.Add(shadowMask);
}
rendererInfos.Add(info);
}
}
}
var lights = root.GetComponentsInChildren<Light>(true);
foreach (Light l in lights)
{
LightInfo lightInfo = new LightInfo();
lightInfo.light = l;
lightInfo.lightmapBaketype = (int)l.lightmapBakeType;
#if UNITY_2020_1_OR_NEWER
lightInfo.mixedLightingMode = (int)UnityEditor.Lightmapping.lightingSettings.mixedBakeMode;
#elif UNITY_2018_1_OR_NEWER
lightInfo.mixedLightingMode = (int)UnityEditor.LightmapEditorSettings.mixedBakeMode;
#else
lightInfo.mixedLightingMode = (int)l.bakingOutput.lightmapBakeType;
#endif
lightsInfo.Add(lightInfo);
}
}
#endif
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: b91f32cd81021d24ab9ff545997e9666
@@ -1,5 +1,6 @@
using Code.Gameplay.Orders.Order; using Code.Gameplay.Orders.Order;
using UnityEngine; using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization; using UnityEngine.Serialization;
namespace Code.Scenes.SceneEnvironments namespace Code.Scenes.SceneEnvironments
@@ -7,11 +8,13 @@ namespace Code.Scenes.SceneEnvironments
[System.Serializable] [System.Serializable]
public class GameplaySceneEnvironment : CurrentSceneEnvironment public class GameplaySceneEnvironment : CurrentSceneEnvironment
{ {
public Transform playerSpawnPoint; public Transform playerSpawnPoint;
public Volume volume;
public void TransitVariables(GameplaySceneEnvironment env) public void TransitVariables(GameplaySceneEnvironment env)
{ {
playerSpawnPoint = env.playerSpawnPoint; playerSpawnPoint = env.playerSpawnPoint;
volume = env.volume;
} }
} }
} }
@@ -33,6 +33,8 @@ namespace Code.StaticData
Dictionary<AudioSourceType, AudioSourceSettingsConfig> AudioSourceSettingsConfigs { get; } Dictionary<AudioSourceType, AudioSourceSettingsConfig> AudioSourceSettingsConfigs { get; }
AudioTestClipsConfig AudioTestClipsConfig { get; } AudioTestClipsConfig AudioTestClipsConfig { get; }
GeneratorConfig GeneratorConfig { get; } GeneratorConfig GeneratorConfig { get; }
CourierSoundListConfig CourierSoundListConfig { get; }
DefaultAudioSettingsConfig DefaultAudioSettingsConfig { get; }
void Load(); void Load();
Task<T> InstantiateAsset<T>(AssetReference assetReference) where T : Behaviour; Task<T> InstantiateAsset<T>(AssetReference assetReference) where T : Behaviour;
} }
@@ -29,6 +29,8 @@ namespace Code.StaticData
public DispatcherSoundListConfig DispatcherSoundListConfig { get; private set; } public DispatcherSoundListConfig DispatcherSoundListConfig { get; private set; }
public EnemiesSoundListConfig EnemiesSoundListConfig { get; private set; } public EnemiesSoundListConfig EnemiesSoundListConfig { get; private set; }
public AudioTestClipsConfig AudioTestClipsConfig { get; private set; } public AudioTestClipsConfig AudioTestClipsConfig { get; private set; }
public CourierSoundListConfig CourierSoundListConfig { get; private set; }
public DefaultAudioSettingsConfig DefaultAudioSettingsConfig { get; private set; }
public DrunkenGrandpaConfig DrunkenGrandpaConfig {get; private set;} public DrunkenGrandpaConfig DrunkenGrandpaConfig {get; private set;}
public CockroachConfig CockroachConfig { get; private set; } public CockroachConfig CockroachConfig { get; private set; }
@@ -66,9 +68,11 @@ namespace Code.StaticData
private void LoadAudioConfigs() private void LoadAudioConfigs()
{ {
AudioMixerConfig = Resources.Load<AudioMixerConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "AudioMixerConfig")); AudioMixerConfig = Resources.Load<AudioMixerConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "AudioMixerConfig"));
DefaultAudioSettingsConfig = Resources.Load<DefaultAudioSettingsConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "DefaultAudioSettingsConfig"));
SoundtrackListConfig = Resources.Load<SoundtrackListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "SoundtrackListConfig")); SoundtrackListConfig = Resources.Load<SoundtrackListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "SoundtrackListConfig"));
AudioTestClipsConfig = Resources.Load<AudioTestClipsConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "AudioTestClipsConfig")); AudioTestClipsConfig = Resources.Load<AudioTestClipsConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "AudioTestClipsConfig"));
SFXListConfig = Resources.Load<SFXListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "SFXListConfig")); SFXListConfig = Resources.Load<SFXListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "SFXListConfig"));
CourierSoundListConfig = Resources.Load<CourierSoundListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "CourierSoundListConfig"));
DispatcherSoundListConfig = Resources.Load<DispatcherSoundListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "DispatcherSoundListConfig")); DispatcherSoundListConfig = Resources.Load<DispatcherSoundListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "DispatcherSoundListConfig"));
EnemiesSoundListConfig = Resources.Load<EnemiesSoundListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "EnemiesSoundListConfig")); EnemiesSoundListConfig = Resources.Load<EnemiesSoundListConfig>(string.Format(StringPaths.ConfigSingle, "Audio", "EnemiesSoundListConfig"));
AudioSourceSettingsConfigs = Resources AudioSourceSettingsConfigs = Resources
@@ -0,0 +1,25 @@
using DG.Tweening;
using UnityEngine;
using UnityEngine.UI;
namespace Code.UI.Panels
{
public class DamagePanel : UIElement
{
[SerializeField] private Image background;
[SerializeField] private Color shownColor;
[SerializeField] private Color hiddenColor;
public override void Hide()
{
Shown = false;
// background.enabled = false;
background.DOColor(hiddenColor, 2f);
}
public override void Show()
{
Shown = true;
// background.enabled = true;
background.DOColor(shownColor, 0.3f);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b586dbc292c44261892460f578a38e50
timeCreated: 1764769541
@@ -1,3 +1,4 @@
using DG.Tweening;
using TMPro; using TMPro;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@@ -9,21 +10,27 @@ namespace Code.UI
[SerializeField] private TMP_Text scoreText; [SerializeField] private TMP_Text scoreText;
[SerializeField] private TMP_Text gameOverText; [SerializeField] private TMP_Text gameOverText;
[SerializeField] private Image _background; [SerializeField] private Image _background;
[SerializeField] private Color shownColor;
[SerializeField] private Color hiddenColor;
public void UpdateScoreText(int score) => scoreText.text = score.ToString(); public void UpdateScoreText(int score) => scoreText.text = score.ToString();
public override void Hide() public override void Hide()
{ {
_background.enabled = false; _background.enabled = false;
scoreText.enabled = false; // scoreText.enabled = true;
gameOverText.enabled = false; // gameOverText.enabled = false;
scoreText.DOColor(hiddenColor, 3f);
// gameOverText.DOColor(hiddenColor, 3f);
base.Hide(); base.Hide();
} }
public override void Show() public override void Show()
{ {
_background.enabled = true; // _background.enabled = true;
scoreText.enabled = true; // scoreText.enabled = true;
gameOverText.enabled = true; // gameOverText.enabled = true;
scoreText.DOColor(shownColor, 5f);
// gameOverText.DOColor(shownColor, 5f);
base.Show(); base.Show();
} }
} }
@@ -26,6 +26,9 @@ namespace Code.UI.Panels
[Header("MoneyBar")] [Header("MoneyBar")]
[SerializeField] private TMP_Text moneyText; [SerializeField] private TMP_Text moneyText;
[SerializeField] private DamagePanel damagePanel;
public DamagePanel DamagePanel => damagePanel;
private void ScoreUpdate(int count, int money) private void ScoreUpdate(int count, int money)
{ {
// TODO Анимация получения\потери // TODO Анимация получения\потери
@@ -7,21 +7,24 @@ namespace Code.UI.Panels
public class LoadingScreen : UIElement public class LoadingScreen : UIElement
{ {
[SerializeField] private Image background; [SerializeField] private Image background;
[SerializeField] private TMP_Text loadingTitle; [SerializeField] private Image loadingImage;
[SerializeField] private TMP_Text vyapWatermark; // [SerializeField] private TMP_Text loadingTitle;
// [SerializeField] private TMP_Text vyapWatermark;
public override void Hide() public override void Hide()
{ {
Shown = false; Shown = false;
background.enabled = false; background.enabled = false;
loadingTitle.enabled = false; loadingImage.enabled = false;
vyapWatermark.enabled = false; // loadingTitle.enabled = false;
// vyapWatermark.enabled = false;
} }
public override void Show() public override void Show()
{ {
Shown = true; Shown = true;
background.enabled = true; background.enabled = true;
loadingTitle.enabled = true; loadingImage.enabled = true;
vyapWatermark.enabled = true; // loadingTitle.enabled = true;
// vyapWatermark.enabled = true;
} }
} }
} }
@@ -14,6 +14,7 @@ namespace Code.UI
[SerializeField] private Slider master; [SerializeField] private Slider master;
[SerializeField] private Slider sfx; [SerializeField] private Slider sfx;
[SerializeField] private Slider dispatcher; [SerializeField] private Slider dispatcher;
[SerializeField] private Slider courier;
[SerializeField] private Slider creatures; [SerializeField] private Slider creatures;
[SerializeField] private Slider menuMusic; [SerializeField] private Slider menuMusic;
[SerializeField] private Slider gameplayMusic; [SerializeField] private Slider gameplayMusic;
@@ -28,16 +29,19 @@ namespace Code.UI
sfx.value = _audioService.GetSetting(AudioType.SFX); sfx.value = _audioService.GetSetting(AudioType.SFX);
sfx.onValueChanged.AddListener(OnSFXUpdate); sfx.onValueChanged.AddListener(OnSFXUpdate);
dispatcher.value = _audioService.GetSetting(AudioType.DispatcherSounds); dispatcher.value = _audioService.GetSetting(AudioType.Dispatcher);
dispatcher.onValueChanged.AddListener(OnDispatcherUpdate); dispatcher.onValueChanged.AddListener(OnDispatcherUpdate);
creatures.value = _audioService.GetSetting(AudioType.Creatures); courier.value = _audioService.GetSetting(AudioType.Courier);
courier.onValueChanged.AddListener(OnCourierUpdate);
creatures.value = _audioService.GetSetting(AudioType.Enemies);
creatures.onValueChanged.AddListener(OnEnemiesUpdate); creatures.onValueChanged.AddListener(OnEnemiesUpdate);
menuMusic.value = _audioService.GetSetting(AudioType.MenuMusic); menuMusic.value = _audioService.GetSetting(AudioType.MenuMusic);
menuMusic.onValueChanged.AddListener(OnMenuMusicUpdate); menuMusic.onValueChanged.AddListener(OnMenuMusicUpdate);
gameplayMusic.value = _audioService.GetSetting(AudioType.GameplayMusic); gameplayMusic.value = _audioService.GetSetting(AudioType.ActionMusic);
gameplayMusic.onValueChanged.AddListener(OnGameplayUpdate); gameplayMusic.onValueChanged.AddListener(OnGameplayUpdate);
} }
@@ -51,25 +55,32 @@ namespace Code.UI
_audioService.ChangeSetting(AudioType.SFX, value); _audioService.ChangeSetting(AudioType.SFX, value);
_audioService.PlayTestClip(AudioType.SFX); _audioService.PlayTestClip(AudioType.SFX);
} }
private void OnCourierUpdate(float value)
{
_audioService.ChangeSetting(AudioType.Courier, value);
_audioService.PlayTestClip(AudioType.Courier);
}
private void OnDispatcherUpdate(float value) private void OnDispatcherUpdate(float value)
{ {
_audioService.ChangeSetting(AudioType.DispatcherSounds, value); _audioService.ChangeSetting(AudioType.Dispatcher, value);
_audioService.PlayTestClip(AudioType.DispatcherSounds); _audioService.PlayTestClip(AudioType.Dispatcher);
} }
private void OnEnemiesUpdate(float value) private void OnEnemiesUpdate(float value)
{ {
_audioService.ChangeSetting(AudioType.Creatures, value); _audioService.ChangeSetting(AudioType.Enemies, value);
_audioService.PlayTestClip(AudioType.Creatures); _audioService.PlayTestClip(AudioType.Enemies);
} }
private void OnMenuMusicUpdate(float value) private void OnMenuMusicUpdate(float value)
{ {
_audioService.ChangeSetting(AudioType.MenuMusic, value); _audioService.ChangeSetting(AudioType.MenuMusic, value);
_audioService.ChangeSetting(AudioType.DeathMusic, value);
_audioService.PlayTestClip(AudioType.MenuMusic); _audioService.PlayTestClip(AudioType.MenuMusic);
} }
private void OnGameplayUpdate(float value) private void OnGameplayUpdate(float value)
{ {
_audioService.ChangeSetting(AudioType.GameplayMusic, value); _audioService.ChangeSetting(AudioType.ActionMusic, value);
_audioService.PlayTestClip(AudioType.GameplayMusic); _audioService.ChangeSetting(AudioType.PeacefulMusic, value);
_audioService.PlayTestClip(AudioType.ActionMusic);
} }
public override void Hide() public override void Hide()
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 45b4aa0e7c33e934493bb7d2a15a9add
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 767316a9a37abc34694c3086d846f668
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 43bd94852ddc6b34dbe9fec318fb54d8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,17 @@
{
"name": "AYellowpaper.SerializedCollections.Editor",
"references": [
"GUID:d525ad6bd40672747bde77962f1c401e"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 234340c04eed5674a988bc6ebde7d248
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 243052
packageName: Serialized Dictionary
packageVersion: 1.0.13
assetPath: Assets/Plugins/SerializedCollections/Editor/AYellowpaper.SerializedCollections.Editor.asmdef
uploadId: 632226
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: edb739dfb1824234681f6480c75cd523
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,177 @@
fileFormatVersion: 2
guid: 8deddfed9f39d7740879d2cb0fcf7ce0
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: iPhone
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 8192
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 243052
packageName: Serialized Dictionary
packageVersion: 1.0.13
assetPath: Assets/Plugins/SerializedCollections/Editor/Assets/BurgerMenu@2x.png
uploadId: 632226
Loaded 100 of 638 files, more files were not shown because too many files have changed in this diff. Show more