Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
- Исправлено поведение игрока при падении с высоты и разворотах (устранен сильный отскок от углов) - Центрирован PolygonCollider2D по оси X на префабе character_defeat_4.prefab (m_Offset.x установлен в 0) - Упрощена форма PolygonCollider2D до симметричного выпуклого шестиугольника - Сохранен бэкап старого префаба игрока в Player_Old.prefab
304 lines
11 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|