void AddCircleCollider2Ds(Transform parent) { // find all valid colliders, add them to projection var colliders = FindObjectsOfType <CircleCollider2D>(); var filtered = colliders.Where(co => IsValidCollider(co)).ToList(); foreach (var collider in filtered) { // note: creating a primitive is necessary in order for it to bake properly var go = GameObject.CreatePrimitive(PrimitiveType.Cylinder); go.isStatic = true; go.transform.parent = parent; // position via offset and transformpoint var localPos = new Vector3(collider.offset.x, collider.offset.y, 0); var worldPos = collider.transform.TransformPoint(localPos); // position in 3D with Y aligned so feet are at y=0 go.transform.position = new Vector3(worldPos.x, NavMesh2D.ProjectedObjectY, worldPos.y); // scale depending on scale * collider size (circle=radius/box=size/...) go.transform.localScale = NavMeshUtils2D.ScaleFromCircleCollider2D(collider); // rotation go.transform.rotation = Quaternion.Euler(NavMeshUtils2D.RotationTo3D(collider.transform.eulerAngles)); MakeUnwalkable(go); } }
// monobehaviour /////////////////////////////////////////////////////////// void Awake() { // create projection var go = GameObject.CreatePrimitive(PrimitiveType.Cylinder); go.name = "NAVIGATION2D_OBSTACLE"; go.transform.position = NavMeshUtils2D.ProjectTo3D(transform.position); go.transform.rotation = Quaternion.Euler(NavMeshUtils2D.RotationTo3D(transform.eulerAngles)); obst = go.AddComponent <NavMeshObstacle>(); // disable mesh and collider (no collider for now) Destroy(obst.GetComponent <Collider>()); Destroy(obst.GetComponent <MeshRenderer>()); }
void Update() { // copy properties to projection all the time // (in case they are modified after creating it) obst.carving = carve; obst.center = NavMeshUtils2D.ProjectTo3D(center); obst.size = new Vector3(size.x, 1, size.y); // scale and rotate to match scaled/rotated sprites center properly obst.transform.localScale = new Vector3(transform.localScale.x, 1, transform.localScale.y); obst.transform.rotation = Quaternion.Euler(NavMeshUtils2D.RotationTo3D(transform.eulerAngles)); // project position to 3d obst.transform.position = NavMeshUtils2D.ProjectTo3D(transform.position); }
void AddPolygonCollider2Ds(Transform parent) { // find all valid colliders, add them to projection var colliders = GameObject.FindObjectsOfType <PolygonCollider2D>(); var filtered = colliders.Where(co => IsValidCollider(co)).ToList(); foreach (var collider in filtered) { for (int i = 0; i < collider.pathCount; i++) { // note: creating a primitive is necessary in order for it to bake properly var go = GameObject.CreatePrimitive(PrimitiveType.Cube); go.isStatic = true; go.transform.parent = parent; // position via offset and transformpoint var localPos = new Vector3(collider.offset.x, collider.offset.y, 0); var worldPos = collider.transform.TransformPoint(localPos); go.transform.position = new Vector3(worldPos.x, 0, worldPos.y); // scale depending on scale * collider size (circle=radius/box=size/...) go.transform.localScale = NavMeshUtils2D.ScaleFromPolygonCollider2D(collider); // rotation go.transform.rotation = Quaternion.Euler(NavMeshUtils2D.RotationTo3D(collider.transform.eulerAngles)); // remove box collider. note that baking uses the meshfilter, so // the collider doesn't really matter anyway. DestroyImmediate(go.GetComponent <BoxCollider>()); // Use the triangulator to get indices for creating triangles int[] indices = Triangulation.Triangulate(collider.GetPath(i).ToList()).ToArray(); // convert vector2 points to vector3 vertices var vertices = collider.GetPath(i).Select(p => new Vector3(p.x, 0, p.y)).ToList(); // create mesh var mesh = new Mesh(); mesh.vertices = vertices.ToArray(); mesh.triangles = indices; //mesh.RecalculateNormals(); mesh.RecalculateBounds(); // assign it to the mesh filter go.GetComponent <MeshFilter>().sharedMesh = mesh; MakeUnwalkable(go); } } }
void AddTilemapCollider2Ds(Transform parent) { // find all grids Grid[] grids = GameObject.FindObjectsOfType <Grid>(); foreach (Grid grid in grids) { // find tilemaps (we only care about those that have colliders) var tilemaps = grid.GetComponentsInChildren <Tilemap>().Where( tm => tm.GetComponent <TilemapCollider2D>() ).ToList(); foreach (Tilemap tilemap in tilemaps) { // go through each cell BoundsInt bounds = tilemap.cellBounds; for (int y = bounds.position.y; y < bounds.size.y; ++y) { for (int x = bounds.position.x; x < bounds.size.x; ++x) { // find out if it has a collider Vector3Int cellPosition = new Vector3Int(x, y, 0); if (tilemap.GetColliderType(cellPosition) != Tile.ColliderType.None) { // convert to world space Vector3 worldPosition = tilemap.GetCellCenterWorld(cellPosition); // note: creating a primitive is necessary in order for it to bake properly var go = GameObject.CreatePrimitive(PrimitiveType.Cube); go.isStatic = true; go.transform.parent = parent; // position via offset and transformpoint go.transform.position = new Vector3(worldPosition.x, 0, worldPosition.y); // scale depending on scale * collider size (circle=radius/box=size/...) go.transform.localScale = NavMeshUtils2D.ScaleTo3D(tilemap.transform.localScale); // rotation go.transform.rotation = Quaternion.Euler(NavMeshUtils2D.RotationTo3D(tilemap.transform.eulerAngles)); MakeUnwalkable(go); } } } } } }
void AddEdgeCollider2Ds(Transform parent) { // find all valid colliders, add them to projection var colliders = GameObject.FindObjectsOfType <EdgeCollider2D>(); var filtered = colliders.Where(co => IsValidCollider(co)).ToList(); foreach (var collider in filtered) { // note: creating a primitive is necessary in order for it to bake properly var go = GameObject.CreatePrimitive(PrimitiveType.Cube); go.isStatic = true; go.transform.parent = parent; // position via offset and transformpoint var localPos = new Vector3(collider.offset.x, collider.offset.y, 0); var worldPos = collider.transform.TransformPoint(localPos); go.transform.position = new Vector3(worldPos.x, 0, worldPos.y); // scale depending on scale * collider size (circle=radius/box=size/...) go.transform.localScale = NavMeshUtils2D.ScaleFromEdgeCollider2D(collider); // rotation go.transform.rotation = Quaternion.Euler(NavMeshUtils2D.RotationTo3D(collider.transform.eulerAngles)); // remove box collider. note that baking uses the meshfilter, so // the collider doesn't really matter anyway. DestroyImmediate(go.GetComponent <BoxCollider>()); // create mesh from edgecollider2D by stepping through each point // and creating a triangle with point, point-1 and point-1 with y=1 List <Vector3> vertices = new List <Vector3>(); List <int> indices = new List <int>(); // start at 2nd point so we can use the first one in our triangle, for (int i = 1; i < collider.points.Length; ++i) { Vector2 a2D = collider.points[i - 1]; Vector2 b2D = collider.points[i]; // convert to 3D // point A // point B // point C := A with y+1 Vector3 a3D = new Vector3(a2D.x, 0, a2D.y); Vector3 b3D = new Vector3(b2D.x, 0, b2D.y); Vector3 c3D = new Vector3(a2D.x, 1, a2D.y); // add 3 vertices vertices.Add(a3D); vertices.Add(b3D); vertices.Add(c3D); // add last 3 vertices as indices indices.Add(vertices.Count - 1); indices.Add(vertices.Count - 2); indices.Add(vertices.Count - 3); } // create mesh var mesh = new Mesh(); mesh.vertices = vertices.ToArray(); mesh.triangles = indices.ToArray(); //mesh.RecalculateNormals(); mesh.RecalculateBounds(); // assign it to the mesh filter go.GetComponent <MeshFilter>().sharedMesh = mesh; MakeUnwalkable(go); } }