Danro/Assets/Scripts/FX/MvpVFXUtility.cs
Danil Iarosh 53afa5498e
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Fix player bouncing off corners and align collider
- Исправлено поведение игрока при падении с высоты и разворотах (устранен сильный отскок от углов)
- Центрирован PolygonCollider2D по оси X на префабе character_defeat_4.prefab (m_Offset.x установлен в 0)
- Упрощена форма PolygonCollider2D до симметричного выпуклого шестиугольника
- Сохранен бэкап старого префаба игрока в Player_Old.prefab
2026-07-16 15:39:43 +03:00

304 lines
11 KiB
C#

using System.Collections.Generic;
using RR.Game2D.Behaviour;
using UnityEngine;
using UnityEngine.VFX;
namespace RR.Game2D.FX
{
public static class MvpVFXUtility
{
private static readonly Dictionary<string, VisualEffectAsset> LoadedAssets = new();
private static readonly string[] ColorPropertyNames =
{
"Color",
"TintColor",
"BaseColor",
"_Color",
"_BaseColor"
};
private static readonly string[] TexturePropertyNames =
{
"MainTexture",
"mainTexture",
"_MainTex",
"_BaseMap",
"_BaseColorMap"
};
private static readonly string[] GradientPropertyNames =
{
"ColorOverLife",
"colorOverLife",
"Color",
"Gradient"
};
private static readonly string[] FloatPropertyNames =
{
"ParticleCount",
"particleCount",
"Count",
"count"
};
private static readonly string[] AnimationCurvePropertyNames =
{
"SizeOverLife",
"sizeOverLife",
"Size",
"size"
};
private static readonly string[] ScalePropertyNames =
{
"Scale",
"scale",
"BaseScale",
"baseScale"
};
public static VisualEffectAsset LoadResourceAsset(string resourcePath)
{
if (string.IsNullOrWhiteSpace(resourcePath)) return null;
if (LoadedAssets.TryGetValue(resourcePath, out VisualEffectAsset cached))
return cached;
VisualEffectAsset asset = Resources.Load<VisualEffectAsset>(resourcePath);
LoadedAssets[resourcePath] = asset;
return asset;
}
public static void Spawn(
VisualEffectAsset asset,
string fallbackResourcePath,
Vector3 position,
float lifetime = 1f)
{
Spawn(asset, fallbackResourcePath, position, lifetime, null);
}
public static GameObject Spawn(
VisualEffectAsset asset,
string fallbackResourcePath,
Vector3 position,
float lifetime,
MvpVFXSpawnSettings settings)
{
VisualEffectAsset resolvedAsset = asset ? asset : LoadResourceAsset(fallbackResourcePath);
if (!resolvedAsset || VFXPool.Instance == null) return null;
int instanceCount = Mathf.Max(1, settings?.instanceCount ?? 1);
GameObject firstInstance = null;
for (int i = 0; i < instanceCount; i++)
{
Vector3 spawnPosition = position + GetSpreadOffset(settings);
GameObject instance = VFXPool.Instance.Spawn(
resolvedAsset,
spawnPosition,
lifetime,
(spawnedInstance, visualEffect) => ApplySettings(spawnedInstance, visualEffect, settings));
if (instance == null) continue;
if (settings != null && settings.overrideSizeOverLife && settings.sizeOverLife != null)
{
VisualEffect visualEffect = instance.GetComponent<VisualEffect>();
bool hasVfxCurve = false;
if (visualEffect != null)
{
foreach (string propertyName in AnimationCurvePropertyNames)
{
if (visualEffect.HasAnimationCurve(propertyName))
{
hasVfxCurve = true;
break;
}
}
}
if (!hasVfxCurve)
{
VFXPool.Instance.AnimateScaleOverLifetime(instance, settings.scale, settings.sizeOverLife, lifetime);
}
}
if (firstInstance == null)
firstInstance = instance;
}
return firstInstance;
}
public static Vector3 GetColliderBottomPosition(Collider2D collider, Transform fallbackTransform, float yOffset = 0.18f)
{
if (collider == null)
return fallbackTransform ? fallbackTransform.position : Vector3.zero;
Bounds bounds = collider.bounds;
return new Vector3(bounds.center.x, bounds.min.y + yOffset, bounds.center.z);
}
private static Vector3 GetSpreadOffset(MvpVFXSpawnSettings settings)
{
if (settings == null || (settings.spreadRadiusX <= 0f && settings.spreadRadiusY <= 0f))
return Vector3.zero;
Vector2 randomPoint = Random.insideUnitCircle;
return new Vector3(
randomPoint.x * settings.spreadRadiusX,
randomPoint.y * settings.spreadRadiusY,
0f);
}
private static void ApplySettings(GameObject instance, MvpVFXSpawnSettings settings)
{
ApplySettings(instance, instance.GetComponent<VisualEffect>(), settings);
}
private static void ApplySettings(GameObject instance, VisualEffect visualEffect, MvpVFXSpawnSettings settings)
{
Vector3 scale = Vector3.one;
Quaternion rotation = Quaternion.identity;
if (settings != null)
{
scale = settings.useScale3D ? settings.scale3D : Vector3.one * settings.scale;
rotation = settings.rotation;
}
scale.x = Mathf.Max(0.01f, scale.x);
scale.y = Mathf.Max(0.01f, scale.y);
scale.z = Mathf.Max(0.01f, scale.z);
instance.transform.localScale = scale;
instance.transform.rotation = rotation;
ResetOverrides(instance, visualEffect);
if (visualEffect != null)
{
foreach (string propertyName in ScalePropertyNames)
{
if (visualEffect.HasVector3(propertyName))
visualEffect.SetVector3(propertyName, scale);
else if (visualEffect.HasFloat(propertyName))
visualEffect.SetFloat(propertyName, Mathf.Max(scale.x, scale.y));
}
}
if (settings == null)
return;
if (settings.overrideColor && visualEffect != null)
{
Vector4 color = new Vector4(settings.color.r, settings.color.g, settings.color.b, settings.color.a);
foreach (string propertyName in ColorPropertyNames)
{
if (visualEffect.HasVector4(propertyName))
visualEffect.SetVector4(propertyName, color);
}
}
if (settings.overrideParticleCount && visualEffect != null)
{
foreach (string propertyName in FloatPropertyNames)
{
if (visualEffect.HasFloat(propertyName))
visualEffect.SetFloat(propertyName, Mathf.Max(0f, settings.particleCount));
}
}
if (settings.overrideTexture && settings.texture != null && visualEffect != null)
{
foreach (string propertyName in TexturePropertyNames)
{
if (visualEffect.HasTexture(propertyName))
visualEffect.SetTexture(propertyName, settings.texture);
}
}
if (settings.overrideColorOverLife && settings.colorOverLife != null && visualEffect != null)
{
foreach (string propertyName in GradientPropertyNames)
{
if (visualEffect.HasGradient(propertyName))
visualEffect.SetGradient(propertyName, settings.colorOverLife);
}
}
if (settings.overrideSizeOverLife && settings.sizeOverLife != null && visualEffect != null)
{
foreach (string propertyName in AnimationCurvePropertyNames)
{
if (visualEffect.HasAnimationCurve(propertyName))
visualEffect.SetAnimationCurve(propertyName, settings.sizeOverLife);
}
}
Renderer renderer = instance.GetComponent<Renderer>();
if (renderer == null) return;
if (!settings.overrideColor && (!settings.overrideTexture || settings.texture == null)) return;
MaterialPropertyBlock block = new MaterialPropertyBlock();
if (settings.overrideColor)
{
block.SetColor("_Color", settings.color);
block.SetColor("_BaseColor", settings.color);
block.SetColor("_TintColor", settings.color);
}
if (settings.overrideTexture && settings.texture != null)
{
block.SetTexture("_MainTex", settings.texture);
block.SetTexture("_BaseMap", settings.texture);
block.SetTexture("_BaseColorMap", settings.texture);
}
renderer.SetPropertyBlock(block);
}
private static void ResetOverrides(GameObject instance, VisualEffect visualEffect)
{
if (visualEffect != null)
{
foreach (string propertyName in ColorPropertyNames)
{
if (visualEffect.HasVector4(propertyName))
visualEffect.ResetOverride(propertyName);
}
foreach (string propertyName in TexturePropertyNames)
{
if (visualEffect.HasTexture(propertyName))
visualEffect.ResetOverride(propertyName);
}
foreach (string propertyName in GradientPropertyNames)
{
if (visualEffect.HasGradient(propertyName))
visualEffect.ResetOverride(propertyName);
}
foreach (string propertyName in FloatPropertyNames)
{
if (visualEffect.HasFloat(propertyName))
visualEffect.ResetOverride(propertyName);
}
foreach (string propertyName in AnimationCurvePropertyNames)
{
if (visualEffect.HasAnimationCurve(propertyName))
visualEffect.ResetOverride(propertyName);
}
foreach (string propertyName in ScalePropertyNames)
{
if (visualEffect.HasVector3(propertyName))
visualEffect.ResetOverride(propertyName);
else if (visualEffect.HasFloat(propertyName))
visualEffect.ResetOverride(propertyName);
}
}
Renderer renderer = instance.GetComponent<Renderer>();
if (renderer != null)
renderer.SetPropertyBlock(null);
}
}
}