крутой шейдер
This commit is contained in:
parent
da648df1d9
commit
9245409fc9
@ -21,7 +21,7 @@ Material:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: EchoCloudMat
|
||||
m_Shader: {fileID: -6465566751694194690, guid: d55932c1661b84243acfb93f7ba5a4b2, type: 3}
|
||||
m_Shader: {fileID: 4800000, guid: cc58e5b86cd79a04789774a9a4b0af75, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
@ -37,6 +37,10 @@ Material:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
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}
|
||||
@ -51,23 +55,34 @@ Material:
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _CloudBandWidth: 3.2
|
||||
- _EchoOpacity1: 0
|
||||
- _EchoOpacity2: 0
|
||||
- _EchoOpacity3: 0
|
||||
- _EchoRadius1: 0
|
||||
- _EchoRadius2: 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
|
||||
- _QueueOffset: 0
|
||||
- _RingWidth: 0.08
|
||||
- _RippleFrequency: 1.5
|
||||
- _RippleStrength: 0.25
|
||||
- _WaveRadius: 0
|
||||
m_Colors:
|
||||
- _EchoColor: {r: 4, g: 3.0263731, b: 1.0490564, a: 1}
|
||||
- _EchoPosition1: {r: -24.5, g: -0.027898155, b: -4, a: 0}
|
||||
- _EchoPosition2: {r: -19.5, g: -0.027898155, b: -8, a: 0}
|
||||
- _EchoPosition3: {r: 21.5, g: -0.027898155, b: 22, a: 0}
|
||||
- _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}
|
||||
- _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}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
|
||||
255
Assets/EchoCloudShader.shader
Normal file
255
Assets/EchoCloudShader.shader
Normal 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"
|
||||
}
|
||||
9
Assets/EchoCloudShader.shader.meta
Normal file
9
Assets/EchoCloudShader.shader.meta
Normal file
@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc58e5b86cd79a04789774a9a4b0af75
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -8,7 +8,7 @@ Material:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: EchoMat
|
||||
m_Shader: {fileID: -6465566751694194690, guid: 504d814182b14b748a5afebbe6fcdb8c, type: 3}
|
||||
m_Shader: {fileID: 4800000, guid: cc58e5b86cd79a04789774a9a4b0af75, type: 3}
|
||||
m_Parent: {fileID: 0}
|
||||
m_ModifiedSerializedProperties: 0
|
||||
m_ValidKeywords: []
|
||||
@ -24,6 +24,10 @@ Material:
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _BaseMap:
|
||||
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}
|
||||
@ -38,19 +42,37 @@ Material:
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats:
|
||||
- _CloudBandWidth: 3.2
|
||||
- _EchoOpacity1: 0
|
||||
- _EchoOpacity2: 0
|
||||
- _EchoOpacity3: 0
|
||||
- _EchoRadius: 27.577322
|
||||
- _EchoRadius1: 0
|
||||
- _EchoRadius2: 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
|
||||
- _QueueOffset: 0
|
||||
- _RingWidth: 0.08
|
||||
- _RippleFrequency: 1.5
|
||||
- _RippleStrength: 0.25
|
||||
- _WaveRadius: 0
|
||||
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}
|
||||
- _EchoPosition1: {r: 0.78633124, g: 1.08, b: -10.874559, 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}
|
||||
- _WaveCenter: {r: 0, g: 0, b: 0, a: 0}
|
||||
m_BuildTextureStacks: []
|
||||
m_AllowLocking: 1
|
||||
--- !u!114 &3906604532312570773
|
||||
|
||||
@ -95,27 +95,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::BlindMutantAI
|
||||
walkSpeed: 2
|
||||
runSpeed: 5
|
||||
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}
|
||||
patrolPoints: []
|
||||
detectionRadius: 3.5
|
||||
losePlayerDistance: 14
|
||||
attackRange: 1.8
|
||||
|
||||
Binary file not shown.
@ -12,6 +12,9 @@ public class BlindMutantAI : MonoBehaviour
|
||||
|
||||
[Header("Патрулирование")]
|
||||
public Transform[] patrolPoints;
|
||||
[Tooltip("Время паузы на точке патрулирования для прислушивания")]
|
||||
public float waitTimeAtPoint = 1.5f;
|
||||
private float waitTimer = 0f;
|
||||
private int currentPatrolIndex;
|
||||
private bool isInvestigating = false;
|
||||
|
||||
@ -30,7 +33,20 @@ public class BlindMutantAI : MonoBehaviour
|
||||
void Start()
|
||||
{
|
||||
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>();
|
||||
|
||||
// Автоматически находим игрока на сцене
|
||||
@ -40,9 +56,36 @@ public class BlindMutantAI : MonoBehaviour
|
||||
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()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private void HandlePlayerChaseAndAttack()
|
||||
{
|
||||
if (agent == null || !agent.isOnNavMesh) return;
|
||||
|
||||
if (targetPlayerHealth != null && targetPlayerHealth.IsDead)
|
||||
{
|
||||
LosePlayerTarget();
|
||||
@ -138,26 +183,34 @@ public class BlindMutantAI : MonoBehaviour
|
||||
|
||||
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)
|
||||
{
|
||||
isInvestigating = false;
|
||||
agent.speed = walkSpeed;
|
||||
if (patrolPoints != null && patrolPoints.Length > 0)
|
||||
{
|
||||
GoToNextPatrolPoint();
|
||||
}
|
||||
waitTimer = waitTimeAtPoint;
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (agent == null || !agent.isOnNavMesh) return;
|
||||
|
||||
targetPlayer = playerTransform;
|
||||
if (targetPlayerHealth == null)
|
||||
{
|
||||
@ -165,6 +218,7 @@ public class BlindMutantAI : MonoBehaviour
|
||||
}
|
||||
|
||||
isInvestigating = false;
|
||||
waitTimer = 0f;
|
||||
agent.isStopped = false;
|
||||
agent.speed = runSpeed;
|
||||
agent.SetDestination(targetPlayer.position);
|
||||
@ -174,22 +228,55 @@ public class BlindMutantAI : MonoBehaviour
|
||||
private void LosePlayerTarget()
|
||||
{
|
||||
targetPlayer = null;
|
||||
agent.isStopped = false;
|
||||
agent.speed = walkSpeed;
|
||||
isInvestigating = false;
|
||||
|
||||
if (patrolPoints != null && patrolPoints.Length > 0)
|
||||
if (agent != null && agent.isOnNavMesh)
|
||||
{
|
||||
GoToNextPatrolPoint();
|
||||
agent.isStopped = false;
|
||||
agent.speed = walkSpeed;
|
||||
}
|
||||
isInvestigating = false;
|
||||
waitTimer = 0f;
|
||||
|
||||
GoToNextPatrolPoint();
|
||||
Debug.Log("Мутант потерял игрока и возвращается к патрулированию.");
|
||||
}
|
||||
|
||||
private void GoToNextPatrolPoint()
|
||||
{
|
||||
if (patrolPoints == null || patrolPoints.Length == 0) return;
|
||||
agent.destination = patrolPoints[currentPatrolIndex].position;
|
||||
currentPatrolIndex = (currentPatrolIndex + 1) % patrolPoints.Length;
|
||||
if (agent == null || !agent.isOnNavMesh) return;
|
||||
|
||||
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)
|
||||
@ -200,7 +287,10 @@ public class BlindMutantAI : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
if (agent == null || !agent.isOnNavMesh) return;
|
||||
|
||||
isInvestigating = true;
|
||||
waitTimer = 0f;
|
||||
agent.isStopped = false;
|
||||
agent.speed = runSpeed;
|
||||
agent.SetDestination(soundPosition);
|
||||
|
||||
@ -71,21 +71,31 @@ public class EchoTrigger : MonoBehaviour
|
||||
if (waveActive[i])
|
||||
{
|
||||
waveRadii[i] += waveSpeed * Time.deltaTime;
|
||||
echoMaterial.SetFloat("_EchoRadius" + (i + 1), waveRadii[i]);
|
||||
|
||||
// ВЫЧИСЛЯЕМ ПРОЗРАЧНОСТЬ с учетом стартовой яркости
|
||||
// Умножаем на waveIntensities[i], чтобы бег был ярче, а стелс тусклее
|
||||
float opacity = (1f - (waveRadii[i] / waveMaxRadii[i])) * waveIntensities[i];
|
||||
|
||||
// Mathf.Max не дает уйти в минус, но РАЗРЕШАЕТ быть больше 1 (для HDR свечения)
|
||||
opacity = Mathf.Max(0f, opacity);
|
||||
float currentRadius = waveRadii[i];
|
||||
float maxRadius = waveMaxRadii[i];
|
||||
float progress = Mathf.Clamp01(currentRadius / maxRadius);
|
||||
|
||||
// Плавное появление (Fade-in): в первые 18% пути волна мягко разгорается (без резкой вспышки)
|
||||
float fadeIn = Mathf.SmoothStep(0f, 1f, progress / 0.18f);
|
||||
// Плавное рассеивание (Fade-out): к концу облако плавно растворяется в темноте
|
||||
float fadeOut = Mathf.Pow(1f - progress, 1.4f);
|
||||
|
||||
float opacity = (fadeIn * fadeOut) * waveIntensities[i];
|
||||
opacity = Mathf.Max(0f, opacity);
|
||||
|
||||
echoMaterial.SetFloat("_EchoRadius" + (i + 1), currentRadius);
|
||||
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;
|
||||
echoMaterial.SetFloat("_EchoRadius" + (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;
|
||||
waveActive[waveIndex] = true;
|
||||
|
||||
echoMaterial.SetFloat("_EchoOpacity" + (waveIndex + 1), targetIntensity);
|
||||
// Начинаем плавно с 0, чтобы разгореться через fadeIn
|
||||
echoMaterial.SetFloat("_EchoOpacity" + (waveIndex + 1), 0f);
|
||||
echoMaterial.SetVector("_EchoPosition" + (waveIndex + 1), position);
|
||||
Shader.SetGlobalFloat("_EchoOpacity" + (waveIndex + 1), 0f);
|
||||
Shader.SetGlobalVector("_EchoPosition" + (waveIndex + 1), position);
|
||||
}
|
||||
}
|
||||
@ -908,7 +908,10 @@ public static class LaboratoryLevelGenerator
|
||||
var ai = enemy.GetComponent<BlindMutantAI>();
|
||||
if (ai != null)
|
||||
{
|
||||
Undo.RecordObject(ai, "Setup Patrol Points");
|
||||
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>");
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user