1. svn -> git

This commit is contained in:
2017-04-12 01:23:07 +09:00
commit daaaf2997b
406 changed files with 68990 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
using UnityEngine;
[AddComponentMenu("Destructible 2D/D2D Anchor")]
public class D2D_Anchor : MonoBehaviour
{
public float Radius = 1.0f;
public float ScaledRadius
{
get
{
return Radius * Mathf.Max(transform.lossyScale.x, Mathf.Max(transform.lossyScale.y, transform.lossyScale.z));
}
}
#if UNITY_EDITOR
protected virtual void OnDrawGizmosSelected()
{
var c = transform.position;
var r = ScaledRadius;
var s = Mathf.PI * 2.0f / 36.0f;
for (var i = 0; i < 36; i++)
{
var a = i * s;
var b = a + s;
Gizmos.DrawLine(c + new Vector3(Mathf.Sin(a), Mathf.Cos(a), 0.0f) * r, c + new Vector3(Mathf.Sin(b), Mathf.Cos(b), 0.0f) * r);
}
}
#endif
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 264ae736e9dab8a46a43cd3488c6230e
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,122 @@
using UnityEngine;
[ExecuteInEditMode]
[AddComponentMenu("Destructible 2D/D2D Auto Polygon Collider")]
public class D2D_AutoPolygonCollider : D2D_Collider
{
[SerializeField]
private PolygonCollider2D polygonCollider2D;
public void RebuildCollider(Texture2D alphaTex)
{
DestroyPolygonCollider2D();
if (alphaTex != null)
{
if (polygonCollider2D == null)
{
var spriteRenderer = D2D_Helper.GetOrAddComponent<SpriteRenderer>(gameObject);
var sprite = Sprite.Create(alphaTex, new Rect(0, 0, alphaTex.width, alphaTex.height), Vector2.zero, 1.0f, 0, SpriteMeshType.FullRect);
spriteRenderer.sprite = sprite;
polygonCollider2D = gameObject.AddComponent<PolygonCollider2D>();
// Disable the collider if it couldn't form any triangles
polygonCollider2D.enabled = IsDefaultPolygonCollider2D(polygonCollider2D) == false;
UpdateColliderSettings();
D2D_Helper.Destroy(sprite);
D2D_Helper.Destroy(spriteRenderer);
}
}
}
public override void UpdateColliderSettings()
{
if (polygonCollider2D != null)
{
polygonCollider2D.isTrigger = IsTrigger;
polygonCollider2D.sharedMaterial = Material;
}
}
protected virtual void OnDestroy()
{
D2D_Helper.DestroyManaged(DestroyPolygonCollider2D);
}
protected override void RebuildAll()
{
var destructible = D2D_Helper.GetComponentUpwards<D2D_Destructible>(transform);
if (destructible != null)
{
RebuildCollider(destructible.AlphaTex);
}
}
private void DestroyPolygonCollider2D()
{
if (polygonCollider2D != null)
{
D2D_Helper.Destroy(polygonCollider2D);
polygonCollider2D = null;
}
}
// The default collider is a pentagon, but its position and size changes based on the sprite
private static bool IsDefaultPolygonCollider2D(PolygonCollider2D polygonCollider2D)
{
if (polygonCollider2D == null) return false;
if (polygonCollider2D.GetTotalPointCount() != 5) return false;
var points = polygonCollider2D.points;
var spacing = Vector2.Distance(points[0], points[4]);
// Same spacing?
for (var i = 0; i < 4; i++)
{
var spacing2 = Vector2.Distance(points[i], points[i + 1]);
if (Mathf.Approximately(spacing, spacing2) == false)
{
return false;
}
}
var midpoint = (points[0] + points[1] + points[2] + points[3] + points[4]) * 0.2f;
var radius = Vector2.Distance(points[0], midpoint);
// Same radius?
for (var i = 1; i < 5; i++)
{
var radius2 = Vector2.Distance(points[i], midpoint);
if (Mathf.Approximately(radius, radius2) == false)
{
return false;
}
}
// Must be a pentagon then!
return true;
}
#if UNITY_EDITOR
protected override void SetHideFlags(HideFlags hideFlags)
{
if (polygonCollider2D != null)
{
polygonCollider2D.hideFlags = hideFlags;
}
}
#else
protected override void SetHideFlags(HideFlags hideFlags)
{
}
#endif
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0379d2d63d6fc2a48b08b1495ea22549
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,55 @@
using UnityEngine;
using System.Collections.Generic;
[RequireComponent(typeof(D2D_DestructibleSprite))]
[RequireComponent(typeof(Rigidbody2D))]
[AddComponentMenu("Destructible 2D/D2D Breakable")]
public class D2D_Breakable : MonoBehaviour
{
public bool ChangeColliderType;
public D2D_SpriteColliderType NewColliderType = D2D_SpriteColliderType.AutoPolygon;
public List<D2D_Anchor> Anchors = new List<D2D_Anchor>();
protected virtual void OnAlphaTexModified()
{
var destructibleSprite = GetComponent<D2D_DestructibleSprite>();
var rb2d = GetComponent<Rigidbody2D>();
var anchored = false;
// Find which anchors we're connected to
foreach (var anchor in Anchors)
{
var collider2Ds = Physics2D.OverlapCircleAll(anchor.transform.position, anchor.ScaledRadius);
foreach (var collider2D in collider2Ds)
{
if (collider2D.attachedRigidbody == rb2d)
{
anchored = true; goto ExitLoops;
}
}
}
ExitLoops:
// Broken off anchors?
if (anchored == false)
{
// Enable physics
GetComponent<Rigidbody2D>().isKinematic = false;
// Change collider?
if (ChangeColliderType == true && destructibleSprite.ColliderType != NewColliderType)
{
destructibleSprite.ColliderType = NewColliderType;
destructibleSprite.RebuildColliders();
}
// Now that it's broken, we no longer need this
D2D_Helper.Destroy(this);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bf10e60ef78d24d4ca2bdc58163c7d41
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,52 @@
using UnityEngine;
public abstract class D2D_Collider : MonoBehaviour
{
public bool IsTrigger;
public PhysicsMaterial2D Material;
private bool dirty;
public void MarkAsDirty()
{
#if UNITY_EDITOR
D2D_Helper.SetDirty(this);
#endif
dirty = true;
}
public abstract void UpdateColliderSettings();
protected abstract void SetHideFlags(HideFlags hideFlags);
protected abstract void RebuildAll();
protected virtual void Update()
{
if (dirty == true)
{
dirty = false;
RebuildAll();
}
}
#if UNITY_EDITOR
public void SetHideFlags(bool hide)
{
var hideFlags = HideFlags.NotEditable;
if (hide == true)
{
hideFlags |= HideFlags.HideInInspector;
}
SetHideFlags(hideFlags);
}
#else
public void SetHideFlags(bool hide)
{
}
#endif
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7375669b0754bd044a108513917998d3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,155 @@
using UnityEngine;
using System.Collections.Generic;
[ExecuteInEditMode]
[AddComponentMenu("Destructible 2D/D2D Damageable Sprite")]
[RequireComponent(typeof(SpriteRenderer))]
public class D2D_DamageableSprite : MonoBehaviour
{
[System.Serializable]
public class DamageLevel
{
public Sprite Sprite;
public float DamageRequired;
}
public float Damage;
public bool AllowDestruction;
public float DamageLimit;
public GameObject ReplaceWith;
public List<DamageLevel> DamageLevels = new List<DamageLevel>();
private SpriteRenderer spriteRenderer;
public DamageLevel AddDamageLevel(Sprite sprite = null, float damageRequired = 0.0f)
{
if (DamageLevels == null)
{
DamageLevels = new List<DamageLevel>();
}
var newDamageLevel = new DamageLevel(); DamageLevels.Add(newDamageLevel);
newDamageLevel.Sprite = sprite;
newDamageLevel.DamageRequired = damageRequired;
return newDamageLevel;
}
public void InflictDamage(float amount)
{
Damage += amount;
UpdateSprite();
}
public void UpdateSprite()
{
var bestDamageLevel = default(DamageLevel);
if (DamageLevels != null)
{
foreach (var damageLevel in DamageLevels)
{
if (damageLevel != null)
{
if (bestDamageLevel == null || Damage >= damageLevel.DamageRequired)
{
// Skip if this is below the best
if (bestDamageLevel != null && damageLevel.DamageRequired < bestDamageLevel.DamageRequired)
{
continue;
}
bestDamageLevel = damageLevel;
}
}
}
}
// Replace sprite?
if (bestDamageLevel != null)
{
if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer.sprite != bestDamageLevel.Sprite)
{
if (bestDamageLevel.Sprite != null)
{
spriteRenderer.sprite = bestDamageLevel.Sprite;
}
else
{
spriteRenderer.sprite = null;
}
}
}
UpdateDestruction();
}
protected virtual void Awake()
{
UpdateDamageLevels();
}
#if UNITY_EDITOR
protected virtual void Reset()
{
UpdateDamageLevels();
}
protected virtual void OnValidate()
{
UpdateSprite();
}
#endif
private void UpdateDamageLevels()
{
if (DamageLevels == null)
{
DamageLevels = new List<DamageLevel>();
}
// Copy default damage level from SpriteRenderer?
if (DamageLevels.Count == 0)
{
if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer.sprite != null)
{
var newDamageLevel = new DamageLevel(); DamageLevels.Add(newDamageLevel);
newDamageLevel.Sprite = spriteRenderer.sprite;
}
}
}
private void UpdateDestruction()
{
if (AllowDestruction == true)
{
#if UNITY_EDITOR
if (Application.isPlaying == false)
{
return;
}
#endif
if (Damage >= DamageLimit)
{
if (ReplaceWith != null)
{
D2D_Helper.CloneGameObject(ReplaceWith, transform.parent, transform.position, transform.rotation);
}
D2D_Helper.Destroy(gameObject);
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2f6d4628b68d59b4993e66e09e35af00
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,524 @@
using UnityEngine;
using System.Collections.Generic;
public enum D2D_SpriteSplitOrder
{
Default,
KeepLargest,
KeepSmallest
}
public abstract class D2D_Destructible : MonoBehaviour
{
public static List<D2D_Destructible> Destructibles = new List<D2D_Destructible>();
public static List<D2D_Destructible> DestructiblesCopy = new List<D2D_Destructible>();
public Texture2D DensityTex;
public bool AllowSplit;
public int SplitMinPixels = 20;
[D2D_RangeAttribute(0.0f, 1.0f)]
public float SplitThreshold = 0.25f;
public D2D_SpriteSplitOrder SplitOrder = D2D_SpriteSplitOrder.Default;
public int OriginalSolidPixelCount;
[System.NonSerialized]
private Texture2D alphaTex;
[SerializeField]
private float alphaScaleX;
[SerializeField]
private float alphaScaleY;
[SerializeField]
private byte[] alphaTexData;
[SerializeField]
private int alphaTexWidth;
[SerializeField]
private int alphaTexHeight;
[SerializeField]
private int cachedSolidPixelCount = -1;
private bool dirty;
public Texture2D AlphaTex
{
get
{
DeserializeAlphaTex();
return alphaTex;
}
}
public int SolidPixelCount
{
get
{
if (cachedSolidPixelCount == -1)
{
cachedSolidPixelCount = 0;
DeserializeAlphaTex();
if (alphaTex != null && alphaTex.width > 0 && alphaTex.height > 0)
{
/*
for (var y = 0; y < alphaTex.height; y++)
{
for (var x = 0; x < alphaTex.width; x++)
{
if (alphaTex.GetPixel(x, y).a >= 0.5f)
{
cachedSolidPixelCount += 1;
}
}
}
*/
// This is faster?
var pixels = alphaTex.GetPixels32();
for (var i = pixels.Length - 1; i >= 0; i--)
{
if (pixels[i].a >= 128)
{
cachedSolidPixelCount += 1;
}
}
}
}
return cachedSolidPixelCount;
}
}
public float SolidPixelRatio
{
get
{
return D2D_Helper.Divide(SolidPixelCount, OriginalSolidPixelCount);
}
}
public abstract Matrix4x4 WorldToPixelMatrix
{
get;
}
public void ResizeAlphaTex(int newWidth, int newHeight)
{
DeserializeAlphaTex();
if (alphaTex != null)
{
ReplaceAlphaWith(new D2D_Pixels(alphaTex).GetResized(newWidth, newHeight));
}
}
[ContextMenu("Halve Alpha Tex")]
public void HalveAlphaTex()
{
DeserializeAlphaTex();
if (alphaTex != null)
{
ResizeAlphaTex(alphaTex.width / 2, alphaTex.height / 2);
}
}
[ContextMenu("Blur Alpha Tex")]
public void BlurAlphaTex()
{
DeserializeAlphaTex();
if (alphaTex != null)
{
ReplaceAlphaWith(new D2D_Pixels(alphaTex).GetBlurredAlpha());
}
}
[ContextMenu("Recalculate Original Solid Pixel Count")]
public void RecalculateOriginalSolidPixelCount()
{
OriginalSolidPixelCount = SolidPixelCount;
}
public void ReplaceAlphaWith(Sprite newSprite)
{
ReplaceAlphaWith(newSprite != null ? new D2D_Pixels(newSprite) : null);
}
public void ReplaceAlphaWith(Texture2D newTexture)
{
ReplaceAlphaWith(newTexture != null ? new D2D_Pixels(newTexture) : null);
}
public void ReplaceAlphaWith(int newWidth, int newHeight, Color32[] newPixels)
{
ReplaceAlphaWith(new D2D_Pixels(newWidth, newHeight, newPixels));
}
public void ReplaceAlphaWith(D2D_Pixels newPixels)
{
#if UNITY_EDITOR
if (alphaTex != null)
{
D2D_Helper.Record(this, "Modify Alpha Tex");
}
#endif
if (newPixels != null)
{
// Remake texture?
//if (alphaTex == null || alphaTex.width != newPixels.Width || alphaTex.height != newPixels.Height)
{
DestroyAlphaTex();
alphaTexData = newPixels.ApplyAlpha();
alphaTexWidth = newPixels.Width;
alphaTexHeight = newPixels.Height;
alphaScaleX = D2D_Helper.Reciprocal(alphaTexWidth - 1);
alphaScaleY = D2D_Helper.Reciprocal(alphaTexHeight - 1);
}
// Copy settings over?
//else
{
// alphaTex.SetPixels32(newPixels.Pixels);
// alphaTex.Apply();
}
UpdateRect(0, alphaTexWidth, 0, alphaTexHeight);
}
else
{
DestroyAlphaTex();
UpdateRect(0, 0, 0, 0);
}
MarkAsDirty();
NotifyChanges();
#if UNITY_EDITOR
D2D_Helper.SetDirty(this);
#endif
}
public static Matrix4x4 CalculateStampMatrix(Vector2 position, Vector2 size, float angle)
{
var t = D2D_Helper.TranslationMatrix(position.x, position.y, 0.0f);
var r = D2D_Helper.RotationMatrix(Quaternion.Euler(0.0f, 0.0f, angle));
var s = D2D_Helper.ScalingMatrix(size.x, size.y, 1.0f);
var o = D2D_Helper.TranslationMatrix(-0.5f, -0.5f, 0.0f); // Centre stamp
return t * r * s * o;
}
public static void SliceAll(Vector2 startPos, Vector2 endPos, float thickness, Texture2D stampTex, float hardness, int layerMask = -1)
{
if (stampTex != null)
{
var mid = (startPos + endPos) / 2.0f;
var vec = endPos - startPos;
var size = new Vector2(thickness, vec.magnitude);
var angle = D2D_Helper.Atan2(vec) * -Mathf.Rad2Deg;
StampAll(CalculateStampMatrix(mid, size, angle), stampTex, hardness, layerMask);
}
}
public static void StampAll(Vector2 position, Vector2 size, float angle, Texture2D stampTex, float hardness, int layerMask = -1)
{
if (stampTex != null)
{
StampAll(CalculateStampMatrix(position, size, angle), stampTex, hardness, layerMask);
}
}
public static void StampAll(Matrix4x4 matrix, Texture2D stampTex, float hardness, int layerMask = -1)
{
if (stampTex != null)
{
// The original list may change during the stamping, so make a clone
DestructiblesCopy.Clear();
DestructiblesCopy.AddRange(Destructibles);
foreach (var destructible in DestructiblesCopy)
{
if (destructible != null)
{
var mask = 1 << destructible.gameObject.layer;
if ((layerMask & mask) != 0)
{
destructible.Stamp(matrix, stampTex, hardness);
}
}
}
}
}
public float GetAlphaAll(Vector2 position, int layerMask = -1)
{
var alpha = default(float);
GetAlphaAll(position, ref alpha);
return alpha;
}
public bool GetAlphaAll(Vector2 position, ref float alpha, int layerMask = -1)
{
foreach (var destructible in Destructibles)
{
if (destructible != null)
{
var mask = 1 << destructible.gameObject.layer;
if ((layerMask & mask) != 0)
{
if (destructible.GetAlpha(position, ref alpha) == true)
{
return true;
}
}
}
}
return false;
}
public float GetAlpha(Vector2 position)
{
var alpha = default(float);
GetAlpha(position, ref alpha);
return alpha;
}
public bool GetAlpha(Vector2 position, ref float alpha)
{
if (alphaTexData != null && alphaTexData.Length > 0)
{
var point = WorldToPixelMatrix.MultiplyPoint(position);
var x = Mathf.FloorToInt(point.x);
var y = Mathf.FloorToInt(point.y);
if (x >= 0 && x < alphaTexWidth)
{
if (y >= 0 && y < alphaTexHeight)
{
alpha = alphaTexData[x + y * alphaTexWidth]; return true;
}
}
}
return false;
}
public void Stamp(Vector2 position, Vector2 size, float angle, Texture2D stampTex, float hardness)
{
DeserializeAlphaTex();
if (alphaTex != null && stampTex != null)
{
Stamp(CalculateStampMatrix(position, size, angle), stampTex, hardness);
}
}
public void Stamp(Matrix4x4 stampMatrix, Texture2D stampTex, float hardness)
{
if (alphaTex != null && stampTex != null)
{
var stampToPixelMatrix = WorldToPixelMatrix * stampMatrix;
var pixelToStampMatrix = stampToPixelMatrix.inverse;
#if UNITY_EDITOR
D2D_Helper.MakeTextureReadable(stampTex);
D2D_Helper.MakeTextureReadable(DensityTex);
#endif
// Project corners of stamp
// TODO: account for non-orthogonal matrices?
var bl = stampToPixelMatrix.MultiplyPoint(new Vector3(0.0f, 0.0f, 0.0f));
var br = stampToPixelMatrix.MultiplyPoint(new Vector3(1.0f, 0.0f, 0.0f));
var tl = stampToPixelMatrix.MultiplyPoint(new Vector3(0.0f, 1.0f, 0.0f));
var tr = stampToPixelMatrix.MultiplyPoint(new Vector3(1.0f, 1.0f, 0.0f));
// Find AABB of stamp
var xMin = Mathf.FloorToInt(Mathf.Min(Mathf.Min(bl.x, br.x), Mathf.Min(tl.x, tr.x)));
var xMax = Mathf.FloorToInt(Mathf.Max(Mathf.Max(bl.x, br.x), Mathf.Max(tl.x, tr.x)));
var yMin = Mathf.FloorToInt(Mathf.Min(Mathf.Min(bl.y, br.y), Mathf.Min(tl.y, tr.y)));
var yMax = Mathf.FloorToInt(Mathf.Max(Mathf.Max(bl.y, br.y), Mathf.Max(tl.y, tr.y)));
xMin = Mathf.Clamp(xMin, 0, alphaTexWidth - 1);
xMax = Mathf.Clamp(xMax, 0, alphaTexWidth - 1);
yMin = Mathf.Clamp(yMin, 0, alphaTexHeight - 1);
yMax = Mathf.Clamp(yMax, 0, alphaTexHeight - 1);
if (xMax > xMin && yMax > yMin)
{
MarkAsDirty();
for (var y = yMin; y <= yMax; y++)
{
for (var x = xMin; x <= xMax; x++)
{
var uv = pixelToStampMatrix.MultiplyPoint(new Vector3(x, y, 0.0f));
// Is this pixel within the stamp?
if (uv.x >= 0.0f && uv.y >= 0.0f && uv.x < 1.0f && uv.y < 1.0f)
{
var stamp = stampTex.GetPixel(Mathf.FloorToInt(uv.x * stampTex.width), Mathf.FloorToInt(uv.y * stampTex.height));
FastPaint(x, y, stamp.a * hardness);
}
}
}
if (alphaTex != null)
{
alphaTex.Apply();
}
var split = false;
if (AllowSplit == true)
{
split = D2D_SplitCalculator.Generate(this, SplitOrder);
}
if (split == false)
{
UpdateRect(xMin, xMax, yMin, yMax);
NotifyChanges();
}
}
}
}
private void FastPaint(int x, int y, float opacity)
{
var index = x + y * alphaTexWidth;
var alpha = alphaTexData[index];
if (DensityTex != null)
{
var u = x * alphaScaleX * DensityTex.width;
var v = y * alphaScaleY * DensityTex.height;
var density = DensityTex.GetPixel(Mathf.FloorToInt(u), Mathf.FloorToInt(v));
opacity *= 1.0f - density.a;
}
var a = (int)(opacity * 255.0f);
alpha = (byte)Mathf.Clamp((int)alpha - a, 0, 255);
alphaTexData[index] = alpha;
}
protected virtual void OnEnable()
{
Destructibles.Add(this);
#if UNITY_EDITOR
if (UnityEditor.AssetDatabase.Contains(this) == true)
{
return;
}
#endif
CacheTexures();
}
protected virtual void OnDisable()
{
Destructibles.Remove(this);
}
protected virtual void OnDestroy()
{
DestroyAlphaTex();
}
#if UNITY_EDITOR
protected virtual void OnValidate()
{
D2D_Helper.MakeTextureReadable(DensityTex);
}
#endif
protected abstract void UpdateRect(int xMin, int xMax, int yMin, int yMax);
private void DeserializeAlphaTex()
{
if ((dirty == true || alphaTex == null) && alphaTexData != null && alphaTexData.Length > 0 && alphaTexWidth > 0 && alphaTexHeight > 0)
{
dirty = false;
var pixels = new Color32[alphaTexData.Length];
for (var i = pixels.Length - 1; i >= 0; i--)
{
pixels[i].a = alphaTexData[i];
}
alphaTex = new Texture2D(alphaTexWidth, alphaTexHeight, TextureFormat.Alpha8, false);
alphaTex.hideFlags = HideFlags.DontSave;
alphaTex.wrapMode = TextureWrapMode.Clamp;
alphaTex.SetPixels32(pixels);
alphaTex.Apply();
}
}
private void DestroyAlphaTex()
{
if (alphaTex != null)
{
D2D_Helper.Destroy(alphaTex);
alphaTex = null;
}
alphaTexData = null;
alphaTexWidth = 0;
alphaTexHeight = 0;
}
private void CacheTexures()
{
if (DensityTex != null)
{
if (DensityTex.width > 0 && DensityTex.height > 0)
{
DensityTex.GetPixel(0, 0);
}
}
}
private void MarkAsDirty()
{
dirty = true;
cachedSolidPixelCount = -1;
}
private void NotifyChanges()
{
#if UNITY_EDITOR
if (Application.isPlaying == false)
{
return;
}
#endif
BroadcastMessage("OnAlphaTexModified", SendMessageOptions.DontRequireReceiver);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 69ac85ffa12a392489dd6515db8561f8
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,489 @@
using UnityEngine;
using System.Collections.Generic;
public enum D2D_SpriteColliderType
{
None,
Edge,
Polygon,
AutoPolygon
}
[ExecuteInEditMode]
[AddComponentMenu("Destructible 2D/D2D Destructible Sprite")]
[RequireComponent(typeof(SpriteRenderer))]
public class D2D_DestructibleSprite : D2D_Destructible
{
public static List<D2D_DestructibleSprite> DestructibleSprites = new List<D2D_DestructibleSprite>();
public Material SourceMaterial;
[D2D_RangeAttribute(1.0f, 10.0f)]
public float Sharpness = 1.0f;
public D2D_SpriteColliderType ColliderType = D2D_SpriteColliderType.None;
[SerializeField]
private SpriteRenderer spriteRenderer;
[SerializeField]
private D2D_EdgeColliders edgeColliders;
[SerializeField]
private D2D_PolygonColliders polygonColliders;
[SerializeField]
private D2D_AutoPolygonCollider autoPolygonCollider;
[SerializeField]
private float expectedPixelsToUnits;
[SerializeField]
private Vector2 expectedPivot;
[SerializeField]
private Material clonedMaterial;
public override Matrix4x4 WorldToPixelMatrix
{
get
{
if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();
if (AlphaTex != null)
{
var sprite = spriteRenderer.sprite;
if (sprite != null)
{
var scale = CalculateAlphaTexScale(sprite);
var offset = CalculateAlphaTexOffset(sprite);
var s = D2D_Helper.ScalingMatrix(D2D_Helper.Reciprocal(scale));
var t = D2D_Helper.TranslationMatrix(-offset);
return s * t * transform.worldToLocalMatrix;
}
}
return transform.worldToLocalMatrix;
}
}
[ContextMenu("Halve Alpha Tex And Split Min Pixels")]
public void HalveAlphaTexAndSplitMinPixels()
{
if (AlphaTex != null)
{
HalveAlphaTex();
SplitMinPixels = Mathf.Max(1, SplitMinPixels / 2);
}
}
[ContextMenu("Blur Alpha Tex And Double Sharpness")]
public void BlurAlphaTexAndDoubleSharpness()
{
if (AlphaTex != null)
{
BlurAlphaTex();
Sharpness *= 2;
}
}
public void RebuildColliders()
{
if (AlphaTex != null && AlphaTex.width > 0 && AlphaTex.height > 0)
{
RebuildColliders(0, AlphaTex.width, 0, AlphaTex.height);
}
}
protected override void OnEnable()
{
base.OnEnable();
// Has this been cloned?
if (clonedMaterial != null)
{
foreach (var destructibleSprite in DestructibleSprites)
{
if (destructibleSprite != null && destructibleSprite.clonedMaterial == clonedMaterial)
{
OnDuplicate();
}
}
}
DestructibleSprites.Add(this);
}
protected override void OnDisable()
{
base.OnDisable();
DestructibleSprites.Remove(this);
}
protected virtual void Update()
{
if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();
// Copy alpha from main tex
if (AlphaTex == null && spriteRenderer.sprite != null)
{
ReplaceAlphaWith(spriteRenderer.sprite);
RecalculateOriginalSolidPixelCount();
}
#if UNITY_EDITOR
D2D_Helper.MakeTextureReadable(DensityTex);
#endif
UpdateColliders();
}
protected override void OnDestroy()
{
base.OnDestroy();
DestroyAutoPolygonCollider();
DestroyPolygonColliders();
DestroyEdgeColliders();
DestroyMaterial();
}
protected virtual void OnWillRenderObject()
{
if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();
UpdateSourceMaterial();
DestroyMaterialIfSettingsDiffer();
var sprite = spriteRenderer.sprite;
if (SourceMaterial != null && sprite != null)
{
// Clone new material?
if (clonedMaterial == null)
{
clonedMaterial = D2D_Helper.Clone(SourceMaterial, false);
}
else
{
clonedMaterial.CopyPropertiesFromMaterial(SourceMaterial);
}
#if UNITY_EDITOR
clonedMaterial.hideFlags = HideFlags.DontSave;
#endif
clonedMaterial.SetTexture("_MainTex", sprite.texture);
clonedMaterial.SetTexture("_AlphaTex", AlphaTex);
clonedMaterial.SetVector("_AlphaScale", CalculateAlphaScale(sprite));
clonedMaterial.SetVector("_AlphaOffset", CalculateAlphaOffset(sprite));
clonedMaterial.SetFloat("_Sharpness", Sharpness);
#if UNITY_EDITOR
clonedMaterial.hideFlags = HideFlags.None;
#endif
}
if (spriteRenderer.sharedMaterial != clonedMaterial)
{
spriteRenderer.sharedMaterial = clonedMaterial;
}
}
protected override void UpdateRect(int xMin, int xMax, int yMin, int yMax)
{
RebuildColliders(xMin, xMax, yMin, yMax);
}
protected virtual void OnDuplicate()
{
if (spriteRenderer == null) spriteRenderer = GetComponent<SpriteRenderer>();
if (clonedMaterial == spriteRenderer.sharedMaterial)
{
clonedMaterial = D2D_Helper.Clone(clonedMaterial);
spriteRenderer.sharedMaterial = clonedMaterial;
}
}
private Vector2 CalculateAlphaScale(Sprite sprite)
{
var texture = sprite.texture;
var textureRect = sprite.textureRect;
var scaleX = texture.width / textureRect.width;
var scaleY = texture.height / textureRect.height;
return new Vector2(scaleX, scaleY);
}
private Vector2 CalculateAlphaOffset(Sprite sprite)
{
var texture = sprite.texture;
var textureRect = sprite.textureRect;
var offsetX = textureRect.x / texture.width;
var offsetY = textureRect.y / texture.height;
return new Vector2(offsetX, offsetY);
}
private void UpdateSourceMaterial()
{
// Do we need to set a source material?
if (SourceMaterial == null)
{
if (spriteRenderer.sharedMaterial != null)
{
SourceMaterial = spriteRenderer.sharedMaterial;
}
else
{
SourceMaterial = Resources.Load<Material>("Sprites-Default (Destructible 2D)");
}
}
// Replace Sprites-Default with Sprites-Default (Destructible 2D)?
if (SourceMaterial != null && SourceMaterial.HasProperty("_AlphaTex") == false)
{
if (SourceMaterial.name == "Sprites-Default")
{
SourceMaterial = Resources.Load<Material>("Sprites-Default (Destructible 2D)");
}
}
}
private void RebuildColliders(int xMin, int xMax, int yMin, int yMax)
{
switch (ColliderType)
{
case D2D_SpriteColliderType.Edge:
{
if (edgeColliders != null)
{
edgeColliders.RebuildColliders(AlphaTex, xMin, xMax, yMin, yMax);
}
}
break;
case D2D_SpriteColliderType.Polygon:
{
if (polygonColliders != null)
{
polygonColliders.RebuildColliders(AlphaTex, xMin, xMax, yMin, yMax);
}
}
break;
case D2D_SpriteColliderType.AutoPolygon:
{
if (autoPolygonCollider != null)
{
autoPolygonCollider.RebuildCollider(AlphaTex);
}
}
break;
}
}
private void UpdateColliders()
{
if (ColliderType != D2D_SpriteColliderType.None)
{
var colliderTransform = default(Transform);
switch (ColliderType)
{
case D2D_SpriteColliderType.Edge:
{
DestroyAutoPolygonCollider();
DestroyPolygonColliders();
if (edgeColliders == null)
{
edgeColliders = D2D_Helper.CreateGameObject("Edge Colliders", transform).AddComponent<D2D_EdgeColliders>();
edgeColliders.RebuildAllColliders(AlphaTex);
}
colliderTransform = edgeColliders.transform;
}
break;
case D2D_SpriteColliderType.Polygon:
{
DestroyAutoPolygonCollider();
DestroyEdgeColliders();
if (polygonColliders == null)
{
polygonColliders = D2D_Helper.CreateGameObject("Polygon Colliders", transform).AddComponent<D2D_PolygonColliders>();
polygonColliders.RebuildAllColliders(AlphaTex);
}
colliderTransform = polygonColliders.transform;
}
break;
case D2D_SpriteColliderType.AutoPolygon:
{
DestroyPolygonColliders();
DestroyEdgeColliders();
if (autoPolygonCollider == null)
{
autoPolygonCollider = D2D_Helper.CreateGameObject("Auto Polygon Collider", transform).AddComponent<D2D_AutoPolygonCollider>();
autoPolygonCollider.RebuildCollider(AlphaTex);
}
colliderTransform = autoPolygonCollider.transform;
}
break;
}
if (colliderTransform != null)
{
var colliderScale = Vector3.one;
var colliderOffset = Vector3.zero;
if (spriteRenderer != null && AlphaTex != null)
{
var sprite = spriteRenderer.sprite;
// Magic to align the colliders with the sprite renderer
if (sprite != null)
{
colliderScale = CalculateAlphaTexScale(sprite);
colliderOffset = CalculateAlphaTexOffset(sprite);
}
}
if (colliderTransform.localPosition != colliderOffset)
{
colliderTransform.localPosition = colliderOffset;
}
if (colliderTransform.localScale != colliderScale)
{
colliderTransform.localScale = colliderScale;
}
}
}
else
{
DestroyAutoPolygonCollider();
DestroyPolygonColliders();
DestroyEdgeColliders();
}
}
private Vector3 CalculateAlphaTexScale(Sprite sprite)
{
var scale = Vector3.one;
scale.x = D2D_Helper.Divide(sprite.bounds.size.x, sprite.rect.width) * D2D_Helper.Divide(sprite.textureRect.width, AlphaTex.width);
scale.y = D2D_Helper.Divide(sprite.bounds.size.y, sprite.rect.height) * D2D_Helper.Divide(sprite.textureRect.height, AlphaTex.height);
return scale;
}
private Vector3 CalculateAlphaTexOffset(Sprite sprite)
{
var offset = Vector3.one;
offset.x = sprite.bounds.min.x + sprite.bounds.size.x * D2D_Helper.Divide(sprite.textureRectOffset.x, sprite.rect.width);
offset.y = sprite.bounds.min.y + sprite.bounds.size.y * D2D_Helper.Divide(sprite.textureRectOffset.y, sprite.rect.height);
return offset;
}
private void DestroyMaterialIfSettingsDiffer()
{
if (clonedMaterial != null)
{
if (SourceMaterial == null)
{
DestroyMaterial(); return;
}
if (clonedMaterial.shader != SourceMaterial.shader)
{
DestroyMaterial(); return;
}
}
}
private void DestroyEdgeColliders()
{
if (edgeColliders != null)
{
D2D_Helper.Destroy(edgeColliders.gameObject);
edgeColliders = null;
}
}
private void DestroyPolygonColliders()
{
if (polygonColliders != null)
{
D2D_Helper.Destroy(polygonColliders.gameObject);
polygonColliders = null;
}
}
private void DestroyAutoPolygonCollider()
{
if (autoPolygonCollider != null)
{
D2D_Helper.Destroy(autoPolygonCollider.gameObject);
autoPolygonCollider = null;
}
}
private void DestroyMaterial()
{
D2D_Helper.Destroy(clonedMaterial);
clonedMaterial = null;
}
#if UNITY_EDITOR
[UnityEditor.MenuItem("CONTEXT/SpriteRenderer/Make Destructible", true)]
private static bool MakeDestructibleValidate(UnityEditor.MenuCommand mc)
{
if (mc != null && mc.context != null)
{
var spriteRenderer = mc.context as SpriteRenderer;
if (spriteRenderer != null)
{
return spriteRenderer.GetComponent<D2D_DestructibleSprite>() == null;
}
}
return false;
}
[UnityEditor.MenuItem("CONTEXT/SpriteRenderer/Make Destructible", false)]
private static void MakeDestructible(UnityEditor.MenuCommand mc)
{
if (mc != null && mc.context != null)
{
var spriteRenderer = mc.context as SpriteRenderer;
if (spriteRenderer != null && spriteRenderer.GetComponent<D2D_DestructibleSprite>() == null)
{
UnityEditor.Undo.AddComponent<D2D_DestructibleSprite>(spriteRenderer.gameObject);
}
}
}
#endif
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6902fd9fba33c0143ad93ba6ee754d73
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,34 @@
using UnityEngine;
[ExecuteInEditMode]
[RequireComponent(typeof(D2D_DestructibleSprite))]
[RequireComponent(typeof(Rigidbody2D))]
[AddComponentMenu("Destructible 2D/D2D Dynamic Mass")]
public class D2D_DynamicMass : MonoBehaviour
{
public float MassPerPixel = 0.01f;
private D2D_DestructibleSprite destructibleSprite;
protected virtual void FixedUpdate()
{
UpdateMass();
}
protected virtual void LateUpdate()
{
UpdateMass();
}
private void UpdateMass()
{
if (destructibleSprite == null) destructibleSprite = GetComponent<D2D_DestructibleSprite>();
var newMass = destructibleSprite.SolidPixelCount * MassPerPixel;
if (GetComponent<Rigidbody2D>().mass != newMass)
{
GetComponent<Rigidbody2D>().mass = newMass;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dd1445ce7be05b54b9509f4324e485e4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,216 @@
using UnityEngine;
using System.Collections.Generic;
[ExecuteInEditMode]
[AddComponentMenu("Destructible 2D/D2D Edge Colliders")]
public class D2D_EdgeColliders : D2D_Collider
{
[System.Serializable]
public class Cell
{
public List<EdgeCollider2D> EdgeCollider2Ds = new List<EdgeCollider2D>();
public void Destroy()
{
foreach (var edgeCollider2D in EdgeCollider2Ds)
{
D2D_Helper.Destroy(edgeCollider2D);
}
EdgeCollider2Ds.Clear();
}
public void ReplaceColliders(List<EdgeCollider2D> newEdgeCollider2Ds)
{
Destroy();
EdgeCollider2Ds.AddRange(newEdgeCollider2Ds);
}
public void UpdateColliderSettings(bool isTrigger, PhysicsMaterial2D material)
{
foreach (var edgeCollider2D in EdgeCollider2Ds)
{
if (edgeCollider2D != null)
{
edgeCollider2D.isTrigger = isTrigger;
edgeCollider2D.sharedMaterial = material;
}
}
}
}
[D2D_PopupAttribute(8, 16, 32, 64, 128, 256)]
public int CellSize = 64;
[D2D_RangeAttribute(0.0f, 0.3f)]
public float Tolerance = 0.01f;
[SerializeField]
private List<Cell> cells = new List<Cell>();
[SerializeField]
private int cellsX;
[SerializeField]
private int cellsY;
[SerializeField]
private int cellsXY;
[SerializeField]
private int width;
[SerializeField]
private int height;
public void RebuildAllColliders(Texture2D alphaTex)
{
if (alphaTex != null)
{
RebuildColliders(alphaTex, 0, alphaTex.width, 0, alphaTex.height);
}
else
{
DestroyAllCells();
}
}
public void RebuildColliders(Texture2D alphaTex, int xMin, int xMax, int yMin, int yMax)
{
UpdateColliders(alphaTex);
if (cells.Count > 0)
{
//var stopwatch = System.Diagnostics.Stopwatch.StartNew();
xMin = Mathf.Clamp(xMin - 1, 0, alphaTex.width - 1);
yMin = Mathf.Clamp(yMin - 1, 0, alphaTex.height - 1);
var cellXMin = xMin / CellSize;
var cellYMin = yMin / CellSize;
var cellXMax = (xMax + CellSize - 1) / CellSize;
var cellYMax = (yMax + CellSize - 1) / CellSize;
for (var cellY = cellYMin; cellY <= cellYMax; cellY++)
{
for (var cellX = cellXMin; cellX <= cellXMax; cellX++)
{
if (cellX >= 0 && cellX < cellsX && cellY >= 0 && cellY < cellsY)
{
xMin = CellSize * cellX;
yMin = CellSize * cellY;
xMax = Mathf.Min(CellSize + xMin, alphaTex.width);
yMax = Mathf.Min(CellSize + yMin, alphaTex.height);
var cell = cells[cellX + cellY * cellsX];
var newEdgeCollider2Ds = D2D_EdgeCalculator.Generate(gameObject, alphaTex, xMin, xMax, yMin, yMax, Tolerance);
cell.ReplaceColliders(newEdgeCollider2Ds);
cell.UpdateColliderSettings(IsTrigger, Material);
}
}
}
//stopwatch.Stop(); Debug.Log("RebuildColliders took " + stopwatch.ElapsedMilliseconds + " ms");
}
}
public override void UpdateColliderSettings()
{
foreach (var cell in cells)
{
if (cell != null)
{
cell.UpdateColliderSettings(IsTrigger, Material);
}
}
}
private void UpdateColliders(Texture2D alphaTex)
{
if (alphaTex != null && alphaTex.width > 0 && alphaTex.height > 0 && CellSize > 0 && Tolerance >= 0.0f)
{
cellsX = (alphaTex.width + CellSize - 1) / CellSize;
cellsY = (alphaTex.height + CellSize - 1) / CellSize;
cellsXY = cellsX * cellsY;
if (cells.Count > 0)
{
if (cells.Count != cellsXY)
{
DestroyAllCells();
}
if (alphaTex.width != width || alphaTex.height != height)
{
DestroyAllCells();
}
}
// Rebuild all cells?
if (cells.Count == 0 && cellsXY > 0)
{
width = alphaTex.width;
height = alphaTex.height;
for (var i = 0; i < cellsXY; i++)
{
cells.Add(new Cell());
}
}
}
else
{
DestroyAllCells();
}
}
protected virtual void OnDestroy()
{
D2D_Helper.DestroyManaged(DestroyAllCells);
}
protected override void RebuildAll()
{
var destructible = D2D_Helper.GetComponentUpwards<D2D_Destructible>(transform);
if (destructible != null)
{
RebuildAllColliders(destructible.AlphaTex);
}
}
private void DestroyAllCells()
{
if (cells.Count > 0)
{
foreach (var cell in cells)
{
cell.Destroy();
}
cells.Clear();
}
}
#if UNITY_EDITOR
protected override void SetHideFlags(HideFlags hideFlags)
{
foreach (var cell in cells)
{
foreach (var edgeCollider2D in cell.EdgeCollider2Ds)
{
if (edgeCollider2D != null)
{
edgeCollider2D.hideFlags = hideFlags;
}
}
}
}
#else
protected override void SetHideFlags(HideFlags hideFlags)
{
}
#endif
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: df82a8b85d0c7a241a904864275dc63c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,58 @@
using UnityEngine;
[AddComponentMenu("Destructible 2D/D2D Explosion Damage")]
public class D2D_ExplosionDamage : MonoBehaviour
{
public LayerMask Layers = -1;
public float Radius = 1.0f;
public float Damage = 10.0f;
public int Samples = 32;
public bool HasExploded;
protected virtual void Update()
{
if (HasExploded == false)
{
HasExploded = true;
Explode();
}
}
public void Explode()
{
if (Samples > 0)
{
var origin = transform.position;
var step = 360.0f / Samples;
var scaledDamage = Damage / Samples;
for (var i = 0; i < Samples; i++)
{
var angle = i * step;
var direction = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle));
var hit = Physics2D.Raycast(origin, direction, Radius);
var collider = hit.collider;
if (collider != null && collider.isTrigger == false)
{
var mask = 1 << collider.gameObject.layer;
if ((mask & Layers.value) != 0)
{
var damageableSprite = D2D_Helper.GetComponentUpwards<D2D_DamageableSprite>(collider.transform);
if (damageableSprite != null)
{
damageableSprite.InflictDamage(scaledDamage);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 856de3ca546c49448b24dcb5151b45fb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,55 @@
using UnityEngine;
[AddComponentMenu("Destructible 2D/D2D Explosion Force")]
public class D2D_ExplosionForce : MonoBehaviour
{
public LayerMask Layers = -1;
public float Radius = 1.0f;
public float Force = 1.0f;
public int Samples = 32;
public bool HasExploded;
protected virtual void Update()
{
if (HasExploded == false)
{
HasExploded = true;
Explode();
}
}
public void Explode()
{
if (Samples > 0)
{
var origin = transform.position;
var step = 360.0f / Samples;
var scaledForce = Force / Samples;
for (var i = 0; i < Samples; i++)
{
var angle = i * step;
var direction = new Vector2(Mathf.Sin(angle), Mathf.Cos(angle));
var hit = Physics2D.Raycast(origin, direction, Radius);
var collider = hit.collider;
if (collider != null && collider.isTrigger == false && collider.attachedRigidbody != null)
{
var mask = 1 << collider.gameObject.layer;
if ((mask & Layers.value) != 0)
{
var force = direction * scaledForce * (1.0f - hit.fraction);
hit.collider.attachedRigidbody.AddForceAtPosition(force, origin);
}
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 30cd04bd1fefc174b811f74241da78b1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,36 @@
using UnityEngine;
[AddComponentMenu("Destructible 2D/D2D Explosion Stamp")]
public class D2D_ExplosionStamp : MonoBehaviour
{
public LayerMask Layers = -1;
public Texture2D StampTex;
public float Hardness = 1.0f;
public Vector2 Size = Vector2.one;
public float AngleOffset;
public float AngleRandomness;
public bool HasExploded;
protected virtual void Update()
{
if (HasExploded == false)
{
HasExploded = true;
Explode();
}
}
public void Explode()
{
var angle = transform.rotation.eulerAngles.z + AngleOffset + Random.Range(-0.5f, 0.5f) * AngleRandomness;
D2D_Destructible.StampAll(transform.position, Size, angle, StampTex, Hardness, Layers);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6bbea72cf307518469cf0d6eb4291f0d
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,116 @@
using UnityEngine;
using System.Collections.Generic;
[AddComponentMenu("Destructible 2D/D2D Fixture")]
public class D2D_Fixture : MonoBehaviour
{
public static List<D2D_Fixture> Fixtures = new List<D2D_Fixture>();
[D2D_RangeAttribute(0.01f, 1.0f)]
public float Threshold = 0.5f;
private D2D_Destructible destructible;
private bool dirty = true;
[SerializeField]
private int fixtureID;
private static int nextFixtureID = 1;
protected virtual void OnSpriteSplit(bool isClone)
{
// Assign a fixtureID to the parent, this will be copied to the clones
if (isClone == false)
{
if (nextFixtureID > 1000000)
{
nextFixtureID = 1;
}
else
{
nextFixtureID += 1;
}
fixtureID = nextFixtureID;
}
dirty = true;
}
protected virtual void OnAlphaTexModified()
{
dirty = true;
}
protected virtual void OnEnable()
{
Fixtures.Add(this);
}
protected virtual void OnDisable()
{
Fixtures.Remove(this);
}
protected virtual void Update()
{
if (dirty == true)
{
dirty = false;
destructible = D2D_Helper.GetComponentUpwards<D2D_Destructible>(transform);
if (destructible != null)
{
var alpha = destructible.GetAlpha(transform.position);
// Break fixture?
if (alpha < Threshold)
{
DestroyFixture();
}
// Break others?
else if (fixtureID > 0)
{
for (var i = Fixtures.Count - 1; i >= 0; i--)
{
var fixture = Fixtures[i];
if (fixture != null && fixture != this && fixture.fixtureID == fixtureID)
{
fixture.DestroyFixture();
}
}
}
}
}
}
public static D2D_Fixture FindFixture(string name, Transform transform)
{
if (transform != null)
{
var destructible = transform.GetComponentInParent<D2D_Destructible>();
if (destructible != null)
{
var fixtures = destructible.GetComponentsInChildren<D2D_Fixture>();
foreach (var fixture in fixtures)
{
if (fixture.name == name)
{
return fixture;
}
}
}
}
return null;
}
private void DestroyFixture()
{
D2D_Helper.Destroy(gameObject);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2bbefba9614e86b48a23d7d563b245a9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,217 @@
using UnityEngine;
using System.Collections.Generic;
[ExecuteInEditMode]
[AddComponentMenu("Destructible 2D/D2D Polygon Colliders")]
public class D2D_PolygonColliders : D2D_Collider
{
[System.Serializable]
public class Cell
{
public PolygonCollider2D PolygonCollider2D;
public void Destroy()
{
if (PolygonCollider2D != null)
{
D2D_Helper.Destroy(PolygonCollider2D);
PolygonCollider2D = null;
}
}
public void ReplaceCollider(PolygonCollider2D newPolygonCollider2D)
{
if (PolygonCollider2D != newPolygonCollider2D)
{
Destroy();
PolygonCollider2D = newPolygonCollider2D;
}
}
public void UpdateColliderSettings(bool isTrigger, PhysicsMaterial2D material)
{
if (PolygonCollider2D != null)
{
PolygonCollider2D.isTrigger = isTrigger;
PolygonCollider2D.sharedMaterial = material;
}
}
}
[D2D_PopupAttribute(8, 16, 32, 64, 128, 256)]
public int CellSize = 64;
[D2D_RangeAttribute(0.0f, 0.6f)]
public float Tolerance = 0.1f;
[SerializeField]
private List<Cell> cells = new List<Cell>();
[SerializeField]
private int cellsX;
[SerializeField]
private int cellsY;
[SerializeField]
private int cellsXY;
[SerializeField]
private int width;
[SerializeField]
private int height;
public void RebuildAllColliders(Texture2D alphaTex)
{
if (alphaTex != null)
{
RebuildColliders(alphaTex, 0, alphaTex.width, 0, alphaTex.height);
}
else
{
DestroyAllCells();
}
}
public void RebuildColliders(Texture2D alphaTex, int xMin, int xMax, int yMin, int yMax)
{
UpdateColliders(alphaTex);
if (cells.Count > 0)
{
//var stopwatch = System.Diagnostics.Stopwatch.StartNew();
xMin = Mathf.Clamp(xMin - 1, 0, alphaTex.width - 1);
yMin = Mathf.Clamp(yMin - 1, 0, alphaTex.height - 1);
var cellXMin = xMin / CellSize;
var cellYMin = yMin / CellSize;
var cellXMax = (xMax + CellSize - 1) / CellSize;
var cellYMax = (yMax + CellSize - 1) / CellSize;
for (var cellY = cellYMin; cellY <= cellYMax; cellY++)
{
for (var cellX = cellXMin; cellX <= cellXMax; cellX++)
{
if (cellX >= 0 && cellX < cellsX && cellY >= 0 && cellY < cellsY)
{
xMin = CellSize * cellX;
yMin = CellSize * cellY;
xMax = Mathf.Min(CellSize + xMin, alphaTex.width);
yMax = Mathf.Min(CellSize + yMin, alphaTex.height);
var cell = cells[cellX + cellY * cellsX];
var newPolygonCollider2D = D2D_PolygonCalculator.Generate(gameObject, cell.PolygonCollider2D, alphaTex, xMin, xMax, yMin, yMax, Tolerance);
cell.ReplaceCollider(newPolygonCollider2D);
cell.UpdateColliderSettings(IsTrigger, Material);
}
}
}
//stopwatch.Stop(); Debug.Log("RebuildColliders took " + stopwatch.ElapsedMilliseconds + " ms");
}
}
public override void UpdateColliderSettings()
{
foreach (var cell in cells)
{
if (cell != null)
{
cell.UpdateColliderSettings(IsTrigger, Material);
}
}
}
private void UpdateColliders(Texture2D alphaTex)
{
if (alphaTex != null && alphaTex.width > 0 && alphaTex.height > 0 && CellSize > 0 && Tolerance >= 0.0f)
{
cellsX = (alphaTex.width + CellSize - 1) / CellSize;
cellsY = (alphaTex.height + CellSize - 1) / CellSize;
cellsXY = cellsX * cellsY;
if (cells.Count > 0)
{
if (cells.Count != cellsXY)
{
DestroyAllCells();
}
if (alphaTex.width != width || alphaTex.height != height)
{
DestroyAllCells();
}
}
// Rebuild all cells?
if (cells.Count == 0 && cellsXY > 0)
{
width = alphaTex.width;
height = alphaTex.height;
for (var i = 0; i < cellsXY; i++)
{
cells.Add(new Cell());
}
}
}
else
{
DestroyAllCells();
}
}
protected virtual void OnDestroy()
{
D2D_Helper.DestroyManaged(DestroyAllCells);
}
protected override void RebuildAll()
{
var destructible = D2D_Helper.GetComponentUpwards<D2D_Destructible>(transform);
if (destructible != null)
{
RebuildAllColliders(destructible.AlphaTex);
}
}
private void DestroyAllCells()
{
if (cells.Count > 0)
{
foreach (var cell in cells)
{
cell.Destroy();
}
cells.Clear();
#if UNITY_EDITOR
D2D_Helper.SetDirty(this);
#endif
}
}
#if UNITY_EDITOR
protected override void SetHideFlags(HideFlags hideFlags)
{
foreach (var cell in cells)
{
if (cell.PolygonCollider2D != null)
{
cell.PolygonCollider2D.hideFlags = hideFlags;
}
}
}
#else
protected override void SetHideFlags(HideFlags hideFlags)
{
}
#endif
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 70f8987444db4274e808235343cdada3
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,11 @@
using UnityEngine;
public class D2D_RuntimeSprite : MonoBehaviour
{
public Sprite Sprite;
protected virtual void OnDestroy()
{
D2D_Helper.Destroy(Sprite);
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d4fbb12d5c9357249a0d858dfe2a30ac
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData: