|
Post by Admin on Apr 4, 2019 17:58:11 GMT
I am creating this thread because I have been asked about ways to handle really large boards in the Tactics RPG project. My thoughts are: 1. Create a single mesh for the whole board instead of creating a ton of GameObjects which tend to slow things down. Then use some other method of highlighting tiles such as other materials or Projectors to show tile highlighting. 2. If you prefer the individual tile setup from the blog, try converting to Unity's new ECS. I did some tests there and it was able to handle insanely large board sizes. For those of you choosing option 1, here are some additional tips: You can programmatically create your texture for a projector, see here. I created my texture with the same dimensions as the board's dimensions. I use a filterMode of Point to keep antialiasing from making it look bad. Then I use SetPixel to "mask" where I want tiles to appear using the coordinates of the tiles I want to highlight. I made the Projector light a Directional light type for easier positioning. Hopefully that helps! If not, feel free to ask more questions below. I may have some additional things to share when I get home - if I can find where I tested all of this. Good luck!
|
|
|
Post by aardfish on Apr 4, 2019 21:44:15 GMT
Thanks for the post. Going to tinker and see if I can get the projector working.
|
|
|
Post by Admin on Apr 5, 2019 13:32:38 GMT
While I was testing large boards, I created this little script to create a single mesh of all the board tiles. You can then export it to something like an .obj using some freely available exporters. Import to blender, then use as background reference or just clean it up directly. using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor;
public class BoardToMesh { Dictionary<Point, Tile> tiles; List<Vector3> vertices = new List<Vector3>(); List<Vector3> normals = new List<Vector3>(); List<Vector2> uvs = new List<Vector2>(); List<int> triangles = new List<int>(); Vector3 min; Vector3 max; Vector3 scale;
public BoardToMesh(Dictionary<Point, Tile> tiles) { this.tiles = tiles; }
public Mesh Create() { DetermineExtents();
foreach (Point point in tiles.Keys) { var tile = tiles[point]; AddTopFace(tile); AddXNegFace(tile); AddXPosFace(tile); AddZNegFace(tile); AddZPosFace(tile); }
for (int i = 0; i < 4; ++i) Debug.Log(string.Format("v: {0}, uv: {1}", vertices[i].ToString(), uvs[i].ToString()));
Mesh mesh = new Mesh(); mesh.vertices = vertices.ToArray(); mesh.normals = normals.ToArray(); mesh.uv = uvs.ToArray(); mesh.triangles = triangles.ToArray(); return mesh; }
void DetermineExtents() { min = new Vector3(float.MaxValue, 0, float.MaxValue); max = new Vector3(float.MinValue, 0, float.MinValue); foreach (Tile tile in tiles.Values) { min.x = Mathf.Min(min.x, tile.pos.x); min.z = Mathf.Min(min.z, tile.pos.y); max.x = Mathf.Max(max.x, tile.pos.x + 1); max.y = Mathf.Max(max.y, tile.height * Tile.stepHeight); max.z = Mathf.Max(max.z, tile.pos.y + 1); } var xDelta = max.x - min.x; var yDelta = max.y - min.y; var zDelta = max.z - min.z; var overall = Mathf.Max(xDelta, Mathf.Max(yDelta, zDelta)); scale = new Vector3(xDelta / overall, yDelta / overall, zDelta / overall); Debug.Log("scale: " + scale.ToString()); }
void AddTopFace(Tile tile) { AddTris(); AddNormals(new Vector3(0, 1, 0));
var top = tile.height * Tile.stepHeight; var left = tile.pos.x; var right = tile.pos.x + 1; var near = tile.pos.y; var far = tile.pos.y + 1;
var v = new Vector3[4]; v[0] = new Vector3(left, top, near); v[1] = new Vector3(left, top, far); v[2] = new Vector3(right, top, far); v[3] = new Vector3(right, top, near); vertices.AddRange(v);
var l = (left - min.x) / (max.x - min.x) * scale.x; var r = (right - min.x) / (max.x - min.x) * scale.x; var t = (far - min.z) / (max.z - min.z) * scale.z; var b = (near - min.z) / (max.z - min.z) * scale.z; AddUVs(l, r, t, b); }
void AddXNegFace(Tile tile) { var nextPoint = new Point(tile.pos.x - 1, tile.pos.y); var nextTile = tiles.ContainsKey(nextPoint) ? tiles[nextPoint] : null; if (nextTile != null && nextTile.height >= tile.height) return;
AddTris(); AddNormals(new Vector3(-1, 0, 0));
var low = nextTile != null ? nextTile.height * Tile.stepHeight : 0; var high = tile.height * Tile.stepHeight; var near = tile.pos.y; var far = tile.pos.y + 1;
var v = new Vector3[4]; v[0] = new Vector3(tile.pos.x, low, far); v[1] = new Vector3(tile.pos.x, high, far); v[2] = new Vector3(tile.pos.x, high, near); v[3] = new Vector3(tile.pos.x, low, near); vertices.AddRange(v);
var l = (far - min.z) / (max.z - min.z) * scale.z; var r = (near - min.z) / (max.z - min.z) * scale.z; var t = (high - min.y) / (max.y - min.y) * scale.y; var b = (low - min.y) / (max.y - min.y) * scale.y; AddUVs(1 - l, 1 - r, t, b); }
void AddXPosFace(Tile tile) { var nextPoint = new Point(tile.pos.x + 1, tile.pos.y); var nextTile = tiles.ContainsKey(nextPoint) ? tiles[nextPoint] : null; if (nextTile != null && nextTile.height >= tile.height) return;
AddTris(); AddNormals(new Vector3(1, 0, 0));
var low = nextTile != null ? nextTile.height * Tile.stepHeight : 0; var high = tile.height * Tile.stepHeight; var near = tile.pos.y; var far = tile.pos.y + 1;
var v = new Vector3[4]; v[0] = new Vector3(tile.pos.x + 1, low, near); v[1] = new Vector3(tile.pos.x + 1, high, near); v[2] = new Vector3(tile.pos.x + 1, high, far); v[3] = new Vector3(tile.pos.x + 1, low, far); vertices.AddRange(v);
var l = (near - min.z) / (max.z - min.z) * scale.z; var r = (far - min.z) / (max.z - min.z) * scale.z; var t = (high - min.y) / (max.y - min.y) * scale.y; var b = (low - min.y) / (max.y - min.y) * scale.y; AddUVs(l, r, t, b); }
void AddZNegFace(Tile tile) { var nextPoint = new Point(tile.pos.x, tile.pos.y - 1); var nextTile = tiles.ContainsKey(nextPoint) ? tiles[nextPoint] : null; if (nextTile != null && nextTile.height >= tile.height) return;
AddTris(); AddNormals(new Vector3(0, 0, -1));
var low = nextTile != null ? nextTile.height * Tile.stepHeight : 0; var high = tile.height * Tile.stepHeight; var left = tile.pos.x; var right = tile.pos.x + 1;
var v = new Vector3[4]; v[0] = new Vector3(left, low, tile.pos.y); v[1] = new Vector3(left, high, tile.pos.y); v[2] = new Vector3(right, high, tile.pos.y); v[3] = new Vector3(right, low, tile.pos.y); vertices.AddRange(v);
var l = (left - min.x) / (max.x - min.x) * scale.x; var r = (right - min.x) / (max.x - min.x) * scale.x; var t = (high - min.y) / (max.y - min.y) * scale.y; var b = (low - min.y) / (max.y - min.y) * scale.y; AddUVs(l, r, t, b); }
void AddZPosFace(Tile tile) { var nextPoint = new Point(tile.pos.x, tile.pos.y + 1); var nextTile = tiles.ContainsKey(nextPoint) ? tiles[nextPoint] : null; if (nextTile != null && nextTile.height >= tile.height) return;
AddTris(); AddNormals(new Vector3(0, 0, 1));
var low = nextTile != null ? nextTile.height * Tile.stepHeight : 0; var high = tile.height * Tile.stepHeight; var left = tile.pos.x; var right = tile.pos.x + 1;
var v = new Vector3[4]; v[0] = new Vector3(right, low, tile.pos.y + 1); v[1] = new Vector3(right, high, tile.pos.y + 1); v[2] = new Vector3(left, high, tile.pos.y + 1); v[3] = new Vector3(left, low, tile.pos.y + 1); vertices.AddRange(v);
var l = (right - min.x) / (max.x - min.x) * scale.x; var r = (left - min.x) / (max.x - min.x) * scale.x; var t = (high - min.y) / (max.y - min.y) * scale.y; var b = (low - min.y) / (max.y - min.y) * scale.y; AddUVs(1 - l, 1 - r, t, b); }
void AddTris() { var start = vertices.Count; var t = new int[6]; t[0] = start + 0; t[1] = start + 1; t[2] = start + 2;
t[3] = start + 0; t[4] = start + 2; t[5] = start + 3; triangles.AddRange(t); }
void AddNormals(Vector3 dir) { var n = new Vector3[4]; for (int i = 0; i < 4; ++i) n[i] = dir; normals.AddRange(n); }
void AddUVs(float l, float r, float t, float b) { var u = new Vector2[4]; u[0] = new Vector3(l, b); u[1] = new Vector3(l, t); u[2] = new Vector3(r, t); u[3] = new Vector3(r, b); uvs.AddRange(u); } }
These were added to BoardCreator.cs public void CreateMesh () { var creator = new BoardToMesh(tiles); var mesh = creator.Create(); CreateAsset(mesh, string.Format("{0}_mesh", name)); }
void CreateAsset(Object asset, string named) { string filePath = Application.dataPath + "/Resources/Levels"; if (!Directory.Exists(filePath)) CreateSaveDirectory();
string fileName = string.Format("Assets/Resources/Levels/{0}.asset", named); AssetDatabase.CreateAsset(asset, fileName); AssetDatabase.SaveAssets(); Selection.activeObject = asset; }
|
|
|
Post by Admin on Apr 5, 2019 13:39:57 GMT
P.S. For some reason I accidentally erased the script above. I managed to restore this one but I haven't actually tested it to make sure it was in final working condition. It should at least be enough to get you started though.
|
|