- Home /
prefab instantiated by script containing ShadowCaster2D bugs out
Hey,
i wrote a script that creates shadow casters for a tilemap-grid. The generation is triggered by a button press from the inspector. Since i was unable to figure out how to manipulate the "shape" of a given ShadowCaster2D from script, i made a prefab that has a 1 by 1 ShadowCaster2D attached, instantiate that from my script and set the scale and position. It works fine, the screenshot shows the result of such a generation. However, when i try to manipulate the shape by hand afterwards, i am unable to generate new nodes, and the nodes i try to reposition snap to the gameobjects origin and stay there. When placing and scaling up instances of the prefab manually, it works fine. Is this a bug with prefab instantiation and the ShadowCaster2D's shape-thingy?
So my question is: Any ideas on how to fix that? My original goal was to generate the shadow casters in a way so that i can tweak them by hand afterwards if i desire.
I also have trouble how to make the editor save the instances. i tried to do a Undo.RecordObject on them afterwards, and tried moving the generate code into the button that triggers if, both of which failed to achive permanence. but thats a side-problem, help would be appreciated anyway.
I think many people would potentially be interested in a script like this, when it first successfully generated the shadow casters i was eager to tell the forums about it :) But right now its of limited use. I really hope someone can help me fix this.
Here's a screenshot of the generated shadow casters:
Here is how i instantiate the prefab:
currentInstance = (GameObject)PrefabUtility.InstantiatePrefab(shadowCasterPrefab, shadowCastersContainer);
Here's the complete script:
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
public class GridShadowCastersGenerator : MonoBehaviour {
public string colliderTag = "GenerateShadowCasters";
public GameObject shadowCasterPrefab;
public Transform shadowCastersContainer;
public bool removePreviouslyGenerated = true;
bool[,] hits;
GameObject[,] instances;
public GameObject[] Generate() {
Debug.Log("### Generating ShadowCasters ###");
/* get the bounds of the area to check */
// collect colliders specified by tag
var colliders = new List<Collider2D>();
var tagedGos = GameObject.FindGameObjectsWithTag(colliderTag);
foreach (var go in tagedGos) {
var goColliders = go.GetComponents<Collider2D>();
foreach (var goc in goColliders) {
colliders.Add(goc);
}
}
if (colliders.Count == 0) {
Debug.Log("No colliders found, aborting.");
return new GameObject[0];
}
// get outer-most bound vertices, defining the area to check
var bottomLeft = new Vector2(Mathf.Infinity, Mathf.Infinity);
var topRight = new Vector2(-Mathf.Infinity, -Mathf.Infinity);
foreach (var col in colliders) {
bottomLeft.x = Mathf.Min(bottomLeft.x, Mathf.Floor(col.bounds.min.x));
bottomLeft.y = Mathf.Min(bottomLeft.y, Mathf.Floor(col.bounds.min.y));
topRight.x = Mathf.Max(topRight.x, Mathf.Ceil(col.bounds.max.x));
topRight.y = Mathf.Max(topRight.y, Mathf.Ceil(col.bounds.max.y));
}
Debug.Log("Bounds: downLeft = (" + bottomLeft.x + ", " + bottomLeft.y + ")");
Debug.Log("Bounds: topRight = (" + topRight.x + ", " + topRight.y + ")");
/* check the area for collisions */
var countX = Mathf.RoundToInt(topRight.x - bottomLeft.x);
var countY = Mathf.RoundToInt(topRight.y - bottomLeft.y);
hits = new bool[countX, countY];
instances = new GameObject[countX, countY];
for (int y = 0; y < countY; y++) {
for (int x = 0; x < countX; x++) {
hits[x, y] = IsHit(new Vector2(bottomLeft.x + x + 0.5f, bottomLeft.y + y + 0.5f));
}
}
/* instantiate shadow casters, merging single tiles horizontaly */
// removing old shadow casters! careful!
if (removePreviouslyGenerated) {
foreach (Transform shadowCaster in shadowCastersContainer) {
DestroyImmediate(shadowCaster.gameObject);
}
}
// create new ones
for (int y = 0; y < countY; y++) {
var previousWasHit = false;
GameObject currentInstance = null;
for (int x = 0; x < countX; x++) {
if (hits[x, y]) {
if (!previousWasHit) {
// create new shadowCasterPrefab instance
//currentInstance = (GameObject)Instantiate(shadowCasterPrefab, shadowCastersContainer.transform);
currentInstance = (GameObject)PrefabUtility.InstantiatePrefab(shadowCasterPrefab, shadowCastersContainer);
currentInstance.transform.position = new Vector3(bottomLeft.x + x + 0.5f, bottomLeft.y + y + 0.5f, 0.0f);
} else {
// stretch prevois shadowCasterPrefab instance
var newWidth = currentInstance.transform.localScale.x + 1.0f;
currentInstance.transform.localScale = new Vector3(newWidth, 1.0f, 0.0f);
currentInstance.transform.Translate(new Vector3(0.5f, 0.0f, 0.0f));
}
instances[x, y] = currentInstance;
previousWasHit = true;
} else {
previousWasHit = false;
}
}
}
/* merge vertically if they have the same dimensions */
for (int y = 0; y < countY - 1; y++) { // -1 for skipping last row
for (int x = 0; x < countX; x++) {
if (instances[x, y] != null && instances[x, y + 1] != null) {
var topInstance = instances[x, y];
var bottomInstance = instances[x, y + 1];
if (topInstance != bottomInstance && topInstance.transform.localScale.x == bottomInstance.transform.localScale.x) {
//merge! enlarge top instance...
topInstance.transform.localScale = new Vector3(topInstance.transform.localScale.x, topInstance.transform.localScale.y + 1.0f, 0.0f);
topInstance.transform.Translate(new Vector3(0.0f, 0.5f, 0.0f));
// ...destroy bottom instance, save to instances array
for (var i = 0; i < Mathf.RoundToInt(bottomInstance.transform.localScale.x); i++) {
instances[x + i, y + 1] = instances[x + i, y];
}
DestroyImmediate(bottomInstance);
}
}
}
}
Debug.Log("ShadowCasters generated.");
/* return shadow casters */
var shadowCasterInstances = new List<GameObject>();
for (int y = 0; y < countY; y++) {
for (int x = 0; x < countX; x++) {
if (instances[x, y] != null && !shadowCasterInstances.Contains(instances[x, y])) {
shadowCasterInstances.Add(instances[x, y]);
instances[x, y].name = instances[x, y].name + "_" + shadowCasterInstances.Count.ToString();
}
}
}
return shadowCasterInstances.ToArray();
}
bool IsHit(Vector2 pos) {
var margin = .2f; // prevents overlapping
// get tile bounds
var bottomLeft = new Vector2(pos.x - 0.5f + margin, pos.y + 0.5f - margin);
var topRight = new Vector2(pos.x + 0.5f - margin, pos.y - 0.5f + margin);
//check for collisions
Collider2D[] colliders = Physics2D.OverlapAreaAll(bottomLeft, topRight);
foreach (var col in colliders) {
if (col.CompareTag(colliderTag)) {
return true;
}
}
return false;
}
}
[CustomEditor(typeof(GridShadowCastersGenerator))]
public class GridShadowCastersGeneratorEditor : Editor {
public override void OnInspectorGUI() {
DrawDefaultInspector();
if (GUILayout.Button("Generate")) {
var generator = (GridShadowCastersGenerator)target;
Undo.RecordObject(generator.shadowCastersContainer, "GridShadowCastersGenerator.generate");
generator.Generate();
}
}
}
Your answer
Follow this Question
Related Questions
Infinity runner - best way to spawn board in runtime. 0 Answers
When flipping player, instantiated objects spawn on different spot. 2D shooting 0 Answers
How to move Instantiated 2D objects by 0.5 using arrows 1 Answer
Instantied 2D Prefab Is Invisible 1 Answer
How to instantiate and destroy objects with 2d trigger 1 Answer