JJBB/Assets/Project/Script/Plugin/LinkFxController.cs
2024-08-23 15:49:34 +08:00

188 lines
6.4 KiB
C#
Raw 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 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);
}
}
}