UI update 02
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2af252442079b524e97d60543408a92f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[Serializable]
|
||||
public class CircleDestruction : Destruction
|
||||
{
|
||||
public float radius = 0.3f;
|
||||
EllipseDestruction e;
|
||||
public override void Setup(GameObject gobj)
|
||||
{
|
||||
e.Setup(gobj);
|
||||
}
|
||||
public override void SetupWithColor(GameObject gobj, Color color)
|
||||
{
|
||||
Setup(gobj);
|
||||
burnColor = color;
|
||||
}
|
||||
public override void ApplyDestruction(int cx, int cy, bool[,] mask, float stepX, float stepY,int maskW,int maskH,Color32[]burnage, float burntime)
|
||||
{
|
||||
e.rx = radius;
|
||||
e.ry = radius;
|
||||
e.ApplyDestruction(cx,cy,mask,stepX,stepY,maskW,maskH,burnage,burntime);
|
||||
}
|
||||
public CircleDestruction()
|
||||
{
|
||||
e = new EllipseDestruction();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c38b0a6170f7b7b419c3c2c0ad2acf89
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Destruction Types/CircleDestruction.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[Serializable]
|
||||
public class EllipseDestruction : Destruction
|
||||
{
|
||||
public float rx = 0.3f;
|
||||
public float ry = 0.3f;
|
||||
Sprite sprite;
|
||||
float normalX;
|
||||
float normalY;
|
||||
List<int> destroyed = new();
|
||||
public override void Setup(GameObject gobj)
|
||||
{
|
||||
SpriteRenderer sprend = gobj.GetComponent<SpriteRenderer>();
|
||||
sprite = sprend.sprite;
|
||||
normalX=gobj.transform.localScale.x;
|
||||
normalY=gobj.transform.localScale.y;
|
||||
|
||||
}
|
||||
public override void SetupWithColor(GameObject gobj, Color color)
|
||||
{
|
||||
Setup(gobj);
|
||||
burnColor = color;
|
||||
}
|
||||
public override void ApplyDestruction(int cx, int cy, bool[,] mask, float stepX, float stepY,int maskW,int maskH,Color32[] burnage, float burntime)
|
||||
{
|
||||
destroyed.Clear();
|
||||
float rpx = rx * sprite.pixelsPerUnit/normalX;
|
||||
float rpy = ry * sprite.pixelsPerUnit/normalY;
|
||||
int cmx = Mathf.FloorToInt(cx/stepX);
|
||||
int cmy = Mathf.FloorToInt(cy/stepY);
|
||||
int rmx = (int)(rpx/stepX);
|
||||
int rmy = (int)(rpy/stepY);
|
||||
for (int i = cmx - rmx; i <= cmx + rmx; i++){
|
||||
if(i >= maskW || i < 0) continue;
|
||||
|
||||
float dx = i - cmx;
|
||||
float nx = dx/rmx;
|
||||
for (int j = cmy - rmy; j <= cmy + rmy; j++)
|
||||
{
|
||||
if (j < 0 ||j >= maskH) continue;
|
||||
|
||||
float dy = j - cmy;
|
||||
float ny = dy/rmy;
|
||||
|
||||
if (nx * nx + ny * ny <= 1f){
|
||||
mask[i, j] = false;
|
||||
destroyed.Add(j * maskW + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
BurnEdge(destroyed,maskW,maskH,mask,burnage,burntime);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85cc06dd67d78f847b096890f2223790
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Destruction Types/EllipseDestruction.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[Serializable]
|
||||
public class RectDestruction : Destruction
|
||||
{
|
||||
public float l = 0.3f;
|
||||
public float b = 0.3f;
|
||||
Sprite sprite;
|
||||
List<int> destroyed = new();
|
||||
float normalX;
|
||||
float normalY;
|
||||
public override void Setup(GameObject gobj)
|
||||
{
|
||||
SpriteRenderer sprend = gobj.GetComponent<SpriteRenderer>();
|
||||
sprite = sprend.sprite;
|
||||
normalX=gobj.transform.localScale.x;
|
||||
normalY=gobj.transform.localScale.y;
|
||||
|
||||
}
|
||||
public override void SetupWithColor(GameObject gobj, Color color)
|
||||
{
|
||||
Setup(gobj);
|
||||
burnColor = color;
|
||||
}
|
||||
public override void ApplyDestruction(int cx, int cy, bool[,] mask, float stepX, float stepY,int maskW,int maskH,Color32[] burnage, float burntime)
|
||||
{
|
||||
destroyed.Clear();
|
||||
float lp = l * sprite.pixelsPerUnit/normalX;
|
||||
float bp = b * sprite.pixelsPerUnit/normalY;
|
||||
int cmx = Mathf.FloorToInt(cx/stepX);
|
||||
int cmy = Mathf.FloorToInt(cy/stepY);
|
||||
int lm = (int)(lp/stepX);
|
||||
int bm = (int)(bp/stepY);
|
||||
|
||||
for (int i = cmx - lm; i <= cmx + lm; i++){
|
||||
if(i >= maskW || i < 0) continue;
|
||||
for (int j = cmy - bm; j <= cmy + bm; j++)
|
||||
{
|
||||
if (j < 0 ||j >= maskH) continue;
|
||||
mask[i, j] = false;
|
||||
destroyed.Add(j * maskW + i);
|
||||
}
|
||||
}
|
||||
BurnEdge(destroyed,maskW,maskH,mask,burnage,burntime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59ed6c62a15ec3141998da30fc21c102
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Destruction Types/RectDestruction.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,77 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[Serializable]
|
||||
public class StampDestruction : Destruction
|
||||
{
|
||||
public Texture2D stampTexture;
|
||||
public float scaleFactor;
|
||||
public float rotationAngle;
|
||||
private int stampWidth;
|
||||
private int stampHeight;
|
||||
private Color[] stampPixels;
|
||||
float normalX;
|
||||
float normalY;
|
||||
List<int> destroyed = new();
|
||||
public override void Setup(GameObject gobj)
|
||||
{
|
||||
stampWidth = stampTexture.width;
|
||||
stampHeight = stampTexture.height;
|
||||
stampPixels = stampTexture.GetPixels();
|
||||
normalX = gobj.transform.localScale.x;
|
||||
normalY = gobj.transform.localScale.y;
|
||||
}
|
||||
public override void SetupWithColor(GameObject gobj, Color color)
|
||||
{
|
||||
Setup(gobj);
|
||||
burnColor = color;
|
||||
}
|
||||
public override void ApplyDestruction(int cx, int cy, bool [,] mask, float stepX, float stepY,int maskW,int maskH,Color32[] burnage, float burntime)
|
||||
{
|
||||
destroyed.Clear();
|
||||
float rotRad = rotationAngle * Mathf.Deg2Rad;
|
||||
int cmx = Mathf.FloorToInt(cx / stepX);
|
||||
int cmy = Mathf.FloorToInt(cy / stepY);
|
||||
int sw = Mathf.FloorToInt(stampWidth /(scaleFactor*normalX * stepX));
|
||||
int sh = Mathf.FloorToInt(stampHeight /(scaleFactor*normalY * stepY));
|
||||
float c = Mathf.Cos(rotRad);
|
||||
float s = Mathf.Sin(rotRad);
|
||||
|
||||
for(int i = 0; i< sw; i++)
|
||||
{
|
||||
int x = cmx + i - sw/2; //offsetting to centre (-sw/2)
|
||||
|
||||
if(x < 0 || x >= maskW) continue;
|
||||
for(int j = 0; j < sh; j++)
|
||||
{
|
||||
int y = cmy + j - sh/2;
|
||||
if(y < 0 || y>=maskH) continue;
|
||||
float dx = i - 0.5f * sw;//make x and y centred(-ve and +ve around midpoint)
|
||||
float dy = j - 0.5f * sh;
|
||||
float ux = dx * stepX * scaleFactor * normalX;
|
||||
float uy = dy * stepY * scaleFactor * normalY;
|
||||
float rx = ux * c - uy * s;
|
||||
float ry = ux * s + uy * c;
|
||||
|
||||
int px = Mathf.FloorToInt(rx + stampWidth * 0.5f);
|
||||
int py = Mathf.FloorToInt(ry + stampHeight * 0.5f);
|
||||
|
||||
if(px < 0|| py < 0 || px >= stampWidth|| py >= stampHeight) continue;
|
||||
|
||||
int indx = py * stampWidth + px;
|
||||
|
||||
|
||||
if(stampPixels[indx].a > 0.1f)
|
||||
{
|
||||
mask[x,y] = false;
|
||||
destroyed.Add(y * maskW + x);
|
||||
}
|
||||
}
|
||||
}
|
||||
BurnEdge(destroyed,maskW,maskH,mask,burnage,burntime);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 623659f1a080fc54a97298c5b8e07174
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Destruction Types/StampDestruction.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: caeb7972101235344a85482afc9d5ae1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,361 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace KD.Destro2D{
|
||||
[RequireComponent(typeof(PolygonCollider2D))]
|
||||
[RequireComponent(typeof(PixelHandler))]
|
||||
public class CollisionHandler : MonoBehaviour
|
||||
{
|
||||
|
||||
public int maskWidth = 64;
|
||||
public int maskHeight = 64;
|
||||
public bool HasInit()=>init;
|
||||
|
||||
Color[] rectPixels;
|
||||
float stepX;
|
||||
float stepY;
|
||||
bool[,] collisionMask;
|
||||
PolygonCollider2D polyCollider;
|
||||
PixelHandler pHandler;
|
||||
SpriteRenderer sprend;
|
||||
public Vector2[,] posGrid{get;private set;}
|
||||
List<(Vector2,Vector2)> segments = new();
|
||||
float cellWidth,cellHeight;
|
||||
bool init = false;
|
||||
public bool collisionDebug = false;
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void InitialiseCollision()//initialise only after pixel handler initialises
|
||||
{
|
||||
if(HasInit()) return;
|
||||
pHandler = GetComponent<PixelHandler>();
|
||||
sprend = GetComponent<SpriteRenderer>();
|
||||
polyCollider = GetComponent<PolygonCollider2D>();
|
||||
|
||||
if (!pHandler.HasInit())
|
||||
{
|
||||
Debug.LogWarning("Has not initialised visuals before collisions! Quitting.");
|
||||
return;
|
||||
}
|
||||
rectPixels = pHandler.rectPixels;
|
||||
int texWidth = sprend.sprite.texture.width;
|
||||
int texHeight = sprend.sprite.texture.height;
|
||||
stepX = (float)texWidth/maskWidth;
|
||||
stepY = (float)texHeight/maskHeight;
|
||||
BuildCollisionMask(texWidth,texHeight);
|
||||
Make2DLocalGrid();
|
||||
segments.Clear();
|
||||
pHandler.SyncToVisual(collisionMask,maskWidth,maskHeight);
|
||||
MarchingSquares();
|
||||
pHandler.DoStuffOnVisualUpdate+=CollisionUpdater;
|
||||
init = true;
|
||||
}
|
||||
|
||||
void BuildCollisionMask(int texwidth, int texheight)
|
||||
{
|
||||
collisionMask = new bool[maskWidth, maskHeight];
|
||||
posGrid = new Vector2[maskWidth,maskHeight];
|
||||
|
||||
for(int i = 0; i < maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
int px = (int)(i * stepX);
|
||||
int py = (int)(j * stepY);
|
||||
if(px < 0||py<0||px>=texwidth||py>=texheight) continue;
|
||||
collisionMask[i,j] = rectPixels[py * texwidth + px].a > 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void Make2DLocalGrid()
|
||||
{
|
||||
Bounds b = sprend.sprite.bounds;
|
||||
|
||||
Vector2 origin = b.min;
|
||||
cellWidth = b.size.x/maskWidth;
|
||||
cellHeight = b.size.y/maskHeight;
|
||||
|
||||
for(int i = 0; i < maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
Vector2 pos = origin + new Vector2(i * cellWidth, j * cellHeight);
|
||||
posGrid[i,j] = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
void CollisionUpdater()
|
||||
{
|
||||
segments.Clear();
|
||||
pHandler.SyncToVisual(collisionMask,maskWidth,maskHeight);
|
||||
MarchingSquares();
|
||||
}
|
||||
|
||||
void MarchingSquares() //determines collider edges and calls function to build collider
|
||||
{
|
||||
for(int i = -1; i <= maskWidth; i++)
|
||||
{
|
||||
for(int j = -1; j <= maskHeight; j++)
|
||||
{
|
||||
//anti clockwise
|
||||
bool c1 = GetMask(i,j);
|
||||
bool c2 = GetMask(i+1,j);
|
||||
bool c3 = GetMask(i+1,j+1);
|
||||
bool c4 = GetMask(i,j+1);
|
||||
|
||||
int val = (c1 ? 1:0)+(c2 ? 2:0)+(c3 ? 4:0)+(c4 ? 8:0);
|
||||
|
||||
if(val == 0 || val == 15) continue;
|
||||
|
||||
Vector2 p00 = GetPos(i, j);
|
||||
Vector2 p10 = GetPos(i+1, j);
|
||||
Vector2 p11 = GetPos(i+1, j+1);
|
||||
Vector2 p01 = GetPos(i, j+1);
|
||||
|
||||
Vector2 M(Vector2 a, Vector2 b) => (a + b) * 0.5f;
|
||||
switch (val)
|
||||
{
|
||||
case 1:
|
||||
segments.Add((M(p00, p01), M(p00, p10)));
|
||||
break;
|
||||
|
||||
case 2:
|
||||
segments.Add((M(p00, p10), M(p10, p11)));
|
||||
break;
|
||||
|
||||
case 3:
|
||||
segments.Add((M(p00, p01), M(p10, p11)));
|
||||
break;
|
||||
|
||||
case 4:
|
||||
segments.Add((M(p10, p11), M(p01, p11)));
|
||||
break;
|
||||
|
||||
case 5:
|
||||
segments.Add((M(p00, p10), M(p01, p11)));
|
||||
break;
|
||||
|
||||
case 6:
|
||||
segments.Add((M(p00, p10), M(p01, p11)));
|
||||
break;
|
||||
|
||||
case 7:
|
||||
segments.Add((M(p00, p01), M(p01, p11)));
|
||||
break;
|
||||
|
||||
case 8:
|
||||
segments.Add((M(p01, p11), M(p00, p01)));
|
||||
break;
|
||||
|
||||
case 9:
|
||||
segments.Add((M(p01, p11), M(p00, p10)));
|
||||
break;
|
||||
|
||||
case 10:
|
||||
segments.Add((M(p10, p11), M(p00, p01)));
|
||||
break;
|
||||
|
||||
case 11:
|
||||
segments.Add((M(p01, p11), M(p11, p10)));
|
||||
break;
|
||||
|
||||
case 12:
|
||||
segments.Add((M(p00, p01), M(p10, p11)));
|
||||
break;
|
||||
|
||||
case 13:
|
||||
segments.Add((M(p10, p11), M(p00, p10)));
|
||||
break;
|
||||
|
||||
case 14:
|
||||
segments.Add((M(p00, p10), M(p01, p00)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
BuildCollider();
|
||||
}
|
||||
|
||||
bool GetMask(int x, int y)
|
||||
{
|
||||
if(x < 0 || y < 0 || x >= maskWidth || y >= maskHeight)
|
||||
return false;
|
||||
return collisionMask[x,y];
|
||||
}
|
||||
Vector2 GetPos(int x, int y)
|
||||
{
|
||||
int cx = Mathf.Clamp(x,0,maskWidth-1);
|
||||
int cy = Mathf.Clamp(y,0,maskHeight-1);
|
||||
|
||||
Vector2 pos = posGrid[cx,cy];
|
||||
|
||||
if(x < 0)
|
||||
{
|
||||
pos.x -= cellWidth;
|
||||
}else if(x >= maskWidth)
|
||||
{
|
||||
pos.x += cellWidth;
|
||||
}
|
||||
if(y < 0)
|
||||
{
|
||||
pos.y -= cellHeight;
|
||||
}else if(y >= maskHeight)
|
||||
{
|
||||
pos.y += cellHeight;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
void BuildCollider()
|
||||
{
|
||||
float snap = 0.001f;
|
||||
Vector2 Snap(Vector2 v)
|
||||
{
|
||||
return new Vector2(
|
||||
Mathf.Round(v.x / snap) * snap,
|
||||
Mathf.Round(v.y / snap) * snap
|
||||
);
|
||||
}
|
||||
Dictionary<Vector2, List<Vector2>> graph = new();
|
||||
|
||||
foreach (var seg in segments)
|
||||
{
|
||||
Vector2 a = Snap(seg.Item1);
|
||||
Vector2 b = Snap(seg.Item2);
|
||||
|
||||
if (!graph.ContainsKey(a)) graph[a] = new();
|
||||
if (!graph.ContainsKey(b)) graph[b] = new();
|
||||
|
||||
graph[a].Add(b);
|
||||
graph[b].Add(a);
|
||||
}
|
||||
|
||||
if (graph.Count == 0)
|
||||
{
|
||||
polyCollider.pathCount = 0;
|
||||
return;
|
||||
}
|
||||
HashSet<Vector2> vis = new();
|
||||
List<List<Vector2>> loops = new();
|
||||
foreach(var start in graph.Keys)
|
||||
{
|
||||
if(vis.Contains(start)) continue;
|
||||
var l = Looper(start,graph,vis);
|
||||
if(l.Count >= 3)
|
||||
loops.Add(l);
|
||||
}
|
||||
polyCollider.pathCount = loops.Count;
|
||||
|
||||
for (int i = 0; i < loops.Count; i++)
|
||||
{
|
||||
Vector2[] local = new Vector2[loops[i].Count];
|
||||
for (int j = 0; j < loops[i].Count; j++)
|
||||
{
|
||||
local[j] = loops[i][j];
|
||||
}
|
||||
polyCollider.SetPath(i, local);
|
||||
}
|
||||
}
|
||||
List<Vector2> Looper(Vector2 start, Dictionary<Vector2, List<Vector2>> graph, HashSet<Vector2> visited)
|
||||
{
|
||||
List<Vector2> loop = new();
|
||||
Vector2 current = start;
|
||||
Vector2 prev = new(float.NaN, float.NaN);
|
||||
loop.Add(current);
|
||||
int count = 0;
|
||||
while (true)
|
||||
{
|
||||
visited.Add(current);
|
||||
bool moved = false;
|
||||
foreach(var n in graph[current])
|
||||
{
|
||||
|
||||
if (prev != n && !visited.Contains(n))
|
||||
{
|
||||
prev = current;
|
||||
current = n;
|
||||
loop.Add(current);
|
||||
moved = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!moved)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
count ++;
|
||||
if(count > 1000) break;
|
||||
|
||||
}
|
||||
|
||||
return loop;
|
||||
}
|
||||
|
||||
public Vector2 GetPosOnDifferent(int x, int y, int mWidth, int mHeight)
|
||||
{
|
||||
float stepX = maskWidth/mWidth;
|
||||
float stepY = maskHeight/mHeight;
|
||||
|
||||
int mx = Mathf.FloorToInt(x * stepX);
|
||||
int my = Mathf.FloorToInt(y * stepY);
|
||||
if(mx < 0||my<0||mx>=maskWidth||my>=maskHeight){
|
||||
throw new IndexOutOfRangeException("Position out of bounds");
|
||||
}
|
||||
return posGrid[mx,my];
|
||||
|
||||
}
|
||||
|
||||
//only for visualising collision mask and edges
|
||||
void OnDrawGizmosSelected()
|
||||
{
|
||||
|
||||
if(!sprend || !collisionDebug || !HasInit()) return;
|
||||
Bounds b = sprend.sprite.bounds;
|
||||
Vector2 origin = b.min;
|
||||
|
||||
for (int x = 0; x < maskWidth; x++)
|
||||
{
|
||||
for (int y = 0; y < maskHeight; y++)
|
||||
{
|
||||
if (!collisionMask[x, y]) continue;
|
||||
|
||||
Vector2 center = origin + new Vector2(
|
||||
x * cellWidth + cellWidth * 0.5f,
|
||||
y * cellHeight + cellHeight * 0.5f
|
||||
);
|
||||
Vector3 centerWorld = transform.TransformPoint(center);
|
||||
Gizmos.color = Color.green;
|
||||
Gizmos.DrawCube(centerWorld, new Vector3(cellWidth * 0.9f * transform.localScale.x, cellHeight * 0.9f * transform.localScale.y, 0.01f));
|
||||
}
|
||||
}
|
||||
if (segments == null)
|
||||
return;
|
||||
|
||||
Gizmos.color = Color.blue;
|
||||
|
||||
foreach (var seg in segments)
|
||||
{
|
||||
Vector3 A = transform.TransformPoint(seg.Item1);
|
||||
Vector3 B = transform.TransformPoint(seg.Item2);
|
||||
|
||||
Gizmos.DrawLine(A, B);
|
||||
Gizmos.DrawSphere(A, 0.01f);
|
||||
Gizmos.DrawSphere(B, 0.01f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6483c7bdbae77c4186cbd3b87097918
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Main/CollisionHandler.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,175 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[RequireComponent(typeof(PixelHandler))]
|
||||
[RequireComponent(typeof(CollisionHandler))]
|
||||
[RequireComponent(typeof(SplitHandler))]
|
||||
public class Destro2DMain : MonoBehaviour
|
||||
{
|
||||
[SerializeReference]
|
||||
public List<Destruction> destructionList = new();
|
||||
|
||||
PixelHandler pHandler;
|
||||
SpriteRenderer sprend;
|
||||
CollisionHandler cHandler;
|
||||
SplitHandler sHandler;
|
||||
CircleDestruction fracture;
|
||||
public Action<Vector2> OnDestruction;
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void OnEnable()
|
||||
{
|
||||
Initialise();
|
||||
fracture = new();
|
||||
fracture.Setup(this.gameObject);
|
||||
}
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
public void DynamicDestroyWorld(Vector2 world)
|
||||
{
|
||||
Vector2 loc = transform.InverseTransformPoint(world);
|
||||
(int cx, int cy) = Destruction.LocToPixel(loc,sprend);
|
||||
foreach(Destruction d in destructionList)
|
||||
{
|
||||
pHandler.DestroyMask(d,cx,cy);
|
||||
}
|
||||
OnDestruction?.Invoke(world);
|
||||
|
||||
}
|
||||
public void DynamicDestroyLocal(Vector2 loc)
|
||||
{
|
||||
(int cx, int cy) = Destruction.LocToPixel(loc,sprend);
|
||||
foreach(Destruction d in destructionList)
|
||||
{
|
||||
pHandler.DestroyMask(d,cx,cy);
|
||||
}
|
||||
OnDestruction?.Invoke(loc);
|
||||
|
||||
}
|
||||
|
||||
public void DynamicDestroyLocal(Vector2 loc, List<Destruction> dlist)
|
||||
{
|
||||
(int cx, int cy) = Destruction.LocToPixel(loc,sprend);
|
||||
foreach(Destruction d in dlist)
|
||||
{
|
||||
pHandler.DestroyMask(d,cx,cy);
|
||||
}
|
||||
OnDestruction?.Invoke(loc);
|
||||
|
||||
}
|
||||
|
||||
public void DynamicDestroyWorld(Vector2 world, List<Destruction> dlist)
|
||||
{
|
||||
Vector2 loc = transform.InverseTransformPoint(world);
|
||||
(int cx, int cy) = Destruction.LocToPixel(loc,sprend);
|
||||
foreach(Destruction d in dlist)
|
||||
{
|
||||
pHandler.DestroyMask(d,cx,cy);
|
||||
}
|
||||
OnDestruction?.Invoke(world);
|
||||
}
|
||||
|
||||
public void DynamicFracture(Vector2 world, float Rcore, float Router, float noiseScale,float thickness, int lines)
|
||||
{
|
||||
Vector2 loc = transform.InverseTransformPoint(world);
|
||||
(int cx, int cy) = Destruction.LocToPixel(loc,sprend);
|
||||
fracture.radius = thickness;
|
||||
float seed = UnityEngine.Random.Range(10,100);
|
||||
float step = 0.1f;
|
||||
float[] angles = new float[lines];
|
||||
for (int i = 0; i < lines; i++)
|
||||
{
|
||||
angles[i] = i * Mathf.PI * 2f / lines
|
||||
+ UnityEngine.Random.Range(-20, 20) * Mathf.Deg2Rad;
|
||||
}
|
||||
|
||||
|
||||
float bendStrength = 1.5f * Mathf.Deg2Rad;
|
||||
|
||||
foreach (float baseAngle in angles)
|
||||
{
|
||||
float angle = baseAngle;
|
||||
|
||||
for (float r = Rcore; r <= Router; r += step)
|
||||
{
|
||||
Vector2 dir = new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
|
||||
Vector2 p = world + dir * r;
|
||||
|
||||
float wobble = Mathf.PerlinNoise(
|
||||
(p.x * noiseScale) + seed,
|
||||
(p.y * noiseScale) + seed
|
||||
) * 2f - 1f;
|
||||
|
||||
angle += wobble * bendStrength;
|
||||
|
||||
FractureHelper(p,thickness);
|
||||
}
|
||||
}
|
||||
OnDestruction?.Invoke(world);
|
||||
|
||||
}
|
||||
public void Initialise()
|
||||
{
|
||||
pHandler = GetComponent<PixelHandler>();
|
||||
sprend = GetComponent<SpriteRenderer>();
|
||||
cHandler = GetComponent<CollisionHandler>();
|
||||
sHandler = GetComponent<SplitHandler>();
|
||||
pHandler.Initialise();
|
||||
cHandler.InitialiseCollision();
|
||||
sHandler.InitialiseSplit();
|
||||
foreach(Destruction d in destructionList)
|
||||
{
|
||||
d.Setup(this.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddStampDestruction(Texture2D stampTex, float scale, float rot)
|
||||
{
|
||||
StampDestruction stmp = new StampDestruction();
|
||||
stmp.stampTexture = stampTex;
|
||||
stmp.scaleFactor = scale;
|
||||
stmp.rotationAngle = rot;
|
||||
stmp.Setup(this.gameObject);
|
||||
destructionList.Add(stmp);
|
||||
}
|
||||
public void AddCircleDestruction(float radius)
|
||||
{
|
||||
CircleDestruction cd = new CircleDestruction();
|
||||
cd.radius = radius;
|
||||
cd.Setup(this.gameObject);
|
||||
destructionList.Add(cd);
|
||||
}
|
||||
public void AddEllipseDestruction(float radiusX, float radiusY)
|
||||
{
|
||||
EllipseDestruction ed = new EllipseDestruction();
|
||||
ed.rx = radiusX;
|
||||
ed.ry = radiusY;
|
||||
ed.Setup(this.gameObject);
|
||||
destructionList.Add(ed);
|
||||
}
|
||||
public void AddRectDestruction(float l, float b)
|
||||
{
|
||||
RectDestruction rd = new RectDestruction();
|
||||
rd.l = l;
|
||||
rd.b = b;
|
||||
rd.Setup(this.gameObject);
|
||||
destructionList.Add(rd);
|
||||
}
|
||||
public void InheritDestruction(GameObject src)
|
||||
{
|
||||
if(src.TryGetComponent<Destro2DMain>(out var d))
|
||||
{
|
||||
destructionList = d.destructionList;
|
||||
}
|
||||
}
|
||||
void FractureHelper(Vector2 world, float radius)
|
||||
{
|
||||
Vector2 loc = transform.InverseTransformPoint(world);
|
||||
(int cx, int cy) = Destruction.LocToPixel(loc,sprend);
|
||||
pHandler.DestroyMask(fracture,cx,cy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ead6d33feb996340b43f15ce524b4e7
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Main/Destro2DMain.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[Serializable]
|
||||
public abstract class Destruction
|
||||
{
|
||||
protected Color burnColor = Color.white;
|
||||
public static List<GameObject> chunks = new();
|
||||
public abstract void Setup(GameObject gobj);
|
||||
public abstract void SetupWithColor(GameObject gobj, Color color);
|
||||
public abstract void ApplyDestruction(int cx, int cy, bool[,] mask, float stepX, float stepY,int maskW, int mmaskH,Color32[] burnage, float burntime);
|
||||
public static (int cx, int cy) LocToPixel(Vector2 loc, SpriteRenderer sprend)
|
||||
{
|
||||
Sprite s = sprend.sprite;
|
||||
Bounds b = s.bounds;
|
||||
float spw = s.rect.width;
|
||||
float sph = s.rect.height;
|
||||
|
||||
float uvx = (loc.x - b.min.x)/b.size.x;
|
||||
float uvy = (loc.y - b.min.y)/b.size.y;
|
||||
|
||||
int cx = Mathf.FloorToInt(uvx * spw);
|
||||
int cy = Mathf.FloorToInt(uvy * sph);
|
||||
|
||||
return (cx,cy);
|
||||
|
||||
}
|
||||
protected void BurnEdge(List<int> destroyed, int width, int height, bool[,] mask, Color32[] burnage, float burntime)
|
||||
{
|
||||
foreach (int i in destroyed)
|
||||
{
|
||||
int x = i % width;
|
||||
int y = i / width;
|
||||
|
||||
TryBurn(x + 1, y);
|
||||
TryBurn(x - 1, y);
|
||||
TryBurn(x, y + 1);
|
||||
TryBurn(x, y - 1);
|
||||
}
|
||||
|
||||
void TryBurn(int nx, int ny)
|
||||
{
|
||||
if (nx < 0 || ny < 0 || nx >= width || ny >= height)
|
||||
return;
|
||||
|
||||
if (mask[nx, ny])
|
||||
{
|
||||
int nidx = ny * width + nx;
|
||||
burnage[nidx] = burnColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1836b5c3ec02ee04394ff03d708ed6d4
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Main/Destruction.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
public class PixelHandler : MonoBehaviour
|
||||
{
|
||||
public Material maskerMaterial;
|
||||
public int maskWidth = 128, maskHeight = 128;
|
||||
public bool HasInit() => init;
|
||||
public bool IsDirty() => isDirty;
|
||||
public int burnDecay = 1;
|
||||
public float burnTime = 5f;
|
||||
|
||||
SpriteRenderer sprend;
|
||||
public Texture2D runtimeTex{get; private set;}
|
||||
bool[,] visualMask;
|
||||
int width, height;
|
||||
float stepX, stepY;
|
||||
public Color[] rectPixels{get; private set;}
|
||||
Texture2D maskTex;
|
||||
bool isDirty = false;
|
||||
bool init = false;
|
||||
public Action DoStuffOnVisualUpdate;
|
||||
Color32[] burnAge;
|
||||
Color32[] maskPixels;
|
||||
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void Initialise(Color[] cachedRectPixels = null, Texture2D cachedRunTimeTex = null,bool isChunk = false)
|
||||
{
|
||||
if(HasInit()) return;
|
||||
sprend = GetComponent<SpriteRenderer>();
|
||||
Texture2D src = sprend.sprite.texture;
|
||||
Rect srcRect = sprend.sprite.rect;
|
||||
width = (int)srcRect.width;
|
||||
height = (int)srcRect.height;
|
||||
if(cachedRectPixels == null)
|
||||
rectPixels = src.GetPixels((int)srcRect.x, (int)srcRect.y,width,height);
|
||||
else
|
||||
rectPixels = cachedRectPixels;
|
||||
|
||||
if(cachedRunTimeTex == null){
|
||||
runtimeTex = new Texture2D(width,height,TextureFormat.RGBA32,false);
|
||||
runtimeTex.SetPixels(rectPixels);
|
||||
runtimeTex.Apply();
|
||||
}
|
||||
else
|
||||
{
|
||||
runtimeTex = cachedRunTimeTex;
|
||||
}
|
||||
if(!isChunk)
|
||||
sprend.sprite = Sprite.Create(runtimeTex, new Rect(0,0,width,height),new Vector2(0.5f,0.5f),sprend.sprite.pixelsPerUnit);
|
||||
stepX = (float)width/maskWidth;
|
||||
stepY = (float)height/maskHeight;
|
||||
|
||||
maskTex = new Texture2D(maskWidth, maskHeight, TextureFormat.RGBA32,false);
|
||||
maskTex.filterMode = FilterMode.Point;
|
||||
sprend.sharedMaterial = maskerMaterial;
|
||||
|
||||
var block = new MaterialPropertyBlock();
|
||||
sprend.GetPropertyBlock(block);
|
||||
block.SetTexture("_MainTex", runtimeTex);
|
||||
block.SetTexture("_MaskTex", maskTex);
|
||||
block.SetVector("_MaskTexelSize",new Vector2(1f / maskTex.width, 1f / maskTex.height));
|
||||
sprend.SetPropertyBlock(block);
|
||||
|
||||
InitialiseMask();
|
||||
ApplyMaskToTexture();
|
||||
init = true;
|
||||
|
||||
}
|
||||
|
||||
private void InitialiseMask()
|
||||
{
|
||||
maskPixels = new Color32[maskWidth * maskHeight];
|
||||
burnAge = new Color32[maskWidth * maskHeight];
|
||||
visualMask = new bool[maskWidth,maskHeight];
|
||||
for(int i = 0; i< maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j< maskHeight; j++)
|
||||
{
|
||||
int px = (int)(i * stepX);
|
||||
int py = (int)(j * stepY);
|
||||
if(px < 0||py<0||px>=width||py>=height) continue;
|
||||
visualMask[i,j] = rectPixels[py * width + px].a > 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void ImmediateMaskUpdate(SplitHandler split)
|
||||
{
|
||||
if(split)
|
||||
ApplyMaskToTexture();
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
StartCoroutine(CheckDirty());
|
||||
}
|
||||
private void SetDirty()
|
||||
{
|
||||
isDirty = true;
|
||||
}
|
||||
IEnumerator CheckDirty()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if(isDirty) {
|
||||
|
||||
ApplyMaskToTexture();
|
||||
|
||||
isDirty = false;
|
||||
}
|
||||
yield return new WaitForSeconds(0.01f);
|
||||
|
||||
}
|
||||
}
|
||||
private void ApplyMaskToTexture()
|
||||
{
|
||||
for(int i = 0; i < maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
int idx = j * maskWidth + i;
|
||||
byte solid = visualMask[i,j] ? (byte)255: (byte)0;
|
||||
maskPixels[idx].r = burnAge[idx].r;
|
||||
maskPixels[idx].g = burnAge[idx].g;
|
||||
maskPixels[idx].b = burnAge[idx].b;
|
||||
maskPixels[idx].a = solid;
|
||||
float step = burnDecay * Time.deltaTime;
|
||||
burnAge[idx].r = (byte)(burnAge[idx].r > step ? burnAge[idx].r - step : 0);
|
||||
burnAge[idx].g = (byte)(burnAge[idx].g > step ? burnAge[idx].g - step : 0);
|
||||
burnAge[idx].b = (byte)(burnAge[idx].b > step ? burnAge[idx].b - step : 0);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
maskTex.SetPixels32(maskPixels);
|
||||
maskTex.Apply(false);
|
||||
DoStuffOnVisualUpdate?.Invoke();
|
||||
|
||||
}
|
||||
//fucntions for changing mask:
|
||||
|
||||
public void DestroyMask(Destruction d, int cx, int cy)
|
||||
{
|
||||
d.ApplyDestruction(cx,cy,visualMask,stepX,stepY,maskWidth,maskHeight,burnAge,burnTime);
|
||||
SetDirty();
|
||||
}
|
||||
public void SyncToVisual(bool[,] mask, int mWidth, int mHeight)
|
||||
{
|
||||
float stepX = (float)maskWidth/mWidth;
|
||||
float stepY = (float)maskHeight/mHeight;
|
||||
|
||||
for(int i = 0; i < mWidth; i++)
|
||||
{
|
||||
for(int j = 0; j< mHeight; j++)
|
||||
{
|
||||
int x = (int)(i * stepX);
|
||||
int y = (int)(j * stepY);
|
||||
if(x < 0||y<0||x>=maskWidth||y>=maskHeight) continue;
|
||||
mask[i,j] = visualMask[x,y];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public void Split(bool[,]mask, int mWidth, int mHeight, bool chunk = false)
|
||||
{
|
||||
float stepX = (float)maskWidth/mWidth;
|
||||
float stepY = (float)maskHeight/mHeight;
|
||||
|
||||
for(int i = 0; i< maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
int x = (int)(i / stepX);
|
||||
int y = (int)(j / stepY);
|
||||
|
||||
if(x < 0||y<0||x>=mWidth||y>=mHeight) continue;
|
||||
if(!chunk){
|
||||
if (!visualMask[i, j])
|
||||
continue;
|
||||
bool keep = false;
|
||||
|
||||
|
||||
for (int dy = -1; dy <= 1 && !keep; dy++)
|
||||
{
|
||||
for (int dx = -1; dx <= 1 && !keep; dx++)
|
||||
{
|
||||
int nx = x + dx;
|
||||
int ny = y + dy;
|
||||
|
||||
if (nx < 0 || ny < 0 || nx >= mWidth || ny >= mHeight)
|
||||
continue;
|
||||
|
||||
if (mask[nx, ny])
|
||||
keep = true;
|
||||
}
|
||||
}
|
||||
|
||||
visualMask[i, j] = keep;
|
||||
}
|
||||
else
|
||||
{
|
||||
visualMask[i,j] = mask[x,y];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
SetDirty();
|
||||
ApplyMaskToTexture();
|
||||
}
|
||||
public void InheritBurn(PixelHandler pother)
|
||||
{
|
||||
pother.burnAge = burnAge.ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0cd2b8cdc7d724d4fa15c58096ef8cc3
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Main/PixelHandler.cs
|
||||
uploadId: 925032
|
||||
@@ -0,0 +1,245 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace KD.Destro2D{
|
||||
[RequireComponent(typeof(PixelHandler))]
|
||||
public class SplitHandler : MonoBehaviour
|
||||
{
|
||||
|
||||
public int maskWidth = 64;
|
||||
public int maskHeight = 64;
|
||||
public int minCount = 8;
|
||||
public float splitMass = 1;
|
||||
public GameObject anchor;
|
||||
public Vector2 chunkCentre{get; private set;}
|
||||
public bool HasInit()=>init;
|
||||
public int MaxChunkCount = 4;
|
||||
bool[,] splitMask;
|
||||
PixelHandler pHandler;
|
||||
SpriteRenderer sprend;
|
||||
Color[] rectPixels;
|
||||
float stepX;
|
||||
float stepY;
|
||||
List<List<(int,int)>> regions = new();
|
||||
bool init = false;
|
||||
bool generatingChunks = false;
|
||||
public Action OnAnchorBroken;
|
||||
bool flag = true;
|
||||
Texture2D runtimeTex;
|
||||
public Queue<GameObject> splitChunks{get; private set;} = new();
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
public void InitialiseSplit()//initialise only after pixel handler initialises
|
||||
{
|
||||
if(HasInit()) return;
|
||||
pHandler = GetComponent<PixelHandler>();
|
||||
sprend = GetComponent<SpriteRenderer>();
|
||||
if (!pHandler.HasInit())
|
||||
{
|
||||
Debug.LogWarning("Has not initialised visuals before splitter! Quitting.");
|
||||
return;
|
||||
}
|
||||
rectPixels = pHandler.rectPixels;
|
||||
runtimeTex = pHandler.runtimeTex;
|
||||
int texWidth = sprend.sprite.texture.width;
|
||||
int texHeight = sprend.sprite.texture.height;
|
||||
stepX = (float)texWidth/maskWidth;
|
||||
stepY = (float)texHeight/maskHeight;
|
||||
BuildSplitMask(texWidth,texHeight);
|
||||
pHandler.SyncToVisual(splitMask,maskWidth,maskHeight);
|
||||
GetRegions();
|
||||
pHandler.DoStuffOnVisualUpdate+=CheckDisconnected;
|
||||
init = true;
|
||||
}
|
||||
|
||||
void CheckDisconnected()
|
||||
{
|
||||
if(generatingChunks) return;
|
||||
pHandler.SyncToVisual(splitMask,maskWidth,maskHeight);
|
||||
GetRegions();
|
||||
|
||||
}
|
||||
void GetRegions()
|
||||
{
|
||||
regions.Clear();
|
||||
bool[,] visited = new bool[maskWidth,maskHeight];
|
||||
var (ax, ay) = PlaceAnchor();
|
||||
FloodFill(ax,ay,visited);//get anchored base to get relative split chunks(object doesn't have to be anchored, though)
|
||||
|
||||
for(int i = 0; i < maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
if(!splitMask[i,j] || visited[i,j])
|
||||
continue;
|
||||
List<(int,int)> splitRegion = new();
|
||||
FloodFill(i, j, visited, splitRegion);
|
||||
if(splitRegion.Count >= minCount)
|
||||
regions.Add(splitRegion);
|
||||
}
|
||||
}
|
||||
GenerateChunks();
|
||||
|
||||
}
|
||||
void BuildSplitMask(int texwidth, int texheight)
|
||||
{
|
||||
splitMask = new bool[maskWidth, maskHeight];
|
||||
|
||||
for(int i = 0; i < maskWidth; i++)
|
||||
{
|
||||
for(int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
int px = (int)(i * stepX);
|
||||
int py = (int)(j * stepY);
|
||||
if(px < 0||py<0||px>=texwidth||py>=texheight) continue;
|
||||
splitMask[i,j] = rectPixels[py * texwidth + px].a > 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void FloodFill(int startX, int startY, bool[,] visited, List<(int,int)> region = null)
|
||||
{
|
||||
Stack<(int x, int y)> stack = new();
|
||||
stack.Push((startX, startY));
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
var (x,y) = stack.Pop();
|
||||
if(x < 0 || y < 0|| x >= maskWidth || y >= maskHeight)
|
||||
continue;
|
||||
|
||||
if(!splitMask[x,y]) continue;
|
||||
if(visited[x,y]) continue;
|
||||
|
||||
visited[x,y] = true;
|
||||
region?.Add((x,y));
|
||||
|
||||
stack.Push((x+1,y));
|
||||
stack.Push((x-1,y));
|
||||
stack.Push((x,y+1));
|
||||
stack.Push((x,y-1));
|
||||
}
|
||||
}
|
||||
|
||||
(int,int) PlaceAnchor()
|
||||
{
|
||||
|
||||
if (anchor)
|
||||
{
|
||||
Vector2 locPos = transform.InverseTransformPoint(anchor.transform.position);
|
||||
var (ax, ay) = Destruction.LocToPixel(locPos,sprend);
|
||||
|
||||
ax = Mathf.FloorToInt(ax/stepX);
|
||||
ay = Mathf.FloorToInt(ay/stepY);
|
||||
|
||||
if(ax >= 0 && ay >= 0 && ax < maskWidth && ay < maskHeight)
|
||||
{
|
||||
if(splitMask[ax,ay])
|
||||
return (ax,ay);
|
||||
}
|
||||
|
||||
}
|
||||
//if no anchor, call event ONCE, then default to first visible pixel
|
||||
if (flag)
|
||||
{
|
||||
OnAnchorBroken?.Invoke();
|
||||
flag = false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < maskWidth; i++)
|
||||
{
|
||||
for (int j = 0; j < maskHeight; j++)
|
||||
{
|
||||
if (splitMask[i, j])
|
||||
{
|
||||
return (i,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if no visible pixel, Destroy and remove from list
|
||||
if (Destruction.chunks.Contains(this.gameObject))
|
||||
{
|
||||
Destruction.chunks.Remove(this.gameObject);
|
||||
}
|
||||
Destroy(this.gameObject);
|
||||
return (-1,-1);
|
||||
}
|
||||
|
||||
void GenerateChunks()
|
||||
{
|
||||
generatingChunks = true;
|
||||
foreach(var region in regions)
|
||||
{
|
||||
int minLX = int.MaxValue, minLY = int.MaxValue;
|
||||
int maxLX = int.MinValue, maxLY = int.MinValue;
|
||||
bool[,] regMask = new bool[maskWidth,maskHeight];
|
||||
foreach(var r in region)
|
||||
{
|
||||
int x = r.Item1;
|
||||
int y = r.Item2;
|
||||
regMask[x,y] = true;
|
||||
splitMask[x,y] = false;
|
||||
minLX = Mathf.Min(minLX, x);
|
||||
minLY = Mathf.Min(minLY, y);
|
||||
maxLX = Mathf.Max(maxLX, x);
|
||||
maxLY = Mathf.Max(maxLY, y);
|
||||
}
|
||||
//Updating Parent visual
|
||||
pHandler.Split(splitMask,maskWidth,maskHeight);
|
||||
|
||||
//Chunk stuff, here u can make it inherit stuff as u want (by default it doesnt inherit mask details)
|
||||
GameObject chunk = new GameObject("Split Chunk");
|
||||
|
||||
//if queue count is greater than max, cycle
|
||||
if(splitChunks.Count >= MaxChunkCount)
|
||||
{
|
||||
if(splitChunks.TryDequeue(out GameObject g)){
|
||||
Destruction.chunks.Remove(g);
|
||||
Destroy(g);
|
||||
}
|
||||
|
||||
}
|
||||
splitChunks.Enqueue(chunk);
|
||||
Destruction.chunks.Add(chunk);
|
||||
SpriteRenderer sr = chunk.AddComponent<SpriteRenderer>();
|
||||
sr.sprite = sprend.sprite;
|
||||
sr.color = sprend.color;
|
||||
chunk.transform.position = transform.position;
|
||||
chunk.transform.localScale = transform.localScale;
|
||||
chunk.transform.rotation = transform.rotation;
|
||||
Rigidbody2D rb = chunk.AddComponent<Rigidbody2D>();
|
||||
rb.mass = splitMass;
|
||||
chunk.AddComponent<PolygonCollider2D>();
|
||||
PixelHandler p = chunk.AddComponent<PixelHandler>();
|
||||
p.maskerMaterial = pHandler.maskerMaterial;
|
||||
p.Initialise(rectPixels,runtimeTex,true);
|
||||
p.Split(regMask,maskWidth,maskHeight,true);
|
||||
pHandler.InheritBurn(p);
|
||||
var c = chunk.AddComponent<CollisionHandler>();
|
||||
c.InitialiseCollision();
|
||||
Vector2 minPos = c.GetPosOnDifferent(minLX,minLY,maskWidth,maskHeight);
|
||||
Vector2 maxPos = c.GetPosOnDifferent(maxLX,maxLY,maskWidth,maskHeight);
|
||||
|
||||
var s = chunk.AddComponent<SplitHandler>();
|
||||
s.splitMass = splitMass;
|
||||
s.InitialiseSplit();
|
||||
s.chunkCentre = (minPos + maxPos)/2f;
|
||||
Destro2DMain d = chunk.AddComponent<Destro2DMain>();
|
||||
|
||||
//This part decides what destruction the chunk is susceptible to
|
||||
d.InheritDestruction(this.gameObject);
|
||||
|
||||
}
|
||||
generatingChunks = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bbfd1860c521b44294e75917251fdba
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 358408
|
||||
packageName: Destro 2D - Dynamic Sprite Destruction
|
||||
packageVersion: 1.0.3
|
||||
assetPath: Assets/Destro2DMain/Core/Main/SplitHandler.cs
|
||||
uploadId: 925032
|
||||
Reference in New Issue
Block a user