255 lines
8.8 KiB
C#
255 lines
8.8 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace SpriteShadersUltimate
|
|
{
|
|
[AddComponentMenu("Sprite Shaders Ultimate/Wind/Interactive Wind")]
|
|
public class InteractiveWindSSU : InstancerSSU
|
|
{
|
|
[Tooltip("How much physical interaction bends the sprite.")]
|
|
public float rotationFactor = 1.5f;
|
|
[Tooltip("How fast physical interaction bending fades in.")]
|
|
public float bendInSpeed = 8f;
|
|
[Tooltip("How fast physical interaction bending fades out.")]
|
|
public float bendOutSpeed = 8f;
|
|
|
|
[Tooltip("If disabled the sprite will only bend during active movement.")]
|
|
public bool stayBent = true;
|
|
[Tooltip("The minimum speed of the interacting object to trigger bending.")]
|
|
public float minBendSpeed = 1f;
|
|
|
|
[Tooltip("Swaps the material with the default sprite material while inactive.")]
|
|
public bool hyperPerformanceMode = false;
|
|
[Tooltip("Adds a tiny little offset to the Z position on start.\nTo prevent random resorting of render order.")]
|
|
public bool randomOffsetZ = true;
|
|
[Tooltip("Define a material to switch to while inactive.")]
|
|
public bool customMaterial = false;
|
|
[Tooltip("The shader used for the default sprite material.")]
|
|
public string inactiveShader = "Sprites/Default";
|
|
[Tooltip("The material used when inactive.")]
|
|
public Material inactiveMaterial;
|
|
|
|
[Tooltip("Slightly changes 'Wiggle Frequency', to desync the wiggle shaders of multiple sprites.")]
|
|
public bool randomizeWiggle = false;
|
|
[Tooltip("The editor-side script set's the layer to 'Ignore Raycast' to fix potential issues. Enable this to disable that and set the layer to a different one.")]
|
|
public bool allowCustomLayer = false;
|
|
|
|
//Variables:
|
|
HashSet<Collider2D> collidersInside;
|
|
BoxCollider2D boxCollider;
|
|
|
|
//Runtime:
|
|
float currentBending;
|
|
float currentRotationDirection;
|
|
bool isActive;
|
|
bool newDirection;
|
|
|
|
float lastPosition;
|
|
float lastBend;
|
|
float currentBendTarget;
|
|
bool bentInLastFrame;
|
|
|
|
SpriteRenderer sr;
|
|
static Material defaultMaterial;
|
|
|
|
int rotationId;
|
|
|
|
void Start()
|
|
{
|
|
//Initialize Variables:
|
|
collidersInside = new HashSet<Collider2D>();
|
|
boxCollider = GetComponent<BoxCollider2D>();
|
|
sr = GetComponent<SpriteRenderer>();
|
|
runtimeMaterial = sr.material;
|
|
|
|
if(defaultMaterial == null)
|
|
{
|
|
if (customMaterial)
|
|
{
|
|
defaultMaterial = inactiveMaterial;
|
|
}
|
|
else
|
|
{
|
|
defaultMaterial = new Material(Shader.Find(inactiveShader));
|
|
}
|
|
}
|
|
|
|
if(hyperPerformanceMode)
|
|
{
|
|
sr.material = defaultMaterial;
|
|
|
|
if(randomOffsetZ)
|
|
{
|
|
//Prevent Resorting:
|
|
Vector3 position = transform.position;
|
|
position.z += Random.value * 0.1f;
|
|
transform.position = position;
|
|
}
|
|
}
|
|
|
|
if(randomizeWiggle && runtimeMaterial != null)
|
|
{
|
|
float wiggleFrequency = runtimeMaterial.GetFloat("_WiggleFrequency") * (0.9f + 0.2f * Random.value);
|
|
runtimeMaterial.SetFloat("_WiggleFrequency", wiggleFrequency);
|
|
}
|
|
|
|
rotationId = Shader.PropertyToID("_WindRotation");
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
if (isActive == false) return;
|
|
|
|
Vector2 localPosition = new Vector2(0, -1000000);
|
|
|
|
foreach(Collider2D collider in collidersInside)
|
|
{
|
|
if(collider != null)
|
|
{
|
|
if(localPosition.y < -99999)
|
|
{
|
|
localPosition = collider.bounds.center - transform.position; //Collider Position
|
|
}
|
|
else
|
|
{
|
|
if (!newDirection) {
|
|
Vector2 newLocalPosition = (collider.bounds.center - transform.position);
|
|
if((currentRotationDirection < 0 && newLocalPosition.x > localPosition.x) || (currentRotationDirection > 0 && newLocalPosition.x < localPosition.x))
|
|
{
|
|
localPosition = newLocalPosition; //Take most heavy position
|
|
}
|
|
}
|
|
else
|
|
{
|
|
localPosition = ((Vector2)(collider.bounds.center - transform.position) + localPosition) * 0.5f; //Position Deviation (multiple colliders)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (localPosition.y > -99999) //Colliders are interacting with the wind sprite.
|
|
{
|
|
//Bend Direction:
|
|
if (newDirection)
|
|
{
|
|
if(localPosition.x < 0)
|
|
{
|
|
currentRotationDirection = -1;
|
|
}else
|
|
{
|
|
currentRotationDirection = 1;
|
|
}
|
|
|
|
newDirection = false;
|
|
}
|
|
|
|
//Bend Target:
|
|
float targetBending = 0;
|
|
if(currentRotationDirection < 0)
|
|
{
|
|
targetBending = Mathf.Clamp01((localPosition.x + boxCollider.size.x * 0.5f) / boxCollider.size.x);
|
|
}
|
|
else
|
|
{
|
|
targetBending = Mathf.Clamp01((boxCollider.size.x * 0.5f - localPosition.x) / boxCollider.size.x);
|
|
}
|
|
|
|
if(stayBent)
|
|
{
|
|
//Staying Bend:
|
|
currentBendTarget = targetBending;
|
|
}
|
|
else
|
|
{
|
|
//Temporary Bend:
|
|
bool moved = Mathf.Abs(lastPosition - localPosition.x) > Time.fixedDeltaTime * minBendSpeed;
|
|
|
|
if(moved && lastBend != 0 && currentRotationDirection > 0 == (localPosition.x - lastPosition) > 0)
|
|
{
|
|
moved = false;
|
|
}
|
|
|
|
if (moved || bentInLastFrame)
|
|
{
|
|
currentBendTarget = targetBending;
|
|
lastBend = targetBending;
|
|
bentInLastFrame = true;
|
|
|
|
if (!moved)
|
|
{
|
|
bentInLastFrame = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
currentBendTarget = Mathf.Lerp(currentBendTarget, 0, Time.fixedDeltaTime * bendInSpeed);
|
|
|
|
if (Mathf.Abs(currentBending) < 0.01f)
|
|
{
|
|
newDirection = true;
|
|
}
|
|
}
|
|
lastPosition = localPosition.x;
|
|
}
|
|
|
|
//Fade In Bending:
|
|
currentBending += (currentBendTarget * currentRotationDirection - currentBending) * Mathf.Min(bendInSpeed * Time.fixedDeltaTime, 1);
|
|
UpdateShader();
|
|
}
|
|
else
|
|
{
|
|
//Fade Out Bending:
|
|
currentBending -= currentBending * Mathf.Min(bendOutSpeed * Time.fixedDeltaTime,1);
|
|
UpdateShader();
|
|
|
|
if (Mathf.Abs(currentBending) < 0.005f)
|
|
{
|
|
isActive = false;
|
|
lastBend = 0;
|
|
|
|
if (hyperPerformanceMode)
|
|
{
|
|
sr.material = defaultMaterial;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void UpdateShader()
|
|
{
|
|
runtimeMaterial.SetFloat(rotationId, -1f * currentBending * rotationFactor);
|
|
}
|
|
|
|
void OnTriggerEnter2D(Collider2D collision)
|
|
{
|
|
if(collidersInside.Count == 0 || Mathf.Abs(currentBending) < 0.2f)
|
|
{
|
|
newDirection = true;
|
|
}
|
|
|
|
collidersInside.Add(collision);
|
|
|
|
if (hyperPerformanceMode && isActive == false)
|
|
{
|
|
sr.material = runtimeMaterial;
|
|
}
|
|
isActive = true;
|
|
}
|
|
void OnTriggerExit2D(Collider2D collision)
|
|
{
|
|
if (collidersInside.Contains(collision))
|
|
{
|
|
collidersInside.Remove(collision);
|
|
}
|
|
}
|
|
|
|
//Other:
|
|
public static void DefaultCollider(BoxCollider2D box)
|
|
{
|
|
box.isTrigger = true;
|
|
box.size = new Vector2(2, 1);
|
|
box.offset = new Vector2(0, -0.5f);
|
|
}
|
|
}
|
|
} |