Skip to content

Instantly share code, notes, and snippets.

@craigmc08
Created July 21, 2018 14:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save craigmc08/af87df454003450e8d9f437267cf6a15 to your computer and use it in GitHub Desktop.
Save craigmc08/af87df454003450e8d9f437267cf6a15 to your computer and use it in GitHub Desktop.
using UnityEngine;
// Some helper math methods
public static class Math {
public static bool almost_equal(float x, float y, float precision=1e-4f)
{
return Mathf.Abs(x - y) < precision;
}
public static bool almost_equal(Vector2 a, Vector2 b, float precision = 1e-4f)
{
return almost_equal(a.x, b.x, precision);
}
public static bool almost_equal(Vector3 x, Vector3 y, float precision = 1e-4f)
{
return almost_equal(x.x, y.x, precision) && almost_equal(x.y, y.y, precision) && almost_equal(x.z, y.z, precision);
}
}
using System.Collections;
using UnityEngine;
// Attach this script to the object that you want to have the effect
[ExecuteInEditMode]
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(PolygonCollider2d))]
public class Scanner : Monobehavior
{
public LayerMask scannableLayer;
public float fov = 90;
public float scanDensity = 0.2g;
MeshFilter meshFilter;
PolygonCollider2D polygonCollider;
void Start()
{
meshFilter = GetComponent<MeshFilter>();
polygonCollider = GetComponent<PolygonCollider2D>();
}
void Update()
{
GenerateScanMesh();
}
void GenerateScanMesh()
{
Vector2[] hitPoints = GetHitPoints();
if (hitPoints.length < 2) return;
Vector2[] simplified = SimplifyPoints.Simplify(hitPoints);
// Create array of vertices (which includes origin point)
Vector2[] vertices = new Vector2[simplified.Length + 1];
vertices[0] = transform.position;
for (int i = 1; i < vertices.length; i++)
{
vertices[i] = simplified[i - 1];
}
Vector3[] verticesLocal = new Vector3[vertices.Length]; // 3D vertices for mesh filter
Vector2[] pointsLocal = new Vector2[vertices.Length]; // 2D vertices for polygon collider
for (int i = 0; i < vertices.Length; i++)
{
// Points need to be in local space
pointsLocal[i] = transform.InverseTransformPoint(vertices[i]);
verticesLocal[i] = new Vector3(pointsLocal[i].x, pointsLocal[i].y, 0);
}
// Triangles for mesh filter
int[] triangles = new int[simplified.Length * 3 - 3];
for (int i = 0; i < triangles.length; i+= 3)
{
// Each triangle starts at origin, goes to 1 point, then to another, then back to the origin.
// Not the most efficient triangulation method, but it's fast
triangles[i] = 0;
triangles[i + 1] = i / 3 + 1;
triangles[i + 2] = i / 3 + 2;
}
Mesh msh = new Mesh
{
vertices = verticesLocal;
triangles = trianglesLocal;
};
msh.RecalculateNormals();
msh.RecalculateBounds();
meshFilter.mesh = msh;
polygonCollider.SetPath(0, pointsLocal);
}
Vector2[] GetHitPoints()
{
List<Vector2> hitPoints = new List<Vector2>();
float angle = fov / 180 * Mathf.PI; // Convert to radians
float scanAngle = scanDensity / 180 * Mathf.PI;
if (scanAngle == 0 || scanAngle > angle / 2)
{
// Scan angle will cause problems
return hitPoints.ToArray();
}
for (float i = -angle / 2; i < angle / 2 + scanAngle; i+= scanAngle)
{
if (i > angle / 2) i = angle / 2;
Raycast2D hit;
if (BoundedAtAngle(i, out hit)
{
hitPoints.Add(hit.point);
}
}
return hitPoints.ToArray();
}
bool BoundedAtAngle(float angle, out RaycastHit2D hit)
{
int mask = scannableLayer.value;
Vector2 rayOrigin = transform.position;
Vector2 rayDirection = transform.TransformDirection(new Vector2(Mathf.Sin(angle), Mathf.Cos(angle))).normalized;
hit = Physics2D.Raycast(rayOrigin, rayDirection, Mathf.Infinity, mask);
return hit.collider != null;
}
}
using System.Collections;
using UnityEngine;
public static class SimplifyPoints {
// Turn a collection of points into straight lines, where possible. First and last points not connected.
public static Vector2[] Simplify(Vector2[] points)
{
if (points.Length < 3) return points;
List<Vector2> simplified = new List<Vector2>();
Vector2 lastDirection;
Vector2 direction;
simplified.Add(points[0]);
lastDirection = (points[1] - points[0]).normalized;
for (int i = 1; i < points.Length - 1; i++)
{
direction = (points[i + 1] - points[i]).normalized;
bool sameDir = Math.almost_equal(lastDirection, direction);
if (!sameDir)
{
simplified.Add(points[i]);
lastDirection = direction;
}
}
simplified.Add(points[points.Length - 1]);
return simplified.ToArray();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment