// hideable.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
[DisallowMultipleComponent]
public class Hideable : MonoBehaviour
{
[Range(0f, 1f)]
public float hiddenAlpha = 0.25f;
public bool forceMaterialInstanceFallback = false;
Renderer[] renderers;
MaterialPropertyBlock mpb;
Dictionary<Renderer, Material[]> instancedMaterials = new Dictionary<Renderer, Material[]>();
bool isHidden = false;
void Awake()
{
renderers = GetComponentsInChildren<Renderer>(includeInactive: true);
mpb = new MaterialPropertyBlock();
}
public void SetHidden(bool hidden)
{
if (isHidden == hidden) return;
isHidden = hidden;
if (hidden) ApplyHidden(); else RevertHidden();
}
void ApplyHidden()
{
foreach (var r in renderers)
{
if (r == null) continue;
bool mpbWorked = TrySetAlphaViaMPB(r, hiddenAlpha);
if (!mpbWorked || forceMaterialInstanceFallback)
{
InstanceAndSetMaterials(r, hiddenAlpha);
}
else
{
SafeSetShadows(r, false);
}
}
}
void RevertHidden()
{
foreach (var r in renderers)
{
if (r == null) continue;
try { r.SetPropertyBlock(null); } catch { }
if (instancedMaterials.TryGetValue(r, out var mats))
{
try { r.sharedMaterials = mats; } catch { }
instancedMaterials.Remove(r);
}
SafeSetShadows(r, true);
}
}
bool TrySetAlphaViaMPB(Renderer r, float alpha)
{
var mat = r.sharedMaterial;
if (mat == null) return false;
string colorProp = null;
if (mat.HasProperty("_BaseColor")) colorProp = "_BaseColor";
else if (mat.HasProperty("_Color")) colorProp = "_Color";
if (colorProp == null) return false;
try
{
Color current = mat.GetColor(colorProp);
current.a = alpha;
mpb.Clear();
mpb.SetColor(colorProp, current);
if (mat.HasProperty("_Surface")) mpb.SetFloat("_Surface", 1f);
r.SetPropertyBlock(mpb);
return true;
}
catch { return false; }
}
void InstanceAndSetMaterials(Renderer r, float alpha)
{
if (r == null) return;
if (!instancedMaterials.ContainsKey(r))
{
try { instancedMaterials[r] = r.sharedMaterials; } catch { }
}
Material[] mats;
try { mats = r.materials; } catch { return; }
for (int i = 0; i < mats.Length; i++)
{
var m = mats[i];
if (m == null) continue;
if (m.HasProperty("_BaseColor"))
{
Color c = m.GetColor("_BaseColor");
c.a = alpha;
m.SetColor("_BaseColor", c);
if (m.HasProperty("_Surface")) m.SetFloat("_Surface", 1f);
m.renderQueue = 3000;
}
else if (m.HasProperty("_Color"))
{
Color c = m.GetColor("_Color");
c.a = alpha;
m.SetColor("_Color", c);
ConfigureMaterialForTransparency(m);
}
else
{
ConfigureMaterialForTransparency(m);
}
mats[i] = m;
}
try { r.materials = mats; } catch { }
SafeSetShadows(r, false);
}
static void ConfigureMaterialForTransparency(Material m)
{
if (m == null) return;
try
{
m.SetOverrideTag("RenderType", "Transparent");
m.SetFloat("_Mode", 3f);
m.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha);
m.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha);
if (m.HasProperty("_ZWrite")) m.SetInt("_ZWrite", 0);
m.DisableKeyword("_ALPHATEST_ON");
m.EnableKeyword("_ALPHABLEND_ON");
m.DisableKeyword("_ALPHAPREMULTIPLY_ON");
m.renderQueue = 3000;
}
catch { }
}
static void SafeSetShadows(Renderer r, bool enable)
{
try
{
r.shadowCastingMode = enable ? ShadowCastingMode.On : ShadowCastingMode.Off;
r.receiveShadows = enable;
}
catch { }
}
}
//showbehindwalls.cs
using System.Collections.Generic;
using UnityEngine;
[DisallowMultipleComponent]
public class ShowBehindWalls : MonoBehaviour
{
public Transform target;
public LayerMask hideableLayerMask = ~0;
public float maxDistance = 0f;
public bool active = true;
Camera cam;
readonly HashSet<Renderer> currentHidden = new HashSet<Renderer>();
readonly List<RaycastHit> hitBuffer = new List<RaycastHit>(32);
void Awake()
{
cam = GetComponent<Camera>();
if (cam == null) cam = Camera.main;
}
void Update()
{
if (!active || cam == null || target == null)
{
RestoreAll();
return;
}
Vector3 camPos = cam.transform.position;
Vector3 dir = (target.position - camPos);
float dist = dir.magnitude;
if (dist <= Mathf.Epsilon)
{
RestoreAll();
return;
}
dir /= dist;
float castDist = (maxDistance > 0f) ? maxDistance : dist - 0.1f;
hitBuffer.Clear();
RaycastHit[] hits = Physics.RaycastAll(camPos, dir, castDist, hideableLayerMask);
if (hits != null && hits.Length > 0)
{
for (int i = 0; i < hits.Length; i++) hitBuffer.Add(hits[i]);
}
var hitRenderers = new HashSet<Renderer>();
for (int i = 0; i < hitBuffer.Count; i++)
{
var hit = hitBuffer[i];
if (hit.collider == null) continue;
Renderer r = hit.collider.GetComponent<Renderer>()
?? hit.collider.GetComponentInParent<Renderer>()
?? hit.collider.GetComponentInChildren<Renderer>();
if (r == null) continue;
if (r.transform.IsChildOf(target)) continue;
hitRenderers.Add(r);
}
var toRestore = new List<Renderer>();
foreach (var r in currentHidden)
if (!hitRenderers.Contains(r)) toRestore.Add(r);
foreach (var r in toRestore)
{
var hideable = r.GetComponentInParent<Hideable>();
if (hideable != null) hideable.SetHidden(false);
currentHidden.Remove(r);
}
foreach (var r in hitRenderers)
{
if (currentHidden.Contains(r)) continue;
var hideable = r.GetComponentInParent<Hideable>();
if (hideable != null)
{
hideable.SetHidden(true);
currentHidden.Add(r);
}
}
}
void RestoreAll()
{
foreach (var r in currentHidden)
{
if (r == null) continue;
var hideable = r.GetComponentInParent<Hideable>();
if (hideable != null) hideable.SetHidden(false);
}
currentHidden.Clear();
}
void OnDisable() => RestoreAll();
void OnDestroy() => RestoreAll();
}