Reputation: 21
I have run into this issue where I have a GameObject, for example size 1x3 - and the gameobject is only recognized for being on a tile because it's placed there and given coordinates in the inspector (for example 5 x, 0 y, 6 z). The problem being that the code only detects that there is a GameObject on one tile, the middle tile of the grid code.
I need to make sure the other tiles the GameObject is covering is aware that there is a GameObject there, so I can set them all to for example that they're not walkable on - or that you can use them as cover by being next to them. But so far the code only registers 1 tile of the GameObject - therein lies the problem.
Thing is, I don't know where to start. I have some ideas, maybe do a loop to check tiles next to them if there is a gameobject but then the code won't know if something is on that tile and the loop would also be quite heavy on performance - unless I do that loop on Awake or Start or something similar.
Can anyone point me in the right direction? Is there some built-in thing in Unity that can detect if something is above the specific tile I created?
It's an own gridsystem for the record to support 3D, so I'm not using the built-in tilemaps system for 2D games that Unity offers these days.
Unity Version 2017.3
Down below is Gridbase.cs - this handles the world and spawns all nodes (tiles)
public class GridBase : MonoBehaviour
{
//Grid Scale
public int sizeX = 32;
//amount of floors/levels, Y is up
public int sizeY = 3;
public int sizeZ = 32;
public float scaleXZ = 1;
// character scale
public float scaleY = 2.3f;
public Node[,,] grid;
public List<YLevels> yLevels = new List<YLevels>();
public bool debugNode = true;
public Material debugMaterial;
GameObject debugNodeObj;
void Start()
{
InitPhase();
}
public void InitPhase()
{
if (debugNode)
debugNodeObj = WorldNode();
//debug check all values for the grid.
Check();
//Spawn Grid Function
CreateGrid();
GameManager.singleton.Init();
}
void Check()
{
if(sizeX == 0)
{
Debug.Log("Size x is 0, assigning min");
sizeX = 16;
}
if(sizeY == 0)
{
Debug.Log("Size y is 0, assigning min");
sizeY = 1;
}
if (sizeZ == 0)
{
Debug.Log("Size z is 0, assigning min");
sizeX = 1;
}
if (scaleXZ == 0)
{
Debug.Log("ScaleXZ is 0, assigning min");
scaleXZ = 1;
}
if (scaleY == 0)
{
Debug.Log("ScaleY is 0, assigning min");
scaleY = 2;
}
}
void CreateGrid()
{
grid = new Node[sizeX, sizeY, sizeZ];
for (int y = 0; y < sizeY; y++)
{
YLevels ylvl = new YLevels();
ylvl.nodeParent = new GameObject();
ylvl.nodeParent.name = "Level" + y.ToString();
ylvl.y = y;
yLevels.Add(ylvl);
//Creating Collision for all nodes)
CreateCollision(y);
for (int x = 0; x < sizeX; x++)
{
for (int z = 0; z < sizeZ; z++)
{
Node n = new Node();
n.x = x;
n.y = y;
n.z = z;
n.isWalkable = true;
if(debugNode)
{
Vector3 targetPosition = WorldCoordinatesFromNode(x, y, z);
GameObject go = Instantiate(debugNodeObj,
targetPosition,
Quaternion.identity ) as GameObject;
go.transform.parent = ylvl.nodeParent.transform;
}
grid[x, y, z] = n;
}
}
}
}
void CreateCollision(int y)
{
YLevels lvl = yLevels[y];
GameObject go = new GameObject();
BoxCollider box = go.AddComponent<BoxCollider>();
// Creates a box collider that has the whole size of the grid + a little bit more
box.size = new Vector3(sizeX * scaleXZ + (scaleXZ * 2),
0.2f,
sizeZ * scaleXZ + (scaleXZ * 2));
//Spawn box collider in center
box.transform.position = new Vector3((sizeX * scaleXZ) * .5f - (scaleXZ * .5f),
y * scaleY,
(sizeZ * scaleXZ) * 0.5f - (scaleXZ * .5f));
lvl.CollisionObj = go;
lvl.CollisionObj.name = "lvl " + y + " collision";
}
public Node GetNode(int x, int y, int z)
{
x = Mathf.Clamp(x, 0, sizeX - 1);
y = Mathf.Clamp(y, 0, sizeY - 1);
z = Mathf.Clamp(z, 0, sizeZ - 1);
return grid[x, y, z];
}
//get World Cordinates from any Node
public Vector3 WorldCoordinatesFromNode(int x, int y, int z)
{
Vector3 r = Vector3.zero;
r.x = x * scaleXZ;
r.y = y * scaleY;
r.z = z * scaleXZ;
return r;
}
GameObject WorldNode()
{
GameObject go = new GameObject();
GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
Destroy(quad.GetComponent<Collider>());
quad.transform.parent = go.transform;
quad.transform.localPosition = Vector3.zero;
quad.transform.localEulerAngles = new Vector3(90, 0, 0);
quad.transform.localScale = Vector3.one * 0.95f;
quad.GetComponentInChildren<MeshRenderer>().material = debugMaterial;
return go;
}
public static GridBase singleton;
private void Awake()
{
singleton = this;
}
}
[System.Serializable]
public class YLevels
{
public int y;
public GameObject nodeParent;
public GameObject CollisionObj;
}
And this is the Node.cs file
public class Node
{
//Node's position in the grid
public int x;
public int y;
public int z;
//Node's costs for pathfinding purposes
public float hCost;
public float gCost;
public float fCost
{
get //the fCost is the gCost+hCost so we can get it directly this way
{
return gCost + hCost;
}
}
public Node parentNode;
public bool isWalkable = true;
//Reference to the world object so we can have the world position of the node among other things
public GameObject worldObject;
//Types of nodes we can have, we will use this later on a case by case examples
public NodeType nodeType;
public enum NodeType
{
ground,
air
}
}
this is the GridBase code pastebin.com/gazu9jPR that spawns the nodes (tiles) and this is the node script that triggers whenever gridbase references to Node class - pastebin.com/jk25n6ee
Upvotes: 2
Views: 3174
Reputation: 722
All the tiles need to have colliders. Also the object you place on the grid needs to have a collider(tick as trigger) which is big enough to overlap with tiles' colliders. Then you can use that to check how many tiles are covered by that object. The way you can do this is by using Collider.bounds which is of type Bounds. Bounds object has a method called Contains which you can pass in the tile's center point and see if it's covered by the object.
Upvotes: 1
Reputation: 132
You can use trigger colliders at the place the gameobjects will be created on. You'll need a seperate collider for each grid cell. Make the gameobject with the collider the child of the grid cell (I don't exactly know your hierarchy, so I'll just keep guessing). Then, when the collider detects the gameobject, let the corresponding cell know that it is occupied. Hope this helps.
Upvotes: 2