Add FloorVisibilityManager for dynamic floor visibility management and update material properties for transparency effects

This commit is contained in:
2025-12-13 01:35:22 +01:00
parent 189bbb7ae7
commit 7b1eb645ef
13 changed files with 348 additions and 24 deletions

View File

@@ -24,9 +24,10 @@ Material:
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3} m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: [] m_ValidKeywords:
- _EMISSION
m_InvalidKeywords: [] m_InvalidKeywords: []
m_LightmapFlags: 4 m_LightmapFlags: 6
m_EnableInstancingVariants: 0 m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: -1 m_CustomRenderQueue: -1

View File

@@ -25,16 +25,20 @@ Material:
m_Parent: {fileID: 2100000, guid: 6f050d9117f771bbbab3e6f1eead9d67, type: 2} m_Parent: {fileID: 2100000, guid: 6f050d9117f771bbbab3e6f1eead9d67, type: 2}
m_ModifiedSerializedProperties: 2 m_ModifiedSerializedProperties: 2
m_ValidKeywords: m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _EMISSION - _EMISSION
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: [] m_InvalidKeywords: []
m_LightmapFlags: 6 m_LightmapFlags: 6
m_EnableInstancingVariants: 0 m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: -1 m_CustomRenderQueue: -1
stringTagMap: stringTagMap:
RenderType: Opaque RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- MOTIONVECTORS - MOTIONVECTORS
- DepthOnly
- SHADOWCASTER
m_LockedProperties: m_LockedProperties:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3

View File

@@ -12,16 +12,20 @@ Material:
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: m_ValidKeywords:
- _ALPHAPREMULTIPLY_ON
- _EMISSION - _EMISSION
- _SURFACE_TYPE_TRANSPARENT
m_InvalidKeywords: [] m_InvalidKeywords: []
m_LightmapFlags: 6 m_LightmapFlags: 6
m_EnableInstancingVariants: 0 m_EnableInstancingVariants: 1
m_DoubleSidedGI: 0 m_DoubleSidedGI: 0
m_CustomRenderQueue: -1 m_CustomRenderQueue: 3000
stringTagMap: stringTagMap:
RenderType: Opaque RenderType: Transparent
disabledShaderPasses: disabledShaderPasses:
- MOTIONVECTORS - MOTIONVECTORS
- DepthOnly
- SHADOWCASTER
m_LockedProperties: m_LockedProperties:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
@@ -96,8 +100,8 @@ Material:
- _Cutoff: 0.5 - _Cutoff: 0.5
- _DetailAlbedoMapScale: 1 - _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1 - _DetailNormalMapScale: 1
- _DstBlend: 0 - _DstBlend: 10
- _DstBlendAlpha: 0 - _DstBlendAlpha: 10
- _EnvironmentReflections: 1 - _EnvironmentReflections: 1
- _GlossMapScale: 0 - _GlossMapScale: 0
- _Glossiness: 0 - _Glossiness: 0
@@ -112,10 +116,10 @@ Material:
- _SpecularHighlights: 1 - _SpecularHighlights: 1
- _SrcBlend: 1 - _SrcBlend: 1
- _SrcBlendAlpha: 1 - _SrcBlendAlpha: 1
- _Surface: 0 - _Surface: 1
- _WorkflowMode: 1 - _WorkflowMode: 1
- _XRMotionVectorsPass: 1 - _XRMotionVectorsPass: 1
- _ZWrite: 1 - _ZWrite: 0
m_Colors: m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1} - _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1} - _Color: {r: 1, g: 1, b: 1, a: 1}

View File

@@ -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

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: af1492750aabf7eb688b2ba78cdbe649
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -165,6 +165,7 @@ MonoBehaviour:
m_Bits: 8 m_Bits: 8
groundCheckDistance: 1.5 groundCheckDistance: 1.5
rb: {fileID: 3588611028122136830} rb: {fileID: 3588611028122136830}
meshRenderer: {fileID: 8236084859009437792}
--- !u!1 &9126679406312342716 --- !u!1 &9126679406312342716
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0

View File

@@ -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<List<TileViewAdapter>> _floors;
private int _currentFloorIndex = -1;
public void Initialize(GameSession gameSession, List<Tile> allTiles, Dictionary<string, TileViewAdapter> tileViews, int totalFloors)
{
_gameSession = gameSession;
_floors = new List<List<TileViewAdapter>>();
for (var i = 0; i < totalFloors; i++)
{
_floors.Add(new List<TileViewAdapter>());
}
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;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f836b4958c2c40e4b631f86b35e9f63b
timeCreated: 1765585554

View File

@@ -21,6 +21,7 @@ namespace Infrastructure.Unity
[SerializeField] private CameraController cameraController; [SerializeField] private CameraController cameraController;
[SerializeField] private NpcController npcPrefab; [SerializeField] private NpcController npcPrefab;
[SerializeField] private HunterNpcController hunterNpcPrefab; [SerializeField] private HunterNpcController hunterNpcPrefab;
[SerializeField] private FloorVisibilityManager floorVisibilityManager;
[Header("Level Generation")] [Header("Level Generation")]
[SerializeField] private int floorsCount = 3; [SerializeField] private int floorsCount = 3;
@@ -68,7 +69,17 @@ namespace Infrastructure.Unity
// Set Theme based on High Score // Set Theme based on High Score
ThemeManager.CurrentTheme = ThemeManager.GetTheme(_gameSession.HighScore); 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>();
}
floorVisibilityManager.Initialize(_gameSession, _allTiles, _tileViews, floorsCount);
}
SpawnDeathPlane(); SpawnDeathPlane();
SpawnPlayer(); SpawnPlayer();
@@ -95,11 +106,18 @@ namespace Infrastructure.Unity
if (_playerInstance) if (_playerInstance)
{ {
var playerY = _playerInstance.transform.position.y; var playerY = _playerInstance.transform.position.y;
var currentFloor = Mathf.RoundToInt(-playerY / floorHeightDistance); // Calculate current floor index based on Y height (inverse logic from Generator)
// Note: Generator uses negative offsets: 0, -15, -30.
currentFloor = Mathf.Clamp(currentFloor, 0, floorsCount - 1); // 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); _gameSession.SetPlayerFloor(currentFloor);
// UPDATE VISIBILITY
floorVisibilityManager.UpdateFloorVisibility(currentFloor);
} }
var dt = Time.deltaTime; var dt = Time.deltaTime;

View File

@@ -29,14 +29,11 @@ namespace Infrastructure.Unity
var dilation = _timeDilationProvider?.Invoke() ?? 1f; var dilation = _timeDilationProvider?.Invoke() ?? 1f;
if (IsGrounded()) var direction = (_target.transform.position - transform.position).normalized;
{ direction.y = 0;
var direction = (_target.transform.position - transform.position).normalized; direction.Normalize();
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)) if (Physics.Raycast(transform.position, Vector3.down, out var hit, 2f, tileLayer))
{ {

View File

@@ -43,7 +43,7 @@ namespace Infrastructure.Unity
{ {
var dilation = _timeDilationProvider?.Invoke() ?? 1f; 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)) if (Physics.Raycast(transform.position, Vector3.down, out var hit, 2.0f, tileLayer))
{ {

View File

@@ -1,5 +1,6 @@
using System; using System;
using Core.Domain.Status; using Core.Domain.Status;
using Core.Domain.Status.Effects;
using KBCore.Refs; using KBCore.Refs;
using UnityEngine; using UnityEngine;
using UnityEngine.InputSystem; using UnityEngine.InputSystem;
@@ -23,10 +24,16 @@ namespace Infrastructure.Unity
[SerializeField] private float groundCheckDistance = 1.5f; [SerializeField] private float groundCheckDistance = 1.5f;
[Self][SerializeField] private Rigidbody rb; [Self][SerializeField] private Rigidbody rb;
[Self][SerializeField] private MeshRenderer meshRenderer;
private InputSystem_Actions _actions; private InputSystem_Actions _actions;
private Vector2 _moveInput; private Vector2 _moveInput;
private Transform _camTransform; 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 Rigidbody Rigidbody => rb;
public StatusManager Status { get; private set; } public StatusManager Status { get; private set; }
@@ -58,15 +65,21 @@ namespace Infrastructure.Unity
} }
rb.freezeRotation = true; 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() private void Update()
{ {
Status.Tick(Time.deltaTime); Status.Tick(Time.deltaTime);
// Apply Status logic
rb.useGravity = !Status.CurrentCapabilities.CanHover; rb.useGravity = !Status.CurrentCapabilities.CanHover;
UpdateVisuals();
} }
private void FixedUpdate() private void FixedUpdate()
@@ -171,5 +184,40 @@ namespace Infrastructure.Unity
{ {
_moveInput = Vector2.zero; _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);
}
} }
} }

View File

@@ -31,6 +31,7 @@ namespace Infrastructure.Unity
private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor"); private static readonly int EmissionColorProperty = Shader.PropertyToID("_EmissionColor");
private Action<TileViewAdapter> _onReturnToPool; private Action<TileViewAdapter> _onReturnToPool;
private float _targetAlpha = 1f;
private void Awake() private void Awake()
{ {
@@ -115,9 +116,23 @@ namespace Infrastructure.Unity
StartCoroutine(PulseScaleRoutine()); 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) private void SetColor(Color color)
{ {
meshRenderer.GetPropertyBlock(_propBlock); meshRenderer.GetPropertyBlock(_propBlock);
color.a = _targetAlpha;
_propBlock.SetColor(ColorProperty, color); _propBlock.SetColor(ColorProperty, color);
meshRenderer.SetPropertyBlock(_propBlock); meshRenderer.SetPropertyBlock(_propBlock);
} }