крутой шейдер

This commit is contained in:
Valentina 2026-10-21 13:53:17 +03:00
parent da648df1d9
commit 9245409fc9
9 changed files with 446 additions and 59 deletions

View File

@ -21,7 +21,7 @@ Material:
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: EchoCloudMat m_Name: EchoCloudMat
m_Shader: {fileID: -6465566751694194690, guid: d55932c1661b84243acfb93f7ba5a4b2, type: 3} m_Shader: {fileID: 4800000, guid: cc58e5b86cd79a04789774a9a4b0af75, type: 3}
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: [] m_ValidKeywords: []
@ -37,6 +37,10 @@ Material:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
m_TexEnvs: m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps: - unity_Lightmaps:
m_Texture: {fileID: 0} m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1} m_Scale: {x: 1, y: 1}
@ -51,23 +55,34 @@ Material:
m_Offset: {x: 0, y: 0} m_Offset: {x: 0, y: 0}
m_Ints: [] m_Ints: []
m_Floats: m_Floats:
- _CloudBandWidth: 3.2
- _EchoOpacity1: 0 - _EchoOpacity1: 0
- _EchoOpacity2: 0 - _EchoOpacity2: 0
- _EchoOpacity3: 0 - _EchoOpacity3: 0
- _EchoRadius1: 0 - _EchoRadius1: 0
- _EchoRadius2: 0 - _EchoRadius2: 0
- _EchoRadius3: 0 - _EchoRadius3: 0
- _FresnelPower: 2.5
- _FresnelStrength: 0.4
- _LeadingEdgeSoftness: 1.2
- _LineDensity: 3 - _LineDensity: 3
- _LineThickness: 0.05 - _LineThickness: 0.05
- _NoiseDistortion: 1.3
- _NoiseScale: 0.35
- _NoiseSpeed: 0.2
- _QueueControl: 0 - _QueueControl: 0
- _QueueOffset: 0 - _QueueOffset: 0
- _RingWidth: 0.08 - _RingWidth: 0.08
- _RippleFrequency: 1.5
- _RippleStrength: 0.25
- _WaveRadius: 0 - _WaveRadius: 0
m_Colors: m_Colors:
- _EchoColor: {r: 4, g: 3.0263731, b: 1.0490564, a: 1} - _BaseColor: {r: 0.015, g: 0.015, b: 0.02, a: 1}
- _EchoPosition1: {r: -24.5, g: -0.027898155, b: -4, a: 0} - _EchoColor: {r: 4, g: 3.026, b: 1.049, a: 1}
- _EchoPosition2: {r: -19.5, g: -0.027898155, b: -8, a: 0} - _EchoCoreColor: {r: 7.5, g: 5.5, b: 2.2, a: 1}
- _EchoPosition3: {r: 21.5, g: -0.027898155, b: 22, a: 0} - _EchoPosition1: {r: 1.5618706, g: 1.0799999, b: -34.510273, a: 0}
- _EchoPosition2: {r: -1.1804235, g: 1.0799999, b: -35.782673, a: 0}
- _EchoPosition3: {r: -0.93470556, g: 1.0799999, b: -34.72166, a: 0}
- _WaveCenter: {r: 0, g: 0, b: 0, a: 0} - _WaveCenter: {r: 0, g: 0, b: 0, a: 0}
m_BuildTextureStacks: [] m_BuildTextureStacks: []
m_AllowLocking: 1 m_AllowLocking: 1

View File

@ -0,0 +1,255 @@
Shader "Custom/EchoCloudShader"
{
Properties
{
[Header(Base Appearance)]
_BaseColor("Base Ambient Color", Color) = (0.015, 0.015, 0.02, 1.0)
_BaseMap("Base Map (Optional)", 2D) = "white" {}
[Header(Echo Cloud Visuals)]
[HDR] _EchoColor("Echo Mist Color", Color) = (4.0, 3.026, 1.049, 1.0)
[HDR] _EchoCoreColor("Echo Core Bloom", Color) = (7.5, 5.5, 2.2, 1.0)
_CloudBandWidth("Cloud Thickness / Tail (m)", Range(0.5, 8.0)) = 3.2
_LeadingEdgeSoftness("Leading Edge Softness", Range(0.1, 3.0)) = 1.2
[Header(Cloud Noise and Billows)]
_NoiseScale("Cloud Noise Scale", Range(0.05, 1.5)) = 0.35
_NoiseDistortion("Cloud Billow Distortion", Range(0.0, 3.0)) = 1.3
_NoiseSpeed("Cloud Drift Speed", Range(0.0, 2.0)) = 0.2
[Header(Acoustic Ripples and Edge Glow)]
_RippleFrequency("Acoustic Ripple Frequency", Range(0.1, 5.0)) = 1.5
_RippleStrength("Acoustic Ripple Strength", Range(0.0, 1.0)) = 0.25
_FresnelPower("Edge Rim Power", Range(0.5, 5.0)) = 2.5
_FresnelStrength("Edge Rim Strength", Range(0.0, 2.0)) = 0.4
[Header(Wave Inputs from Script)]
_EchoPosition1("Echo Position 1", Vector) = (0, 0, 0, 0)
_EchoPosition2("Echo Position 2", Vector) = (0, 0, 0, 0)
_EchoPosition3("Echo Position 3", Vector) = (0, 0, 0, 0)
_EchoRadius1("Echo Radius 1", Float) = 0
_EchoRadius2("Echo Radius 2", Float) = 0
_EchoRadius3("Echo Radius 3", Float) = 0
_EchoOpacity1("Echo Opacity 1", Float) = 0
_EchoOpacity2("Echo Opacity 2", Float) = 0
_EchoOpacity3("Echo Opacity 3", Float) = 0
// Legacy compatibility properties
[HideInInspector] _RingWidth("Ring Width", Float) = 0.08
[HideInInspector] _LineDensity("Line Density", Float) = 3.0
[HideInInspector] _LineThickness("Line Thickness", Float) = 0.05
[HideInInspector] _WaveCenter("Wave Center", Vector) = (0, 0, 0, 0)
[HideInInspector] _WaveRadius("Wave Radius", Float) = 0
[HideInInspector] _QueueOffset("Queue Offset", Float) = 0
[HideInInspector] _QueueControl("Queue Control", Float) = 0
}
SubShader
{
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline"
"Queue" = "Geometry"
}
LOD 200
Pass
{
Name "ForwardLit"
Tags { "LightMode" = "UniversalForward" }
ZWrite On
ZTest LEqual
Cull Back
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float3 positionWS : TEXCOORD0;
float3 normalWS : TEXCOORD1;
float2 uv : TEXCOORD2;
float fogFactor : TEXCOORD3;
};
TEXTURE2D(_BaseMap);
SAMPLER(sampler_BaseMap);
CBUFFER_START(UnityPerMaterial)
half4 _BaseColor;
half4 _EchoColor;
half4 _EchoCoreColor;
float _CloudBandWidth;
float _LeadingEdgeSoftness;
float _NoiseScale;
float _NoiseDistortion;
float _NoiseSpeed;
float _RippleFrequency;
float _RippleStrength;
float _FresnelPower;
float _FresnelStrength;
float4 _EchoPosition1;
float4 _EchoPosition2;
float4 _EchoPosition3;
float _EchoRadius1;
float _EchoRadius2;
float _EchoRadius3;
float _EchoOpacity1;
float _EchoOpacity2;
float _EchoOpacity3;
float4 _BaseMap_ST;
float _RingWidth;
float _LineDensity;
float _LineThickness;
float4 _WaveCenter;
float _WaveRadius;
float _QueueOffset;
float _QueueControl;
CBUFFER_END
// 3D Hash and Value Noise
float3 Hash33(float3 p)
{
p = float3(dot(p, float3(127.1, 311.7, 74.7)),
dot(p, float3(269.5, 183.3, 246.1)),
dot(p, float3(113.5, 271.9, 124.6)));
return frac(sin(p) * 43758.5453123);
}
float ValueNoise3D(float3 p)
{
float3 i = floor(p);
float3 f = frac(p);
float3 u = f * f * (3.0 - 2.0 * f);
float n000 = dot(Hash33(i + float3(0,0,0)) - 0.5, f - float3(0,0,0));
float n100 = dot(Hash33(i + float3(1,0,0)) - 0.5, f - float3(1,0,0));
float n010 = dot(Hash33(i + float3(0,1,0)) - 0.5, f - float3(0,1,0));
float n110 = dot(Hash33(i + float3(1,1,0)) - 0.5, f - float3(1,1,0));
float n001 = dot(Hash33(i + float3(0,0,1)) - 0.5, f - float3(0,0,1));
float n101 = dot(Hash33(i + float3(1,0,1)) - 0.5, f - float3(1,0,1));
float n011 = dot(Hash33(i + float3(0,1,1)) - 0.5, f - float3(0,1,1));
float n111 = dot(Hash33(i + float3(1,1,1)) - 0.5, f - float3(1,1,1));
float nx00 = lerp(n000, n100, u.x);
float nx10 = lerp(n010, n110, u.x);
float nx01 = lerp(n001, n101, u.x);
float nx11 = lerp(n011, n111, u.x);
float nxy0 = lerp(nx00, nx10, u.y);
float nxy1 = lerp(nx01, nx11, u.y);
return lerp(nxy0, nxy1, u.z) + 0.5;
}
float GetCloudNoise(float3 worldPos)
{
float3 p1 = worldPos * _NoiseScale + float3(0, _Time.y * _NoiseSpeed, 0);
float n1 = ValueNoise3D(p1);
float3 p2 = worldPos * (_NoiseScale * 2.2) - float3(0, _Time.y * (_NoiseSpeed * 1.4), 0);
float n2 = ValueNoise3D(p2);
return n1 * 0.65 + n2 * 0.35;
}
float CalculateSingleWave(float3 worldPos, float3 normalWS, float3 viewDirWS, float3 waveCenter, float waveRadius, float waveOpacity, float noiseVal)
{
if (waveOpacity <= 0.001 || waveRadius <= 0.01)
return 0.0;
float rawDist = distance(worldPos, waveCenter);
// Organic cloud boundary distortion via 3D noise
float distortedDist = rawDist + (noiseVal - 0.5) * _NoiseDistortion;
// Soft leading edge (smoothly fades into darkness ahead)
float leadingEdge = smoothstep(waveRadius + 0.2, waveRadius - _LeadingEdgeSoftness, distortedDist);
// Soft trailing cloud body (billowy tail behind the wavefront)
float trailingEdge = smoothstep(waveRadius - _CloudBandWidth, waveRadius - 0.2, distortedDist);
// Combined cloud puff shape
float cloudDensity = leadingEdge * trailingEdge;
// Subtle acoustic harmonic ripples inside the cloud
float ripple = sin((rawDist - waveRadius) * _RippleFrequency) * 0.5 + 0.5;
cloudDensity *= lerp(1.0, ripple, _RippleStrength);
// Subtle edge rim glow on surfaces facing away (gives 3D depth to rooms)
float NdotV = saturate(dot(normalWS, viewDirWS));
float rim = pow(1.0 - NdotV, _FresnelPower) * _FresnelStrength;
cloudDensity += cloudDensity * rim;
return saturate(cloudDensity) * waveOpacity;
}
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
VertexPositionInputs vertexInputs = GetVertexPositionInputs(input.positionOS.xyz);
VertexNormalInputs normalInputs = GetVertexNormalInputs(input.normalOS);
output.positionCS = vertexInputs.positionCS;
output.positionWS = vertexInputs.positionWS;
output.normalWS = normalInputs.normalWS;
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
output.fogFactor = ComputeFogFactor(vertexInputs.positionCS.z);
return output;
}
half4 frag(Varyings input) : SV_Target
{
float3 worldPos = input.positionWS;
float3 normalWS = normalize(input.normalWS);
float3 viewDirWS = normalize(GetCameraPositionWS() - worldPos);
// Base ambient appearance (deep dark atmospheric tone)
half4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
half4 baseCol = texColor * _BaseColor;
// 3D procedural noise
float noiseVal = GetCloudNoise(worldPos);
// Evaluate all 3 simultaneous echo waves
float w1 = CalculateSingleWave(worldPos, normalWS, viewDirWS, _EchoPosition1.xyz, _EchoRadius1, _EchoOpacity1, noiseVal);
float w2 = CalculateSingleWave(worldPos, normalWS, viewDirWS, _EchoPosition2.xyz, _EchoRadius2, _EchoOpacity2, noiseVal);
float w3 = CalculateSingleWave(worldPos, normalWS, viewDirWS, _EchoPosition3.xyz, _EchoRadius3, _EchoOpacity3, noiseVal);
float totalWave = saturate(w1 + w2 + w3);
// Color gradient: soft outer mist (_EchoColor) to glowing core (_EchoCoreColor)
half4 mistColor = _EchoColor * totalWave;
half4 coreBloom = _EchoCoreColor * pow(totalWave, 2.2);
half4 finalColor = baseCol + mistColor + coreBloom;
// Apply scene fog
finalColor.rgb = MixFog(finalColor.rgb, input.fogFactor);
return finalColor;
}
ENDHLSL
}
UsePass "Universal Render Pipeline/Lit/ShadowCaster"
UsePass "Universal Render Pipeline/Lit/DepthOnly"
}
FallBack "Hidden/Universal Render Pipeline/FallbackError"
}

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: cc58e5b86cd79a04789774a9a4b0af75
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:

View File

@ -8,7 +8,7 @@ Material:
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_Name: EchoMat m_Name: EchoMat
m_Shader: {fileID: -6465566751694194690, guid: 504d814182b14b748a5afebbe6fcdb8c, type: 3} m_Shader: {fileID: 4800000, guid: cc58e5b86cd79a04789774a9a4b0af75, type: 3}
m_Parent: {fileID: 0} m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0 m_ModifiedSerializedProperties: 0
m_ValidKeywords: [] m_ValidKeywords: []
@ -24,6 +24,10 @@ Material:
m_SavedProperties: m_SavedProperties:
serializedVersion: 3 serializedVersion: 3
m_TexEnvs: m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps: - unity_Lightmaps:
m_Texture: {fileID: 0} m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1} m_Scale: {x: 1, y: 1}
@ -38,19 +42,37 @@ Material:
m_Offset: {x: 0, y: 0} m_Offset: {x: 0, y: 0}
m_Ints: [] m_Ints: []
m_Floats: m_Floats:
- _CloudBandWidth: 3.2
- _EchoOpacity1: 0
- _EchoOpacity2: 0
- _EchoOpacity3: 0
- _EchoRadius: 27.577322 - _EchoRadius: 27.577322
- _EchoRadius1: 0 - _EchoRadius1: 0
- _EchoRadius2: 0 - _EchoRadius2: 0
- _EchoRadius3: 0 - _EchoRadius3: 0
- _FresnelPower: 2.5
- _FresnelStrength: 0.4
- _LeadingEdgeSoftness: 1.2
- _LineDensity: 3
- _LineThickness: 0.05
- _NoiseDistortion: 1.3
- _NoiseScale: 0.35
- _NoiseSpeed: 0.2
- _QueueControl: 0 - _QueueControl: 0
- _QueueOffset: 0 - _QueueOffset: 0
- _RingWidth: 0.08 - _RingWidth: 0.08
- _RippleFrequency: 1.5
- _RippleStrength: 0.25
- _WaveRadius: 0
m_Colors: m_Colors:
- _EchoColor: {r: 19.265432, g: 10.948601, b: 3.0170376, a: 1} - _BaseColor: {r: 0.015, g: 0.015, b: 0.02, a: 1}
- _EchoColor: {r: 4, g: 3.026, b: 1.049, a: 1}
- _EchoCoreColor: {r: 7.5, g: 5.5, b: 2.2, a: 1}
- _EchoPosition: {r: -4.3227067, g: 1.08, b: -10.807251, a: 0} - _EchoPosition: {r: -4.3227067, g: 1.08, b: -10.807251, a: 0}
- _EchoPosition1: {r: 0.78633124, g: 1.08, b: -10.874559, a: 0} - _EchoPosition1: {r: 0.78633124, g: 1.08, b: -10.874559, a: 0}
- _EchoPosition2: {r: 0.7576918, g: 1.08, b: -11.912178, a: 0} - _EchoPosition2: {r: 0.7576918, g: 1.08, b: -11.912178, a: 0}
- _EchoPosition3: {r: 0.95730513, g: 1.08, b: -16.5998, a: 0} - _EchoPosition3: {r: 0.95730513, g: 1.08, b: -16.5998, a: 0}
- _WaveCenter: {r: 0, g: 0, b: 0, a: 0}
m_BuildTextureStacks: [] m_BuildTextureStacks: []
m_AllowLocking: 1 m_AllowLocking: 1
--- !u!114 &3906604532312570773 --- !u!114 &3906604532312570773

View File

@ -95,27 +95,7 @@ MonoBehaviour:
m_EditorClassIdentifier: Assembly-CSharp::BlindMutantAI m_EditorClassIdentifier: Assembly-CSharp::BlindMutantAI
walkSpeed: 2 walkSpeed: 2
runSpeed: 5 runSpeed: 5
patrolPoints: patrolPoints: []
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
- {fileID: 0}
detectionRadius: 3.5 detectionRadius: 3.5
losePlayerDistance: 14 losePlayerDistance: 14
attackRange: 1.8 attackRange: 1.8

Binary file not shown.

View File

@ -12,6 +12,9 @@ public class BlindMutantAI : MonoBehaviour
[Header("Патрулирование")] [Header("Патрулирование")]
public Transform[] patrolPoints; public Transform[] patrolPoints;
[Tooltip("Время паузы на точке патрулирования для прислушивания")]
public float waitTimeAtPoint = 1.5f;
private float waitTimer = 0f;
private int currentPatrolIndex; private int currentPatrolIndex;
private bool isInvestigating = false; private bool isInvestigating = false;
@ -30,7 +33,20 @@ public class BlindMutantAI : MonoBehaviour
void Start() void Start()
{ {
agent = GetComponent<NavMeshAgent>(); agent = GetComponent<NavMeshAgent>();
agent.speed = walkSpeed; if (agent != null)
{
agent.speed = walkSpeed;
// Если агент чуть выше пола или не на сетке, привязываем его к ближайшей точке NavMesh
if (!agent.isOnNavMesh)
{
if (NavMesh.SamplePosition(transform.position, out NavMeshHit hit, 5.0f, NavMesh.AllAreas))
{
agent.Warp(hit.position);
}
}
}
animator = GetComponentInChildren<Animator>(); animator = GetComponentInChildren<Animator>();
// Автоматически находим игрока на сцене // Автоматически находим игрока на сцене
@ -40,9 +56,36 @@ public class BlindMutantAI : MonoBehaviour
targetPlayerHealth = playerObj; targetPlayerHealth = playerObj;
} }
if (patrolPoints != null && patrolPoints.Length > 0) // Если точки патрулирования не заданы или массив состоит из null, ищем PatrolWaypoints на сцене
if (IsPatrolArrayEmptyOrNull())
{ {
GoToNextPatrolPoint(); AutoAssignPatrolWaypoints();
}
GoToNextPatrolPoint();
}
private bool IsPatrolArrayEmptyOrNull()
{
if (patrolPoints == null || patrolPoints.Length == 0) return true;
for (int i = 0; i < patrolPoints.Length; i++)
{
if (patrolPoints[i] != null) return false;
}
return true;
}
private void AutoAssignPatrolWaypoints()
{
var patrolRoot = GameObject.Find("PatrolWaypoints");
if (patrolRoot != null && patrolRoot.transform.childCount > 0)
{
patrolPoints = new Transform[patrolRoot.transform.childCount];
for (int i = 0; i < patrolRoot.transform.childCount; i++)
{
patrolPoints[i] = patrolRoot.transform.GetChild(i);
}
Debug.Log($"<color=cyan>[BlindMutantAI] Автоматически обнаружено {patrolPoints.Length} точек патрулирования в объекте 'PatrolWaypoints'.</color>");
} }
} }
@ -67,12 +110,14 @@ public class BlindMutantAI : MonoBehaviour
private void UpdateAnimator() private void UpdateAnimator()
{ {
if (animator == null) return; if (animator == null) return;
float currentSpeed = agent != null && agent.enabled ? agent.velocity.magnitude : 0f; float currentSpeed = agent != null && agent.enabled && agent.isOnNavMesh ? agent.velocity.magnitude : 0f;
animator.SetFloat("Speed", currentSpeed); animator.SetFloat("Speed", currentSpeed);
} }
private void HandlePlayerChaseAndAttack() private void HandlePlayerChaseAndAttack()
{ {
if (agent == null || !agent.isOnNavMesh) return;
if (targetPlayerHealth != null && targetPlayerHealth.IsDead) if (targetPlayerHealth != null && targetPlayerHealth.IsDead)
{ {
LosePlayerTarget(); LosePlayerTarget();
@ -138,26 +183,34 @@ public class BlindMutantAI : MonoBehaviour
private void HandlePatrolAndInvestigation() private void HandlePatrolAndInvestigation()
{ {
if (!agent.pathPending && agent.remainingDistance < 0.5f) if (agent == null || !agent.isOnNavMesh) return;
if (!agent.pathPending && agent.remainingDistance < 0.6f)
{ {
if (isInvestigating) if (isInvestigating)
{ {
isInvestigating = false; isInvestigating = false;
agent.speed = walkSpeed; agent.speed = walkSpeed;
if (patrolPoints != null && patrolPoints.Length > 0) waitTimer = waitTimeAtPoint;
{
GoToNextPatrolPoint();
}
} }
else if (patrolPoints != null && patrolPoints.Length > 0)
if (waitTimer > 0f)
{ {
GoToNextPatrolPoint(); waitTimer -= Time.deltaTime;
agent.isStopped = true;
return;
} }
agent.isStopped = false;
waitTimer = waitTimeAtPoint;
GoToNextPatrolPoint();
} }
} }
private void EngagePlayer(Transform playerTransform) private void EngagePlayer(Transform playerTransform)
{ {
if (agent == null || !agent.isOnNavMesh) return;
targetPlayer = playerTransform; targetPlayer = playerTransform;
if (targetPlayerHealth == null) if (targetPlayerHealth == null)
{ {
@ -165,6 +218,7 @@ public class BlindMutantAI : MonoBehaviour
} }
isInvestigating = false; isInvestigating = false;
waitTimer = 0f;
agent.isStopped = false; agent.isStopped = false;
agent.speed = runSpeed; agent.speed = runSpeed;
agent.SetDestination(targetPlayer.position); agent.SetDestination(targetPlayer.position);
@ -174,22 +228,55 @@ public class BlindMutantAI : MonoBehaviour
private void LosePlayerTarget() private void LosePlayerTarget()
{ {
targetPlayer = null; targetPlayer = null;
agent.isStopped = false; if (agent != null && agent.isOnNavMesh)
agent.speed = walkSpeed;
isInvestigating = false;
if (patrolPoints != null && patrolPoints.Length > 0)
{ {
GoToNextPatrolPoint(); agent.isStopped = false;
agent.speed = walkSpeed;
} }
isInvestigating = false;
waitTimer = 0f;
GoToNextPatrolPoint();
Debug.Log("Мутант потерял игрока и возвращается к патрулированию."); Debug.Log("Мутант потерял игрока и возвращается к патрулированию.");
} }
private void GoToNextPatrolPoint() private void GoToNextPatrolPoint()
{ {
if (patrolPoints == null || patrolPoints.Length == 0) return; if (agent == null || !agent.isOnNavMesh) return;
agent.destination = patrolPoints[currentPatrolIndex].position;
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length; if (patrolPoints != null && patrolPoints.Length > 0)
{
for (int attempts = 0; attempts < patrolPoints.Length; attempts++)
{
var wp = patrolPoints[currentPatrolIndex];
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length;
if (wp != null)
{
agent.isStopped = false;
agent.speed = walkSpeed;
agent.SetDestination(wp.position);
return;
}
}
}
// Если точек нет вообще — свободное блуждание по комплексу
WanderRandomly();
}
private void WanderRandomly()
{
if (agent == null || !agent.isOnNavMesh) return;
Vector3 randomDir = Random.insideUnitSphere * 15f;
randomDir += transform.position;
if (NavMesh.SamplePosition(randomDir, out NavMeshHit hit, 15f, NavMesh.AllAreas))
{
agent.isStopped = false;
agent.speed = walkSpeed;
agent.SetDestination(hit.position);
}
} }
public void HearSound(Vector3 soundPosition) public void HearSound(Vector3 soundPosition)
@ -200,7 +287,10 @@ public class BlindMutantAI : MonoBehaviour
return; return;
} }
if (agent == null || !agent.isOnNavMesh) return;
isInvestigating = true; isInvestigating = true;
waitTimer = 0f;
agent.isStopped = false; agent.isStopped = false;
agent.speed = runSpeed; agent.speed = runSpeed;
agent.SetDestination(soundPosition); agent.SetDestination(soundPosition);

View File

@ -71,21 +71,31 @@ public class EchoTrigger : MonoBehaviour
if (waveActive[i]) if (waveActive[i])
{ {
waveRadii[i] += waveSpeed * Time.deltaTime; waveRadii[i] += waveSpeed * Time.deltaTime;
echoMaterial.SetFloat("_EchoRadius" + (i + 1), waveRadii[i]); float currentRadius = waveRadii[i];
float maxRadius = waveMaxRadii[i];
float progress = Mathf.Clamp01(currentRadius / maxRadius);
// ВЫЧИСЛЯЕМ ПРОЗРАЧНОСТЬ с учетом стартовой яркости // Плавное появление (Fade-in): в первые 18% пути волна мягко разгорается (без резкой вспышки)
// Умножаем на waveIntensities[i], чтобы бег был ярче, а стелс тусклее float fadeIn = Mathf.SmoothStep(0f, 1f, progress / 0.18f);
float opacity = (1f - (waveRadii[i] / waveMaxRadii[i])) * waveIntensities[i]; // Плавное рассеивание (Fade-out): к концу облако плавно растворяется в темноте
float fadeOut = Mathf.Pow(1f - progress, 1.4f);
// Mathf.Max не дает уйти в минус, но РАЗРЕШАЕТ быть больше 1 (для HDR свечения) float opacity = (fadeIn * fadeOut) * waveIntensities[i];
opacity = Mathf.Max(0f, opacity); opacity = Mathf.Max(0f, opacity);
echoMaterial.SetFloat("_EchoRadius" + (i + 1), currentRadius);
echoMaterial.SetFloat("_EchoOpacity" + (i + 1), opacity); echoMaterial.SetFloat("_EchoOpacity" + (i + 1), opacity);
if (waveRadii[i] > waveMaxRadii[i]) Shader.SetGlobalFloat("_EchoRadius" + (i + 1), currentRadius);
Shader.SetGlobalFloat("_EchoOpacity" + (i + 1), opacity);
if (currentRadius >= maxRadius)
{ {
waveActive[i] = false; waveActive[i] = false;
echoMaterial.SetFloat("_EchoRadius" + (i + 1), 0f); echoMaterial.SetFloat("_EchoRadius" + (i + 1), 0f);
echoMaterial.SetFloat("_EchoOpacity" + (i + 1), 0f); echoMaterial.SetFloat("_EchoOpacity" + (i + 1), 0f);
Shader.SetGlobalFloat("_EchoRadius" + (i + 1), 0f);
Shader.SetGlobalFloat("_EchoOpacity" + (i + 1), 0f);
} }
} }
} }
@ -146,7 +156,10 @@ public class EchoTrigger : MonoBehaviour
waveRadii[waveIndex] = 0f; waveRadii[waveIndex] = 0f;
waveActive[waveIndex] = true; waveActive[waveIndex] = true;
echoMaterial.SetFloat("_EchoOpacity" + (waveIndex + 1), targetIntensity); // Начинаем плавно с 0, чтобы разгореться через fadeIn
echoMaterial.SetFloat("_EchoOpacity" + (waveIndex + 1), 0f);
echoMaterial.SetVector("_EchoPosition" + (waveIndex + 1), position); echoMaterial.SetVector("_EchoPosition" + (waveIndex + 1), position);
Shader.SetGlobalFloat("_EchoOpacity" + (waveIndex + 1), 0f);
Shader.SetGlobalVector("_EchoPosition" + (waveIndex + 1), position);
} }
} }

View File

@ -908,7 +908,10 @@ public static class LaboratoryLevelGenerator
var ai = enemy.GetComponent<BlindMutantAI>(); var ai = enemy.GetComponent<BlindMutantAI>();
if (ai != null) if (ai != null)
{ {
Undo.RecordObject(ai, "Setup Patrol Points");
ai.patrolPoints = transforms; ai.patrolPoints = transforms;
EditorUtility.SetDirty(ai);
EditorUtility.SetDirty(enemy);
Debug.Log($"<color=green>Configured {transforms.Length} patrol points for SkinnyOrc BlindMutantAI in South Concourse (0, 0.08, -28)!</color>"); Debug.Log($"<color=green>Configured {transforms.Length} patrol points for SkinnyOrc BlindMutantAI in South Concourse (0, 0.08, -28)!</color>");
} }
} }