Files
Continentis/Assets/OtherPlugins/Sprite Shaders Ultimate/Scripts/Interactive/InteractiveWindSSU.cs
SoulliesOfficial ad4948207e 推进度!
2025-11-25 21:49:03 -05:00

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);
}
}
}