Skip to content

Instantly share code, notes, and snippets.

@jackphelps
Last active February 6, 2020 19:46
Show Gist options
  • Save jackphelps/f507d949a84c53457f570c5009bcb6d4 to your computer and use it in GitHub Desktop.
Save jackphelps/f507d949a84c53457f570c5009bcb6d4 to your computer and use it in GitHub Desktop.
CharacterFade
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace RPG.FX {
public class CharacterFade : MonoBehaviour
{
public static void Out(GameObject target, Materials dissolveMaterialToUse, Action callback, float duration = 1.5f)
{
CharacterFade fade = target.AddComponent<CharacterFade>();
fade.duration = duration;
fade.fadeOut = true;
fade.AssignMaterials(dissolveMaterialToUse);
fade.currentDissolutionLevel = 0;
fade.currentEdgeWidth = 0;
fade.SetValues(0,0);
SequenceTimer.Call(duration, callback);
}
// hack: I don't like that I'm including the dissolve material here but if the object was already dissolved out it won't actually be used
// but I don't want to NOT include it, you shouldn't have to worry about whether the thing was dissolved out or not
// I could re-map the materials but I'm lazy and I don't think that will ever be used
public static void In(GameObject target, Materials dissolveMaterialToUse, Action callback, float duration = 1.5f)
{
var existing = target.GetComponent<CharacterFade>();
if (existing != null) { existing.Cleanup(); }
CharacterFade fade = target.AddComponent<CharacterFade>();
fade.duration = duration;
fade.fadeOut = false;
fade.AssignMaterials(dissolveMaterialToUse);
fade.currentDissolutionLevel = 1;
fade.currentEdgeWidth = 1;
fade.SetValues(1,1);
SequenceTimer.Call(duration, callback);
}
// map of renderers to original materials so we can put them back
public Dictionary<Renderer, Material[]> materialsMap = new Dictionary<Renderer, Material[]>();
// list of each copy of the dissolve material added so we can loop through and update their dissolve levels
public List<Material> dissolveMaterials = new List<Material>();
public float duration;
public bool fadeOut;
public float currentDissolutionLevel; // 1 is fully out, 0 is fully in
public float currentEdgeWidth; // 1 is fully greyed out, 0 is fully colored in
void AssignMaterials(Materials dissolveMaterialToUse)
{
var renderers = gameObject.GetComponentsInChildren<Renderer>().ToList();
var thisRenderer = gameObject.GetComponent<Renderer>();
if (thisRenderer != null) { renderers.Add(thisRenderer); }
// loop through each renderer in the object
foreach (var renderer in renderers) {
if (renderer.materials.Length == 0) { continue; }
// add the component to the materials map so we can put things back later
materialsMap.Add(renderer, renderer.materials);
// assign each material a dissolve-ready equivalent, preserving the texture where relevant
var materialsCopy = renderer.materials;
for (var i = 0; i < renderer.materials.Length; i++) {
// make an instance of the dissolve material and assign its main texture from the original material
var originalMat = materialsCopy[i];
var dissolveMat = Asset.Load(dissolveMaterialToUse);
dissolveMat.mainTexture = originalMat.mainTexture;
materialsCopy[i] = dissolveMat;
// add the new material to our list so we can easily update the shader dissolve values
dissolveMaterials.Add(materialsCopy[i]);
}
renderer.materials = materialsCopy;
}
}
void SetValues(float edge, float level)
{
foreach (var mat in dissolveMaterials) {
mat.SetFloat("_Edges", edge);
mat.SetFloat("_Level", level);
}
}
void Update()
{
if (fadeOut) {
if (currentEdgeWidth >= 0.99f) {
if (currentDissolutionLevel >= 0.99f) {
} else {
currentDissolutionLevel += Time.deltaTime / duration * 2;
}
} else {
currentEdgeWidth += Time.deltaTime / duration * 2;
}
} else {
if (currentDissolutionLevel <= 0.01f) {
if (currentEdgeWidth <= 0.01f) {
Cleanup();
} else {
currentEdgeWidth -= Time.deltaTime / duration * 2;
}
} else {
currentDissolutionLevel -= Time.deltaTime / duration * 2;
}
}
SetValues(currentEdgeWidth, currentDissolutionLevel);
}
void Cleanup()
{
foreach (var pair in materialsMap) {
if (pair.Key != null && pair.Key is Renderer renderer && pair.Key.gameObject.activeInHierarchy) { renderer.materials = pair.Value; }
}
Destroy(this);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment