My code isn't working as intended, can't figure out why.

I’m making an Airport Tycoon kind of game, and I’ve had this bug in my code for a few days now and I just can’t figure it out. This is a bit of a long one, but hopefully someone can find what I’m doing wrong.

Here’s what I’m doing: I’m trying to make it so that when you build one section of taxiway over another one, it removes the meshes of the underlying building. I was originally using individual GameObjects for each tile, but this was too slow, so I now have meshes for each tile that I’m combining inside one GameObject. I store them in a list with the references of each submesh contained within each tile, and then have a method for deleting specific tiles in a rectangular shape.

Here’s the code of the building:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;

public class MultiMesh : MonoBehaviour {
	public Vector3 startPos;
	public float endDistance;
	public SectionMap midSection;
	public SectionMap endSection;
	public Material[] materialArray;
	public bool endSameAsMid = true;
	private Vector3 endPos;
	private List<CombineInstance> combine;
	private List<Material> materials;
	private MeshFilter meshFilter;
	private MeshRenderer meshRenderer;
	private List<List<int>> tileSubMeshList;
	private int tileSize;
	private int tileLength;
	private float gridOffset;
	Vector3 scale;
	// Use this for initialization
	void Awake () {
		scale = new Vector3(1, 1, 1);
		tileSize = GameObject.FindGameObjectWithTag("tile manager").GetComponent<TileMap>().tileSize;
		meshFilter = gameObject.GetComponent<MeshFilter>();
		meshRenderer = gameObject.GetComponent<MeshRenderer>();
		materials = new List<Material>();
		meshFilter.mesh = new Mesh();
		combine = new List<CombineInstance>();
		tileSubMeshList = new List<List<int>>();
	}

	void Start () {
		gridOffset = - midSection.XSize / 2 * tileSize;
		if (midSection.XSize % 2 == 0) {
			gridOffset += tileSize / 2;
		}
		transform.localPosition = new Vector3(transform.localPosition.x + gridOffset, 0, 0);
		endPos = Vector3.forward * endDistance;
		tileLength = 0;
		int numberOfSections;
		if (endSameAsMid) {
			BuildSection(midSection, startPos);
			numberOfSections = (int)((Vector3.Distance(startPos, endPos) / tileSize) - midSection.ZSize) / midSection.ZSize;
			tileLength += midSection.ZSize;
		}
		else {
			BuildSection(endSection, startPos);
			numberOfSections = (int)((Vector3.Distance(startPos, endPos) / tileSize) - endSection.ZSize) / endSection.ZSize;
			tileLength += endSection.ZSize;
		}
		for (int i = 1; i <= numberOfSections; i++) {
			BuildSection(midSection, new Vector3(startPos.x, 0, startPos.z + (i * midSection.ZSize * tileSize)));
			tileLength += midSection.ZSize;
		}
		if (startPos != endPos) {
			if (endSameAsMid) {
				BuildSection(midSection, endPos);
				tileLength += midSection.ZSize;
			}
			else {
				BuildSection(endSection, endPos);
				tileLength += endSection.ZSize;
			}
		}
		meshRenderer.materials = materials.ToArray();
		meshFilter.mesh.CombineMeshes(combine.ToArray(), false, true);
	}

	public void Test () {
		RemoveRect (new Vector3 (20, 0, 10), new Vector3(50, 0, 100));
	}

	// Remove rectangle of from the mesh, this doesnt quite work properly at certain rotations
	public void RemoveRect (Vector3 min, Vector3 max) {
		Debug.DrawRay(transform.TransformPoint(min), Vector3.up * 100, Color.red, 1000f, false);
		Debug.DrawRay(transform.TransformPoint(max), Vector3.up * 100, Color.red, 1000f, false);
		Vector3 oldMin = min;
		Vector3 oldMax = max;
		if (min.x > max.x) {
			min.x = oldMax.x ;
			max.x = oldMin.x;
		}
		if (min.z > max.z) {
			min.z = oldMax.z;
			max.z = oldMin.z;
		}
		min = min / tileSize;
		max = max / tileSize;

		Debug.DrawRay(transform.TransformPoint(min * tileSize), Vector3.up * 100, Color.blue, 1000f, false);
		Debug.DrawRay(transform.TransformPoint(max * tileSize), Vector3.up * 100, Color.blue, 1000f, false);
		if (min.x < midSection.XSize && min.z < tileLength && max.x >= 0 && max.z >= 0){
			min.x = Mathf.Clamp(min.x, 0, midSection.XSize - 1);
			max.x = Mathf.Clamp(max.x, 0, midSection.XSize - 1);
			min.z = Mathf.Clamp(min.z, 0, tileLength - 1);
			max.z = Mathf.Clamp(max.z, 0, tileLength - 1);
			Debug.Log (min.ToString());
			Debug.Log (max.ToString());
			for (int i = (int)min.x; i <= max.x; i++){
				for (int j = (int)min.z; j <= max.z; j++) {
					int[] subMeshes = tileSubMeshList[i + midSection.XSize * j].ToArray();
					for (int k = 0; k < subMeshes.Length; k++) {
						meshFilter.mesh.SetTriangles(new int[0], subMeshes[k]);
					}
				}
			}
		}
	}

	public void BuildSection (SectionMap section, Vector3 pos) {
		for (int i = 0; i < section.tiles.Count; i++){
			List<int> newTileSubs = new List<int>();
			for (int j = 0; j < section.tiles*.tile.subMeshCount; j++){*
  •  		CombineInstance newCombine = new CombineInstance();*
    

_ newCombine.mesh = section.tiles*.tile;_
_ Vector3 newPos = pos + new Vector3((i % midSection.XSize) * tileSize, 0, - (i / midSection.XSize) * tileSize);_
_
Quaternion newRotation = new Quaternion();_
_ switch (section.tiles.rotation){
case CardinalRotation.up:
newRotation = Quaternion.LookRotation(Vector3.forward);
break;
case CardinalRotation.right:
newRotation = Quaternion.LookRotation(Vector3.right);
break;
case CardinalRotation.down:
newRotation = Quaternion.LookRotation(Vector3.back);
break;
case CardinalRotation.left:
newRotation = Quaternion.LookRotation(Vector3.left);
break;
}
newCombine.transform = Matrix4x4.TRS (newPos, newRotation, scale);
newCombine.subMeshIndex = j;
newTileSubs.Add(combine.Count);
combine.Add(newCombine);
Material newMaterial = materialArray[j];
materials.Add (newMaterial);*_

* }*
* tileSubMeshList.Add(newTileSubs);*
* }*
* }*
}
and here’s where it gets called by the builder object:
foreach (GameObject building in buildings){
_ Vector3 localMin = building.transform.InverseTransformPoint(new Vector3(coords.minX + 1, 0, coords.minZ + 1) * gridSize);
Vector3 localMax = building.transform.InverseTransformPoint(new Vector3(coords.maxX, 0, coords.maxZ) * gridSize);
* building.GetComponent().RemoveRect(localMin, localMax);
//building.GetComponent().Test ();
}*
So, here’s the really weird part: If I call the currently commented out Test() method, it works as intended, however the line just above that, using the exact same Vector3s, does what I show in the above screenshot, it removes a rectangle offset by one tile. It only does this on taxiway built from left to right. It also has some similar weirdness on both horizontal directions towards the start of the section. What I can’t get my head around is how feeding the exact same numbers into my method works in the test method, and not in the actual one. Does anyone have any idea what is going wrong?_

New to programming and Unity3D in general. So take what I say w/ a grain of salt.

I feel like you should be using a pre-fab instead of designating all the parameters of your object inside of code. Although it’s fine for you to do this if you ever want to change the object in the future it will be much easier to go the pre-fab route.

I’m not seeing an “Update” function which is when I would typically expect to see the calls made to place the objects in the world. If I were to build a similar script to this I’d probably start by building an x & z grid coordinate system in a separate script which would have positions designated. After I had that working I’d use the references from that script for the objects that I’d place on it.

Currently I’m working on a game similar to the old SNES Ogre battle and the units have to be placed on a grid similar to what you’re doing here and that’s how Chris DeLeon and I have worked out to handle the process.

Honestly I’m having a hard time working through what you have and so what I’m saying may not be much use to you but I hope it helped.

OK, well, it turned out to be a matter of casting a float to int not working properly!

Apparently, doing (int)myFloat doesn’t always do what you would expect it to. I’ve replaced them with myInt = Mathf.RoundToInt(myFloat), and now everything seems to be grand.

Here’s my new RemoveRect () in the unlikely event someone wants to know the solution to my obscure problem.

public void RemoveRect (Vector3 min, Vector3 max) {
		Debug.DrawRay(transform.TransformPoint(min), Vector3.up * 100, Color.red, 1000f, false);
		Debug.DrawRay(transform.TransformPoint(max), Vector3.up * 100, Color.red, 1000f, false);
		Vector3 oldMin = min;
		Vector3 oldMax = max;
		if (min.x > max.x) {
			min.x = oldMax.x ;
			max.x = oldMin.x;
		}
		if (min.z > max.z) {
			min.z = oldMax.z;
			max.z = oldMin.z;
		}
		min = min / tileSize;
		max = max / tileSize;

		Debug.DrawRay(transform.TransformPoint(min * tileSize), Vector3.up * 100, Color.blue, 1000f, false);
		Debug.DrawRay(transform.TransformPoint(max * tileSize), Vector3.up * 100, Color.blue, 1000f, false);
		if (min.x < midSection.XSize && min.z < tileLength && max.x >= 0 && max.z >= 0){
			min.x = Mathf.Clamp(min.x, 0, midSection.XSize - 1);
			max.x = Mathf.Clamp(max.x, 0, midSection.XSize - 1);
			min.z = Mathf.Clamp(min.z, 0, tileLength - 1);
			max.z = Mathf.Clamp(max.z, 0, tileLength - 1);
			int minX = Mathf.RoundToInt(min.x);
			int maxX = Mathf.RoundToInt(max.x);
			int minZ = Mathf.RoundToInt(min.z);
			int maxZ = Mathf.RoundToInt(max.z);
			for (int i = minX; i <= maxX; i++){
				for (int j = minZ; j <= maxZ; j++) {
					int[] subMeshes = tileSubMeshList[i + midSection.XSize * j].ToArray();
					for (int k = 0; k < subMeshes.Length; k++) {
						meshFilter.mesh.SetTriangles(new int[0], subMeshes[k]);
					}
				}
			}
		}
	}