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