Kursach_StealthAction/Assets/Scripts/AcidProjectile.cs
2026-10-23 15:44:09 +03:00

193 lines
8.5 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using UnityEngine;
/// <summary>
/// Снаряд ядовитого био-плевка Босса. Летит к игроку, при контакте наносит прямой урон,
/// создает расширяющуюся акустическую волну эхолокации и оставляет токсичную кислотную лужу.
/// </summary>
public class AcidProjectile : MonoBehaviour
{
public float speed = 19f;
public float directDamage = 18f;
public float maxLifetime = 5f;
public bool isMainGlobule = true;
private Vector3 moveDirection;
private float lifeTimer = 0f;
private bool hasImpacted = false;
public static AcidProjectile Spawn(Vector3 startPos, Vector3 targetPos, float projSpeed = 19f, float damage = 18f, bool isMain = true, float spreadAngle = 0f)
{
GameObject go = new GameObject(isMain ? "Boss_Saliva_Globule" : "Boss_Saliva_Droplet");
go.transform.position = startPos;
Vector3 dir = (targetPos - startPos);
dir.y += 0.22f; // небольшая естественная баллистическая дуга плевка
if (spreadAngle > 0.01f)
{
float pitch = Random.Range(-spreadAngle, spreadAngle);
float yaw = Random.Range(-spreadAngle, spreadAngle);
dir = Quaternion.Euler(pitch, yaw, 0f) * dir;
}
Vector3 normDir = dir.normalized;
go.transform.rotation = Quaternion.LookRotation(normDir);
float baseScale = isMain ? 1f : 0.65f;
// 1. Формируем анатомическую вытянутую каплю слюны (а не плоскую кляксу)
// Основное каплевидное тело (вытянутое вдоль направления полета Z)
GameObject body = GameObject.CreatePrimitive(PrimitiveType.Sphere);
body.name = "Saliva_Body";
body.transform.SetParent(go.transform, false);
body.transform.localScale = new Vector3(0.08f, 0.08f, 0.34f) * baseScale;
body.transform.localPosition = Vector3.zero;
// Переднее утолщение капли слюны
GameObject head = GameObject.CreatePrimitive(PrimitiveType.Sphere);
head.name = "Saliva_Head";
head.transform.SetParent(go.transform, false);
head.transform.localScale = new Vector3(0.11f, 0.11f, 0.14f) * baseScale;
head.transform.localPosition = new Vector3(0f, 0f, 0.11f * baseScale);
// Хвостовая мелкая капелька слизи
GameObject tail = GameObject.CreatePrimitive(PrimitiveType.Sphere);
tail.name = "Saliva_Tail";
tail.transform.SetParent(go.transform, false);
tail.transform.localScale = new Vector3(0.05f, 0.05f, 0.08f) * baseScale;
tail.transform.localPosition = new Vector3(0f, 0f, -0.20f * baseScale);
Destroy(body.GetComponent<Collider>());
Destroy(head.GetComponent<Collider>());
Destroy(tail.GetComponent<Collider>());
// Органический материал токсичной слюны: влажный, глянцевый, полупрозрачный
Material salivaMat = new Material(Shader.Find("Universal Render Pipeline/Lit") ?? Shader.Find("Standard"));
salivaMat.color = new Color(0.35f, 0.95f, 0.2f, 0.85f);
salivaMat.EnableKeyword("_EMISSION");
salivaMat.SetColor("_EmissionColor", new Color(0.2f, 0.85f, 0.15f) * 1.3f);
if (salivaMat.HasProperty("_Smoothness")) salivaMat.SetFloat("_Smoothness", 0.94f);
body.GetComponent<Renderer>().material = salivaMat;
head.GetComponent<Renderer>().material = salivaMat;
tail.GetComponent<Renderer>().material = salivaMat;
// 2. След летящей слюны (TrailRenderer) — нить тягучей слизи за летящим плевком
TrailRenderer trail = go.AddComponent<TrailRenderer>();
trail.time = 0.20f;
trail.startWidth = 0.09f * baseScale;
trail.endWidth = 0.005f;
trail.minVertexDistance = 0.04f;
Material trailMat = new Material(Shader.Find("Sprites/Default") ?? Shader.Find("Universal Render Pipeline/Unlit"));
trailMat.color = new Color(0.4f, 0.95f, 0.25f, 0.7f);
trail.material = trailMat;
Gradient grad = new Gradient();
grad.SetKeys(
new GradientColorKey[] { new GradientColorKey(new Color(0.4f, 1f, 0.25f), 0f), new GradientColorKey(new Color(0.25f, 0.85f, 0.15f), 1f) },
new GradientAlphaKey[] { new GradientAlphaKey(0.75f, 0f), new GradientAlphaKey(0.0f, 1f) }
);
trail.colorGradient = grad;
// 3. Мягкая подсветка капли в полете
GameObject lightObj = new GameObject("SalivaGlow");
lightObj.transform.SetParent(go.transform, false);
Light l = lightObj.AddComponent<Light>();
l.type = LightType.Point;
l.color = new Color(0.35f, 1.0f, 0.25f);
l.intensity = isMain ? 0.9f : 0.5f;
l.range = isMain ? 2.0f : 1.2f;
// 4. Коллайдер-триггер на корневом объекте
SphereCollider col = go.AddComponent<SphereCollider>();
col.isTrigger = true;
col.radius = 0.13f * baseScale;
AcidProjectile proj = go.AddComponent<AcidProjectile>();
proj.speed = projSpeed;
proj.directDamage = damage;
proj.isMainGlobule = isMain;
proj.moveDirection = normDir;
return proj;
}
private void Update()
{
if (hasImpacted) return;
lifeTimer += Time.deltaTime;
if (lifeTimer >= maxLifetime)
{
Destroy(gameObject);
return;
}
// Перемещение снаряда вперед с естественной баллистикой
moveDirection += Vector3.down * (4.0f * Time.deltaTime);
transform.position += moveDirection.normalized * (speed * Time.deltaTime);
// Поворот по вектору движения, чтобы капля летела кончиком вперед
if (moveDirection.sqrMagnitude > 0.001f)
{
transform.rotation = Quaternion.LookRotation(moveDirection);
}
// SphereCast вперед для точной регистрации удара на высокой скорости
if (Physics.SphereCast(transform.position, 0.12f, moveDirection, out RaycastHit hit, speed * Time.deltaTime, ~0, QueryTriggerInteraction.Ignore))
{
OnHit(hit.collider, hit.point);
}
}
private void OnTriggerEnter(Collider other)
{
if (hasImpacted) return;
if (other.GetComponentInParent<TitanBossAI>() != null) return;
if (other.name.Contains("Saliva") || other.name.Contains("Acid")) return;
OnHit(other, transform.position);
}
private void OnHit(Collider hitCollider, Vector3 impactPoint)
{
if (hasImpacted) return;
hasImpacted = true;
// 1. Урон игроку при прямом попадании
PlayerHealth player = hitCollider.GetComponentInParent<PlayerHealth>();
if (player != null)
{
player.TakeDamage(directDamage);
Debug.Log($"<color=green>[Босс] Плевок слюны попал в игрока! Нанесено {directDamage} урона.</color>");
}
// 2. Волна эхолокации в месте удара (жидкость ударяется о поверхность и разлетается брызгами)
if (EchoTrigger.Instance != null && isMainGlobule)
{
Vector3 echoPos = impactPoint;
if (Physics.Raycast(impactPoint + Vector3.up * 0.5f, Vector3.down, out RaycastHit floorHit, 4f))
{
echoPos = floorHit.point + Vector3.up * 0.05f;
}
EchoTrigger.Instance.TriggerExternalWave(echoPos, 14f, 1.8f);
}
// 3. Создание органического всплеска слюны на полу
if (isMainGlobule)
{
Vector3 poolPos = impactPoint;
if (Physics.Raycast(impactPoint + Vector3.up * 0.5f, Vector3.down, out RaycastHit fHit, 5f))
{
poolPos = fHit.point;
}
AcidPool.Create(poolPos, poolLifetime: 4.5f, poolRadius: 0.85f);
}
// 4. Звук смачного шлепка слюны о поверхность
GameAudioSynthesizer.PlayAcidImpact();
Destroy(gameObject);
}
}