public abstract class AfterImage3D : MonoBehaviour
{
public abstract void Play();
}
public class AdventurerController : MonoBehaviour
{
private Animator animator;
private AfterImage3D afterImage3D;
private void Awake()
{
animator = GetComponent<Animator>();
afterImage3D = GetComponent<AfterImage3D>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
animator.Play("swordStrike1");
afterImage3D.Play();
}
}
}
方式1:
public class AfterImage3DByAnimation : AfterImage3D
{
public AfterImageObject afterImagePrefab;
public float Duration = 5;
public float Interval = 0.2f;
private float mTime = 5;
private Animator animator;
private List<AfterImageObject> afterImageObjects = new List<AfterImageObject>();
private void Awake()
{
animator = GetComponent<Animator>();
}
public override void Play()
{
if (GetComponentsInChildren<Renderer>().Length <= 0)
{
return;
}
mTime = Duration;
StartCoroutine(AddAfterImage());
}
IEnumerator AddAfterImage()
{
while (mTime > 0)
{
CreateImage();
yield return new WaitForSeconds(Interval);
mTime -= Interval;
}
yield return null;
}
private void CreateImage()
{
if (animator.GetCurrentAnimatorClipInfoCount(0) > 0)
{
string currentAnimationName = animator.GetCurrentAnimatorClipInfo(0)[0].clip.name;
float currentAnimationTime = animator.GetCurrentAnimatorStateInfo(0).normalizedTime;
for (int i = 0; i < afterImageObjects.Count; i++)
{
if (!afterImageObjects[i].gameObject.activeSelf)
{
afterImageObjects[i].Play(currentAnimationName, currentAnimationTime);
return;
}
}
AfterImageObject clone = Instantiate(afterImagePrefab, transform.position, transform.rotation);
clone.Play(currentAnimationName, currentAnimationTime);
afterImageObjects.Add(clone);
}
}
}
public class AfterImageObject : MonoBehaviour
{
private Animator animator;
public Renderer[] renderers;
public Material[] materials;
public float FadeoutTime = 1;
private Material[] tempMaterials;
private float time = 1;
public bool useDelay;
[Range(0, 1)]
public float delaySpeed;
public void Play(string animName, float normalizeTime)
{
if (animator == null)
{
animator = GetComponent<Animator>();
tempMaterials = new Material[renderers.Length];
for (int i = 0; i < renderers.Length; i++)
{
tempMaterials[i] = new Material(materials[i]);
renderers[i].material = tempMaterials[i];
renderers[i].shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
}
}
gameObject.SetActive(true);
animator.Play(animName, 0, normalizeTime);
animator.speed = useDelay ? delaySpeed : 0;
time = FadeoutTime;
}
void LateUpdate()
{
time -= Time.deltaTime;
for (int i = 0; i < tempMaterials.Length; i++)
{
if (tempMaterials[i].HasProperty("_Color"))
{
Color color = Color.white;
color.a = Mathf.Max(0, time / FadeoutTime);
tempMaterials[i].SetColor("_Color", color);
}
}
if (time <= 0)
{
for (int i = 0; i < tempMaterials.Length; i++)
{
if (tempMaterials[i].HasProperty("_Color"))
{
tempMaterials[i].SetColor("_Color", materials[i].GetColor("_Color"));
}
}
gameObject.SetActive(false);
}
}
}
方式三:
public class AfterImage3DByCombine : AfterImage3D
{
public class AfterImange
{
public Mesh mesh;
public Material material;
public Matrix4x4 matrix;
public float duration;
public float time;
}
protected SkinnedMeshRenderer[] skinRenderers;
protected MeshFilter[] filters;
protected int filtersCount = 0;
public bool IncludeMeshFilter = true;
public Material EffectMaterial;
public float Duration = 5;
public float Interval = 0.2f;
public float FadeoutTime = 1;
private float mTime = 5;
private List<AfterImange> mAfterImageList = new List<AfterImange>();
protected virtual void Awake()
{
skinRenderers = GetComponentsInChildren<SkinnedMeshRenderer>();
if (IncludeMeshFilter)
{
filters = GetComponentsInChildren<MeshFilter>();
filtersCount = filters.Length;
}
}
public override void Play()
{
if (skinRenderers.Length + filtersCount <= 0)
{
return;
}
mTime = Duration;
StartCoroutine(AddAfterImage());
}
IEnumerator AddAfterImage()
{
while (mTime > 0)
{
CreateImage();
yield return new WaitForSeconds(Interval);
mTime -= Interval;
}
yield return null;
}
void CreateImage()
{
CombineInstance[] combineInstances = new CombineInstance[skinRenderers.Length + filtersCount];
int index = 0;
for (int i = 0; i < skinRenderers.Length; i++)
{
var render = skinRenderers[i];
var mesh = new Mesh();
render.BakeMesh(mesh);
combineInstances[index] = new CombineInstance
{
mesh = mesh,
transform = render.gameObject.transform.localToWorldMatrix,
subMeshIndex = 0
};
index++;
}
for (int i = 0; i < filtersCount; i++)
{
var render = filters[i];
var temp = (render.sharedMesh != null) ? render.sharedMesh : render.mesh;
var mesh = (Mesh)Instantiate(temp);
combineInstances[index] = new CombineInstance
{
mesh = mesh,
transform = render.gameObject.transform.localToWorldMatrix,
subMeshIndex = 0
};
index++;
}
Mesh combinedMesh = new Mesh();
combinedMesh.CombineMeshes(combineInstances, true, true);
mAfterImageList.Add(new AfterImange
{
mesh = combinedMesh,
material = new Material(EffectMaterial),
time = FadeoutTime,
duration = FadeoutTime,
});
}
void LateUpdate()
{
bool needRemove = false;
foreach (var image in mAfterImageList)
{
image.time -= Time.deltaTime;
if (image.material.HasProperty("_Color"))
{
Color color = Color.white;
color.a = Mathf.Max(0, image.time / image.duration);
image.material.SetColor("_Color", color);
}
Graphics.DrawMesh(image.mesh, Matrix4x4.identity, image.material, gameObject.layer, null, 0, null, false);
if (image.time <= 0)
{
needRemove = true;
}
}
if (needRemove)
{
mAfterImageList.RemoveAll(x => x.time <= 0);
}
}
}
|