Files
JJBB/Assets/Project/Script/Plugin/LinkFxController.cs

188 lines
6.4 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
using Games.Scene;
using UnityEngine;
// 注Unity不支持在运行时获得材质Property列表因此具体每个链接特效都需要按材质属性订做
// 规格统一为所有Mesh类型Y方向不翻转所有Particle类型Y方向翻转90度
// 该虚构类型仅作为接口使用
public abstract class LinkFxController : MonoBehaviour
{
protected abstract bool isBillboard { get; }
private float _baseLength;
private Vector3 _baseScale;
private float _currentRotation;
protected LinkFxMaterialRecord[] materialRecords;
protected ParticleRecord[] particleRecords;
public bool revertLink;
public float rotationSpeed;
protected float endTime;
[HideInInspector] public Vector3 sourcePoint;
[HideInInspector] public Vector3 targetPoint;
private void Awake()
{
RegisterParticleSystems();
var normalMeshRenderer = RegisterMeshMaterials();
_baseScale = transform.localScale;
_baseLength = normalMeshRenderer.bounds.size.x;
}
private void OnDestroy()
{
for (var i = 0; i < materialRecords.Length; i++)
materialRecords[i].DestroyMaterial();
}
protected void RegisterParticleSystems()
{
// 不节约那几毛钱的运算量了
var particleSystems = transform.GetComponentsInChildren<ParticleSystem>(false);
particleRecords = new ParticleRecord[particleSystems.Length];
for (var i = 0; i < particleSystems.Length; i++)
particleRecords[i] = new ParticleRecord(particleSystems[i]);
}
protected abstract MeshRenderer RegisterMeshMaterials();
public virtual bool TryUpdateLink()
{
// 源角色或者目标不存在时,隐藏锁链效果
if (sourcePoint == targetPoint)
{
transform.localScale = Vector3.zero;
return false;
}
else
{
_currentRotation += Time.deltaTime * rotationSpeed;
// 计算面板位置
var delta = sourcePoint - targetPoint;
if (revertLink)
delta = -delta;
var valid = false;
if (delta != Vector3.zero)
{
var scale = delta.magnitude / _baseLength;
transform.position = (sourcePoint + targetPoint) * 0.5f;
transform.localScale = new Vector3(_baseScale.x * scale, _baseScale.y, _baseScale.z);
// 计算面板UV
for (var i = 0; i < particleRecords.Length; i++)
particleRecords[i].SetScale(scale);
for (var i = 0; i < materialRecords.Length; i++)
materialRecords[i].SetScale(scale);
// 计算面板方向 - 面板修改为定时旋转
var x = delta.normalized;
if (isBillboard && SceneLogic.CameraController != null && SceneLogic.CameraController.MainCamera != null)
{
var z = -SceneLogic.CameraController.MainCamera.transform.forward;
var y = Vector3.Cross(z, x);
if (y != Vector3.zero)
{
valid = true;
z = Vector3.Cross(x, y);
transform.rotation = Quaternion.LookRotation(z, y);
}
}
else
{
var y = Vector3.up;
var z = Vector3.Cross(x, y);
if (z != Vector3.zero)
{
valid = true;
// 将z方向按照旋转角度校正
z = Quaternion.AngleAxis(_currentRotation, x) * z;
y = Vector3.Cross(z, x);
//y = Quaternion.AngleAxis(currentRotation, x) * y;
transform.rotation = Quaternion.LookRotation(z, y);
}
}
}
// 连线长度为0或者同摄像机视线完全平行
if (!valid)
transform.localScale = Vector3.zero;
return valid;
}
}
/// <summary>
/// 部分需要在结束时做出特殊表现的锁链需要结束时间
/// </summary>
public void ResetEndTime(float pEndTime)
{
endTime = pEndTime;
}
protected class ParticleRecord
{
public readonly Vector3 boxSize;
public readonly float emission;
public readonly ParticleSystem particleSystem;
public ParticleRecord(ParticleSystem particle)
{
particleSystem = particle;
boxSize = particle.shape.scale;
emission = particle.emission.rate.constant;
}
public void SetScale(float scale)
{
var newBoxSize = boxSize;
newBoxSize.z *= scale;
var newShape = particleSystem.shape;
newShape.scale = newBoxSize;
var emissionModule = particleSystem.emission;
var rate = emissionModule.rate;
rate.constant = emission * scale;
emissionModule.rate = rate;
}
}
protected class LinkFxTextureRecord
{
public readonly Vector2 baseTiling;
public readonly string propertyName;
public LinkFxTextureRecord(string propertyName, Vector2 baseTiling)
{
this.propertyName = propertyName;
this.baseTiling = baseTiling;
}
}
protected class LinkFxMaterialRecord
{
public readonly Material material;
public readonly LinkFxTextureRecord[] textures;
public LinkFxMaterialRecord(Material material, string[] textureNames)
{
this.material = material;
textures = new LinkFxTextureRecord[textureNames.Length];
for (var i = 0; i < textures.Length; i++)
{
var tiling = material.GetTextureScale(textureNames[i]);
textures[i] = new LinkFxTextureRecord(textureNames[i], tiling);
}
}
public void SetScale(float scale)
{
for (var i = 0; i < textures.Length; i++)
{
var tiling = textures[i].baseTiling;
tiling.x *= scale;
material.SetTextureScale(textures[i].propertyName, tiling);
}
}
public void DestroyMaterial()
{
Destroy(material);
}
}
}