How to make a collider get the position from every tile it touches?
This is what happens: link. Every three seconds a gameObject called go_Radar (with a Circle Collider 2D) grows in size (and shrinks to 0) to work as a scan feature.
I want the collider to get the position from all the tiles it touches to turn them green. As of now it only turns green the first one(s) it comes in contact with, as seen in the example above.
Below is my code:
public class TilemapScript : MonoBehaviour
{
Tilemap tilemap;
Tile tileGreen;
Tile tileBlack;
TileBase tileCheck;
private void Awake()
{
tileGreen = Resources.Load<Tile>("Green") as Tile;
tileBlack = Resources.Load<Tile>("Black") as Tile;
}
// Start is called before the first frame update
void Start()
{
tilemap = GetComponent<Tilemap>();
}
// CHANGE TILES ACCORDING TO COLLISIONS
void OnCollisionEnter2D(Collision2D collision)
{
Vector3 hitPosition = Vector3.zero;
{
if (tilemap != null && Manager.Instance.go_Radar == collision.gameObject)
{
foreach (ContactPoint2D hit in collision.contacts)
{
hitPosition.x = hit.point.x;
hitPosition.y = hit.point.y;
hitPosition.z = 0;
tileCheck = tilemap.GetTile(tilemap.WorldToCell(hitPosition));
if (tileCheck == tileBlack && tileCheck != null)
{
tilemap.SetTile(tilemap.WorldToCell(hitPosition), tileGreen); // PROBLEM: IT ONLY TURNS GREEN THE FIRST TILES IT COMES IN CONTACT WITH.
}
}
}
}
}
}
I've been stuck here for a while and I'd very much like to get pointed in the right direction. Thanks in advance.
Answer by adriasierra · Mar 23, 2020 at 11:30 AM
I did it: https://gyazo.com/ba95077b056d95a2c063271c6a097760
Here's the gist of it:
Everytime there's a scan (the go_Radar object grows and shrinks in size with a CircleCollider2D), I run the following method to get every position around the player based on the maximum radar range.
void UpdateProximityArray()
{
// UPDATE PLAYER POSITION - USED TO DETERMINE THE STARTING POINT OF THE "ARRAY"
Manager.Instance.playerPosition.x = (int)Manager.Instance.player.position.x;
Manager.Instance.playerPosition.y = (int)Manager.Instance.player.position.y;
// UPDATE RADAR MAX RANGE - USED TO DETERMINE THE SIZE OF THE "ARRAY"
Manager.Instance.radarRangeSize.x = (int)Manager.Instance.radarMaxRange.x;
Manager.Instance.radarRangeSize.y = (int)Manager.Instance.radarMaxRange.y;
// CHECK FOR TILES AROUND THE PLAYER WITH A MAX DISTANCE BASED ON radarMaxRange
for (int y = Manager.Instance.playerPosition.y - Manager.Instance.radarRangeSize.y; y < (Manager.Instance.playerPosition.y + Manager.Instance.radarRangeSize.y); y++)
{
for (int x = Manager.Instance.playerPosition.x - Manager.Instance.radarRangeSize.x; x < (Manager.Instance.playerPosition.x + Manager.Instance.radarRangeSize.x); x++)
{
Vector3 tilePosition = new Vector3(x, y, 0);
Vector3Int tilePositionInt = new Vector3Int(Mathf.RoundToInt(tilePosition.x), Mathf.RoundToInt(tilePosition.y), 0);
Tile tile = Manager.Instance.tilemap.GetTile<Tile>(tilePositionInt);
if (tile != null && tile.name == "Black") // CHECK IF THERE IS A BLACK TILE
{
// PLACE TileCollider ON EVERY FOUND BLACK TILE
Instantiate(TileCollider, tilePosition, Quaternion.identity);
}
}
}
}
I'm using a Singleton to store global variables which is why you see "Manager.Instance" everywhere. As you can see this method spawns a prefab wherever there's a black tile. Then inside these spawned prefabs there's a script that turns the tile under them green when the go_Radar CircleCollider2D collides with them.
public class TileCollision : MonoBehaviour
{
// CHANGE TILES ACCORDING TO COLLISIONS
void OnCollisionEnter2D(Collision2D collision)
{
Vector3 hitPosition = Vector3.zero;
{
hitPosition.x = this.transform.position.x+0.5f; // COMPENSATE THE POSITION TO FIT THE GRID SINCE THE PREFABS ARE NOT PLACED ON THE CENTER OF EACH CELL.
hitPosition.y = this.transform.position.y;
if (Manager.Instance.go_Radar == collision.gameObject)
{
// SETS THE TILE GREEN
Manager.Instance.tilemap.SetTile(Manager.Instance.tilemap.WorldToCell(hitPosition), Manager.Instance.tileGreen); // tileGreen is loaded from Resources in another script
}
}
}
}
I also added another script in these prefabs to Destroy them after some time related with the frequency of the scan.
public class DestroySelf : MonoBehaviour
{
float time;
private void Start()
{
time = Manager.Instance.radarFrequency - (Manager.Instance.radarFrequency - 1);
Destroy(this.gameObject, time);
}
}
Just in case you were curious how I did it, there it is.
Your answer
Follow this Question
Related Questions
How To Smoothly Climb Over Tiles? 1 Answer
Are there any good auto tile tutorials for procedurally generated worlds? 0 Answers
How do I create tiles that I can add scripts to, and have players interact with? 0 Answers
Bounds and extents of a tilemap collider across differing y axes, Tilemap collider bounds 0 Answers