-
-
Save dylanwolf/1edf97c5e38a369d6b2cd6d7ca18ab52 to your computer and use it in GitHub Desktop.
Unity collider builder for procedurally generated platformer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
// Implementation of http://www.imageprocessingplace.com/downloads_V3/root_downloads/tutorials/contour_tracing_Abeer_George_Ghuneim/theo.html | |
public static class PolygonCreator { | |
static List<Vector2> result = new List<Vector2>(); | |
enum Direction | |
{ | |
Up, | |
Down, | |
Left, | |
Right | |
} | |
static Direction RotateLeft(Direction current) | |
{ | |
switch (current) | |
{ | |
case Direction.Up: | |
return Direction.Left; | |
break; | |
case Direction.Left: | |
return Direction.Down; | |
break; | |
case Direction.Down: | |
return Direction.Right; | |
break; | |
} | |
return Direction.Up; | |
} | |
static Direction RotateRight(Direction current) | |
{ | |
switch (current) | |
{ | |
case Direction.Up: | |
return Direction.Right; | |
break; | |
case Direction.Right: | |
return Direction.Down; | |
break; | |
case Direction.Down: | |
return Direction.Left; | |
break; | |
} | |
return Direction.Up; | |
} | |
static bool IsSomething(LevelBlock[,] blocks, int x, int y, bool isPassthrough) | |
{ | |
if (x < 0 || x > maxX || y < 0 || y > maxY) | |
return false; | |
if (isPassthrough) | |
return blocks[y, x] == LevelBlock.Platform; | |
else | |
return blocks[y, x] != LevelBlock.Nothing && blocks[y,x] != LevelBlock.Platform; | |
} | |
static void SetDeltaValues(Direction dir) | |
{ | |
switch (dir) | |
{ | |
case Direction.Up: | |
P1X = -1; P1Y = 1; | |
P2X = 0; P2Y = 1; | |
break; | |
case Direction.Left: | |
P1X = -1; P1Y = -1; | |
P2X = -1; P2Y = 0; | |
break; | |
case Direction.Down: | |
P1X = 1; P1Y = -1; | |
P2X = 0; P2Y = -1; | |
break; | |
case Direction.Right: | |
P1X = 1; P1Y = 1; | |
P2X = 1; P2Y = 0; | |
break; | |
} | |
} | |
static void CreateVertex(int tileX, int tileY, int cornerX, int cornerY) | |
{ | |
result.Add(new Vector2( | |
(tileX * ChunkManager.Current.TileSize) + (cornerX * ChunkManager.Current.TileSize / 2.0f), | |
(tileY * ChunkManager.Current.TileSize) + (cornerY * ChunkManager.Current.TileSize / 2.0f) | |
)); | |
} | |
static int ZeroOrSign(float value) | |
{ | |
if (value == 0) | |
return 0; | |
else | |
return (int)Mathf.Sign(value); | |
} | |
static bool CanJoinLineSegments(Vector2 a, Vector2 b, Vector2 c) | |
{ | |
return ( | |
ZeroOrSign(b.x - a.x) == ZeroOrSign(c.x - b.x) && | |
ZeroOrSign(b.y - a.y) == ZeroOrSign(c.y - b.y) | |
); | |
} | |
static void CleanupResults() | |
{ | |
int index = 1; | |
while (index + 1 < result.Count) | |
{ | |
if ( | |
CanJoinLineSegments(result[index-1],result[index],result[index+1]) | |
) | |
{ | |
result.RemoveAt(index); | |
} | |
else | |
{ | |
index++; | |
} | |
} | |
} | |
static int P1X = 0; | |
static int P2X = 0; | |
static int P1Y = 0; | |
static int P2Y = 0; | |
static int currentX = 0; | |
static int currentY = 0; | |
static int maxX = 0; | |
static int maxY = 0; | |
static bool[,] generated; | |
static PolygonCollider2D collider; | |
static GameObject passthroughColliders; | |
static GameObject worldColliders; | |
static PlatformEffector2D platform; | |
static bool isPassthrough; | |
const string WORLD_COLLIDERS = "WorldColliders"; | |
const string PASSTHROUGH_COLLIDERS = "PassthroughColliders"; | |
public static void CreatePolygons(GameObject parent, LevelBlock[,] blocks) | |
{ | |
passthroughColliders = new GameObject(); | |
passthroughColliders.name = PASSTHROUGH_COLLIDERS; | |
passthroughColliders.layer = LayerMasks.PassthroughLayer; | |
passthroughColliders.transform.parent = parent.transform; | |
passthroughColliders.transform.localPosition = Vector3.zero; | |
worldColliders = new GameObject(); | |
worldColliders.name = WORLD_COLLIDERS; | |
worldColliders.layer = LayerMasks.WorldLayer; | |
worldColliders.transform.parent = parent.transform; | |
worldColliders.transform.localPosition = Vector3.zero; | |
maxY = blocks.GetLength(0) - 1; | |
maxX = blocks.GetLength(1) - 1; | |
generated = new bool[maxY + 1, maxX + 1]; | |
platform = null; | |
for (int col = 0; col <= maxX; col++) | |
{ | |
for (int row = 0; row <= maxY; row++) | |
{ | |
// Is blank or already handled | |
if (generated[row, col] || blocks[row, col] == LevelBlock.Nothing) | |
continue; | |
// Is surrounded | |
isPassthrough = blocks[row, col] == LevelBlock.Platform; | |
if (IsSomething(blocks, col + 1, row, isPassthrough) && IsSomething(blocks, col - 1, row, isPassthrough) && | |
IsSomething(blocks, col, row + 1, isPassthrough) && IsSomething(blocks, col, row - 1, isPassthrough)) | |
continue; | |
collider = (isPassthrough ? passthroughColliders : worldColliders).AddComponent<PolygonCollider2D>(); | |
collider.points = CreatePolygon(blocks, col, row, isPassthrough); | |
} | |
} | |
} | |
public static Vector2[] CreatePolygon(LevelBlock[,] blocks, int startX, int startY, bool isPassthrough) | |
{ | |
result.Clear(); | |
maxY = blocks.GetLength(0) - 1; | |
maxX = blocks.GetLength(1) - 1; | |
currentX = startX; | |
currentY = startY; | |
Direction dir = Direction.Up; | |
SetDeltaValues(dir); | |
// Create first line segment | |
CreateVertex(currentX, currentY, -1, -1); | |
CreateVertex(currentX, currentY, -1, 1); | |
generated[currentY, currentX] = true; | |
int rotations = 0; | |
while (rotations < 3) | |
{ | |
if (IsSomething(blocks, currentX + P2X, currentY + P2Y, isPassthrough)) | |
{ | |
if (IsSomething(blocks, currentX + P1X, currentY + P1Y, isPassthrough)) | |
{ | |
currentX = currentX + P1X; | |
currentY = currentY + P1Y; | |
dir = RotateLeft(dir); | |
SetDeltaValues(dir); | |
CreateVertex(currentX, currentY, P1X, P1Y); | |
generated[currentY, currentX] = true; | |
} | |
else | |
{ | |
currentX = currentX + P2X; | |
currentY = currentY + P2Y; | |
CreateVertex(currentX, currentY, P1X, P1Y); | |
generated[currentY, currentX] = true; | |
} | |
if (currentX == startX && currentY == startY) | |
{ | |
break; | |
} | |
rotations = 0; | |
} | |
else | |
{ | |
dir = RotateRight(dir); | |
SetDeltaValues(dir); | |
CreateVertex(currentX, currentY, P1X, P1Y); | |
generated[currentY, currentX] = true; | |
rotations++; | |
} | |
} | |
CleanupResults(); | |
return result.ToArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment