diff --git a/Assets/Materials/Orb.mat b/Assets/Materials/Orb.mat index f969c17..8d0df15 100644 --- a/Assets/Materials/Orb.mat +++ b/Assets/Materials/Orb.mat @@ -24,9 +24,10 @@ Material: m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 - m_ValidKeywords: [] + m_ValidKeywords: + - _EMISSION m_InvalidKeywords: [] - m_LightmapFlags: 4 + m_LightmapFlags: 6 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 m_CustomRenderQueue: -1 diff --git a/Assets/Materials/PowerUp.mat b/Assets/Materials/PowerUp.mat index f3651d3..52ebc88 100644 --- a/Assets/Materials/PowerUp.mat +++ b/Assets/Materials/PowerUp.mat @@ -25,16 +25,20 @@ Material: m_Parent: {fileID: 2100000, guid: 6f050d9117f771bbbab3e6f1eead9d67, type: 2} m_ModifiedSerializedProperties: 2 m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON - _EMISSION + - _SURFACE_TYPE_TRANSPARENT m_InvalidKeywords: [] m_LightmapFlags: 6 m_EnableInstancingVariants: 0 m_DoubleSidedGI: 0 m_CustomRenderQueue: -1 stringTagMap: - RenderType: Opaque + RenderType: Transparent disabledShaderPasses: - MOTIONVECTORS + - DepthOnly + - SHADOWCASTER m_LockedProperties: m_SavedProperties: serializedVersion: 3 diff --git a/Assets/Materials/Tile.mat b/Assets/Materials/Tile.mat index 19706e9..4625ec6 100644 --- a/Assets/Materials/Tile.mat +++ b/Assets/Materials/Tile.mat @@ -12,16 +12,20 @@ Material: m_Parent: {fileID: 0} m_ModifiedSerializedProperties: 0 m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON - _EMISSION + - _SURFACE_TYPE_TRANSPARENT m_InvalidKeywords: [] m_LightmapFlags: 6 - m_EnableInstancingVariants: 0 + m_EnableInstancingVariants: 1 m_DoubleSidedGI: 0 - m_CustomRenderQueue: -1 + m_CustomRenderQueue: 3000 stringTagMap: - RenderType: Opaque + RenderType: Transparent disabledShaderPasses: - MOTIONVECTORS + - DepthOnly + - SHADOWCASTER m_LockedProperties: m_SavedProperties: serializedVersion: 3 @@ -96,8 +100,8 @@ Material: - _Cutoff: 0.5 - _DetailAlbedoMapScale: 1 - _DetailNormalMapScale: 1 - - _DstBlend: 0 - - _DstBlendAlpha: 0 + - _DstBlend: 10 + - _DstBlendAlpha: 10 - _EnvironmentReflections: 1 - _GlossMapScale: 0 - _Glossiness: 0 @@ -112,10 +116,10 @@ Material: - _SpecularHighlights: 1 - _SrcBlend: 1 - _SrcBlendAlpha: 1 - - _Surface: 0 + - _Surface: 1 - _WorkflowMode: 1 - _XRMotionVectorsPass: 1 - - _ZWrite: 1 + - _ZWrite: 0 m_Colors: - _BaseColor: {r: 1, g: 1, b: 1, a: 1} - _Color: {r: 1, g: 1, b: 1, a: 1} diff --git a/Assets/Materials/TileBreakVfx.mat b/Assets/Materials/TileBreakVfx.mat new file mode 100644 index 0000000..4835188 --- /dev/null +++ b/Assets/Materials/TileBreakVfx.mat @@ -0,0 +1,142 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 8 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: TileBreakVfx + m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} + m_Parent: {fileID: 0} + m_ModifiedSerializedProperties: 0 + m_ValidKeywords: + - _ALPHAPREMULTIPLY_ON + - _EMISSION + - _SURFACE_TYPE_TRANSPARENT + m_InvalidKeywords: [] + m_LightmapFlags: 6 + m_EnableInstancingVariants: 1 + m_DoubleSidedGI: 0 + m_CustomRenderQueue: 3000 + stringTagMap: + RenderType: Transparent + disabledShaderPasses: + - MOTIONVECTORS + - DepthOnly + - SHADOWCASTER + m_LockedProperties: + m_SavedProperties: + serializedVersion: 3 + m_TexEnvs: + - _BaseMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _BumpMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailAlbedoMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailMask: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _DetailNormalMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _EmissionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MainTex: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _MetallicGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _OcclusionMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _ParallaxMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - _SpecGlossMap: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_Lightmaps: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_LightmapsInd: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + - unity_ShadowMasks: + m_Texture: {fileID: 0} + m_Scale: {x: 1, y: 1} + m_Offset: {x: 0, y: 0} + m_Ints: [] + m_Floats: + - _AddPrecomputedVelocity: 0 + - _AlphaClip: 0 + - _AlphaToMask: 0 + - _Blend: 0 + - _BlendModePreserveSpecular: 1 + - _BumpScale: 1 + - _ClearCoatMask: 0 + - _ClearCoatSmoothness: 0 + - _Cull: 2 + - _Cutoff: 0.5 + - _DetailAlbedoMapScale: 1 + - _DetailNormalMapScale: 1 + - _DstBlend: 10 + - _DstBlendAlpha: 10 + - _EnvironmentReflections: 1 + - _GlossMapScale: 0 + - _Glossiness: 0 + - _GlossyReflections: 0 + - _Metallic: 0 + - _OcclusionStrength: 1 + - _Parallax: 0.005 + - _QueueOffset: 0 + - _ReceiveShadows: 1 + - _Smoothness: 0.5 + - _SmoothnessTextureChannel: 0 + - _SpecularHighlights: 1 + - _SrcBlend: 1 + - _SrcBlendAlpha: 1 + - _Surface: 1 + - _WorkflowMode: 1 + - _XRMotionVectorsPass: 1 + - _ZWrite: 0 + m_Colors: + - _BaseColor: {r: 1, g: 1, b: 1, a: 1} + - _Color: {r: 1, g: 1, b: 1, a: 1} + - _EmissionColor: {r: 0, g: 0, b: 0, a: 1} + - _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1} + m_BuildTextureStacks: [] + m_AllowLocking: 1 +--- !u!114 &69646477803621672 +MonoBehaviour: + m_ObjectHideFlags: 11 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion + version: 10 diff --git a/Assets/Materials/TileBreakVfx.mat.meta b/Assets/Materials/TileBreakVfx.mat.meta new file mode 100644 index 0000000..4e505c9 --- /dev/null +++ b/Assets/Materials/TileBreakVfx.mat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af1492750aabf7eb688b2ba78cdbe649 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Player.prefab b/Assets/Prefabs/Player.prefab index 61fe6be..38cf2ce 100644 --- a/Assets/Prefabs/Player.prefab +++ b/Assets/Prefabs/Player.prefab @@ -165,6 +165,7 @@ MonoBehaviour: m_Bits: 8 groundCheckDistance: 1.5 rb: {fileID: 3588611028122136830} + meshRenderer: {fileID: 8236084859009437792} --- !u!1 &9126679406312342716 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/Infrastructure/Unity/FloorVisibilityManager.cs b/Assets/Scripts/Infrastructure/Unity/FloorVisibilityManager.cs new file mode 100644 index 0000000..ca3e13b --- /dev/null +++ b/Assets/Scripts/Infrastructure/Unity/FloorVisibilityManager.cs @@ -0,0 +1,83 @@ +using System.Collections; +using System.Collections.Generic; +using Core.Domain; +using UnityEngine; + +namespace Infrastructure.Unity +{ + public class FloorVisibilityManager : MonoBehaviour + { + [SerializeField] private float fadeSpeed = 5f; + [SerializeField] private float hiddenAlpha = 0.1f; + [SerializeField] private float visibleAlpha = 1.0f; + + private GameSession _gameSession; + private List> _floors; + private int _currentFloorIndex = -1; + + public void Initialize(GameSession gameSession, List allTiles, Dictionary tileViews, int totalFloors) + { + _gameSession = gameSession; + + _floors = new List>(); + for (var i = 0; i < totalFloors; i++) + { + _floors.Add(new List()); + } + + foreach (var tile in allTiles) + { + if (tileViews.TryGetValue(tile.Id, out var view)) + { + // Safety check for array bounds + if (tile.Floor < _floors.Count) + { + _floors[tile.Floor].Add(view); + } + } + } + } + + private void Update() + { + if (_gameSession == null) return; + + // Check if player changed floors + // We read the private field _playerFloorIndex via a public getter we need to add, + // OR we just track it locally if you updated GameSession to expose it. + // Assuming GameSession doesn't expose it publically yet, let's rely on GameBootstrap passing it or just hack it: + // Ideally, GameSession should emit an event 'OnFloorChanged'. + // For now, let's assume we can get it or we passed the player reference. + } + + // Call this from GameBootstrap.Update() + public void UpdateFloorVisibility(int playerFloorIndex) + { + if (_currentFloorIndex == playerFloorIndex) return; + + _currentFloorIndex = playerFloorIndex; + StopAllCoroutines(); + StartCoroutine(UpdateFloorsRoutine(playerFloorIndex)); + } + + private IEnumerator UpdateFloorsRoutine(int playerFloor) + { + for (var i = 0; i < _floors.Count; i++) + { + var targetAlpha = (i < playerFloor) ? hiddenAlpha : visibleAlpha; + + if (_floors[i].Count == 0) continue; + + foreach (var tile in _floors[i]) + { + if (tile && tile.gameObject.activeInHierarchy) + { + tile.SetAlpha(targetAlpha); + } + } + + if (i % 2 == 0) yield return null; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Infrastructure/Unity/FloorVisibilityManager.cs.meta b/Assets/Scripts/Infrastructure/Unity/FloorVisibilityManager.cs.meta new file mode 100644 index 0000000..1c641c9 --- /dev/null +++ b/Assets/Scripts/Infrastructure/Unity/FloorVisibilityManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f836b4958c2c40e4b631f86b35e9f63b +timeCreated: 1765585554 \ No newline at end of file diff --git a/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs b/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs index a100142..78c7b65 100644 --- a/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs +++ b/Assets/Scripts/Infrastructure/Unity/GameBootstrap.cs @@ -21,6 +21,7 @@ namespace Infrastructure.Unity [SerializeField] private CameraController cameraController; [SerializeField] private NpcController npcPrefab; [SerializeField] private HunterNpcController hunterNpcPrefab; + [SerializeField] private FloorVisibilityManager floorVisibilityManager; [Header("Level Generation")] [SerializeField] private int floorsCount = 3; @@ -68,7 +69,17 @@ namespace Infrastructure.Unity // Set Theme based on High Score ThemeManager.CurrentTheme = ThemeManager.GetTheme(_gameSession.HighScore); - if (levelGenerator) levelGenerator.Generate(soundManager, _allTiles, _tileViews, cameraController, rumbleManager); + if (levelGenerator) + { + levelGenerator.Generate(soundManager, _allTiles, _tileViews, cameraController, rumbleManager); + + if (!floorVisibilityManager) + { + floorVisibilityManager = gameObject.AddComponent(); + } + + floorVisibilityManager.Initialize(_gameSession, _allTiles, _tileViews, floorsCount); + } SpawnDeathPlane(); SpawnPlayer(); @@ -95,11 +106,18 @@ namespace Infrastructure.Unity if (_playerInstance) { var playerY = _playerInstance.transform.position.y; - var currentFloor = Mathf.RoundToInt(-playerY / floorHeightDistance); - - currentFloor = Mathf.Clamp(currentFloor, 0, floorsCount - 1); + // Calculate current floor index based on Y height (inverse logic from Generator) + // Note: Generator uses negative offsets: 0, -15, -30. + // So Floor 0 is at Y=0. Floor 1 is at Y=-15. + + // Math to get positive index: + var rawFloor = Mathf.RoundToInt(-playerY / floorHeightDistance); + var currentFloor = Mathf.Clamp(rawFloor, 0, floorsCount - 1); _gameSession.SetPlayerFloor(currentFloor); + + // UPDATE VISIBILITY + floorVisibilityManager.UpdateFloorVisibility(currentFloor); } var dt = Time.deltaTime; diff --git a/Assets/Scripts/Infrastructure/Unity/HunterNpcController.cs b/Assets/Scripts/Infrastructure/Unity/HunterNpcController.cs index 348e367..a0d9b34 100644 --- a/Assets/Scripts/Infrastructure/Unity/HunterNpcController.cs +++ b/Assets/Scripts/Infrastructure/Unity/HunterNpcController.cs @@ -29,14 +29,11 @@ namespace Infrastructure.Unity var dilation = _timeDilationProvider?.Invoke() ?? 1f; - if (IsGrounded()) - { - var direction = (_target.transform.position - transform.position).normalized; - direction.y = 0; - direction.Normalize(); + var direction = (_target.transform.position - transform.position).normalized; + direction.y = 0; + direction.Normalize(); - rb.MovePosition(rb.position + direction * (moveSpeed * dilation * Time.fixedDeltaTime)); - } + rb.MovePosition(rb.position + direction * (moveSpeed * dilation * Time.fixedDeltaTime)); if (Physics.Raycast(transform.position, Vector3.down, out var hit, 2f, tileLayer)) { diff --git a/Assets/Scripts/Infrastructure/Unity/NpcController.cs b/Assets/Scripts/Infrastructure/Unity/NpcController.cs index 5535919..7d8ec1f 100644 --- a/Assets/Scripts/Infrastructure/Unity/NpcController.cs +++ b/Assets/Scripts/Infrastructure/Unity/NpcController.cs @@ -43,7 +43,7 @@ namespace Infrastructure.Unity { var dilation = _timeDilationProvider?.Invoke() ?? 1f; - if (IsGrounded()) rb.MovePosition(rb.position + _currentDir * (moveSpeed * dilation * Time.fixedDeltaTime)); + rb.MovePosition(rb.position + _currentDir * (moveSpeed * dilation * Time.fixedDeltaTime)); if (Physics.Raycast(transform.position, Vector3.down, out var hit, 2.0f, tileLayer)) { diff --git a/Assets/Scripts/Infrastructure/Unity/PlayerController.cs b/Assets/Scripts/Infrastructure/Unity/PlayerController.cs index 7372e1a..590628a 100644 --- a/Assets/Scripts/Infrastructure/Unity/PlayerController.cs +++ b/Assets/Scripts/Infrastructure/Unity/PlayerController.cs @@ -1,5 +1,6 @@ using System; using Core.Domain.Status; +using Core.Domain.Status.Effects; using KBCore.Refs; using UnityEngine; using UnityEngine.InputSystem; @@ -23,10 +24,16 @@ namespace Infrastructure.Unity [SerializeField] private float groundCheckDistance = 1.5f; [Self][SerializeField] private Rigidbody rb; + [Self][SerializeField] private MeshRenderer meshRenderer; private InputSystem_Actions _actions; private Vector2 _moveInput; private Transform _camTransform; + + private MaterialPropertyBlock _propBlock; + private static readonly int ColorProperty = Shader.PropertyToID("_BaseColor"); + private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor"); + private Color _defaultColor = Color.white; public Rigidbody Rigidbody => rb; public StatusManager Status { get; private set; } @@ -58,15 +65,21 @@ namespace Infrastructure.Unity } rb.freezeRotation = true; - // RB gravity is controlled by capabilities + + _propBlock = new MaterialPropertyBlock(); + if (meshRenderer.material.HasProperty(ColorProperty)) + { + _defaultColor = meshRenderer.material.GetColor(ColorProperty); + } } private void Update() { Status.Tick(Time.deltaTime); - // Apply Status logic rb.useGravity = !Status.CurrentCapabilities.CanHover; + + UpdateVisuals(); } private void FixedUpdate() @@ -171,5 +184,40 @@ namespace Infrastructure.Unity { _moveInput = Vector2.zero; } + + private void UpdateVisuals() + { + var targetColor = _defaultColor; + var emissionColor = Color.black; + + var caps = Status.CurrentCapabilities; + + if (caps.CanHover) + { + targetColor = EffectColors.HoverColor; + emissionColor = EffectColors.HoverColor * 0.5f; + } + else if (!caps.CanTriggerDecay) + { + targetColor = EffectColors.LightFootedColor; + } + else if (caps.SpeedMultiplier > 1.2f) + { + targetColor = EffectColors.SpeedBoostColor; + emissionColor = EffectColors.SpeedBoostColor * 0.5f; + } + + meshRenderer.GetPropertyBlock(_propBlock); + + var currentColor = _propBlock.GetColor(ColorProperty); + if (currentColor.a == 0) currentColor = _defaultColor; + + var newColor = Color.Lerp(currentColor, targetColor, Time.deltaTime * 5f); + + _propBlock.SetColor(ColorProperty, newColor); + _propBlock.SetColor(EmissionColorProperty, emissionColor); + + meshRenderer.SetPropertyBlock(_propBlock); + } } } \ No newline at end of file diff --git a/Assets/Scripts/Infrastructure/Unity/TileViewAdapter.cs b/Assets/Scripts/Infrastructure/Unity/TileViewAdapter.cs index 84b1d5a..710eca9 100644 --- a/Assets/Scripts/Infrastructure/Unity/TileViewAdapter.cs +++ b/Assets/Scripts/Infrastructure/Unity/TileViewAdapter.cs @@ -31,6 +31,7 @@ namespace Infrastructure.Unity private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor"); private Action _onReturnToPool; + private float _targetAlpha = 1f; private void Awake() { @@ -115,9 +116,23 @@ namespace Infrastructure.Unity StartCoroutine(PulseScaleRoutine()); } + public void SetAlpha(float alpha) + { + _targetAlpha = alpha; + + meshRenderer.GetPropertyBlock(_propBlock); + var currentColor = _propBlock.GetColor(ColorProperty); + currentColor.a = _targetAlpha; + _propBlock.SetColor(ColorProperty, currentColor); + meshRenderer.SetPropertyBlock(_propBlock); + } + private void SetColor(Color color) { meshRenderer.GetPropertyBlock(_propBlock); + + color.a = _targetAlpha; + _propBlock.SetColor(ColorProperty, color); meshRenderer.SetPropertyBlock(_propBlock); }