Reputation: 886
We have a parent object, let's call it RectangleParent
, and we want to place child objects, in our case Squares
, (a total determined at runtime within the a range of 1-10) within this surface. Both inside the bounds of our parent object, RectangleParent
, evenly spaced from each other and from left to right in a maximum of two rows (5 items a row max, two rows max, equals 10 sqaures max).
EDIT start
end EDIT
Sample Unity pkg here
Correct example(s):
Ten (10) objects to place
Five (5) objects to place
Current result
Notice our parent object at origin (parent objects being the elongated rectangles, child objects being the smaller squares). It's children are placed as desired, meeting all requirements. Placed within parent bounds, Two rows evenly spaced from each other within their parents bounds, and Each child object is evenly spaced from one another. As pictured in the Ten (10) objects example.
But then notice, for the parent object not located at origin - child objects (Squares) not placed within their parents boundaries, the spacing between the two rows does not fit within the parents bounds, and the objects are no longer squares (they look like rectangles now). However the child objects within each row are spaced evenly between one another so there is at least one desire met here.
If we assign Cube.transform
.localPosition instead of .position
At origin: The spacing between the rows is still correct but now the spacing between the child objects (squares) within each row is incorrect and as well all the child objects are not keeping within their parents bounds.
Away from origin: The two rows are aligned correctly, but the spacing between the two rows is incorrect. The two rows are not fitting within their parent objects boundaries. The child objects themselves have multiple problems. They are not squares and their spacing between one another is incorrect.
So what is wrong with our 3d placement math? How to fix our object placement, so that no matter where our parent object is, our children are placed within the bounds of their parent?
Code
public class NewBehaviourScript : MonoBehaviour {
public int NumberOfObjectsToPlace = 10; //Place 10 objects
public int maxRows = 5; // how many objects can be placed in a row
public int maxColumns = 2; // how many objects can be placed in a column
public GameObject RectangleParent; //the parentObject instance
public GameObject CubePrefab; //the cube prefab
// Use this for initialization
void Start () {
PlaceObjects();
}
// Update is called once per frame
void Update () {
}
void PlaceObjects()
{
Vector3 center = RectangleParent.GetComponent<MeshRenderer>().bounds.center;
Vector3 size = RectangleParent.GetComponent<MeshRenderer>().bounds.size;
Vector3 corner = -new Vector3(size.x / 2, 0, size.z / 2);
float stepX = size.x / (maxColumns + 1);
float stepZ = size.z / (maxRows + 2);
int placedObjects = NumberOfObjectsToPlace;
for (int i = 0; i < placedObjects; i++)
{
GameObject Cube = Instantiate(CubePrefab);
Cube.transform.parent = RectangleParent.transform;
Cube.transform.localRotation = Quaternion.identity;
Cube.transform.position = corner + new Vector3(stepX,
center.y + 0.15f,
stepZ * 1.5f + i * stepZ
);
if (i == maxRows - 1)
{
i -= maxRows;
placedObjects -= maxRows;
stepX += size.x / (maxColumns + 1);
}
}
}
}
(thanks to @Ali-Baba for all their help)
Upvotes: 0
Views: 560
Reputation: 90570
You have to use the position and directions of RectangleParent
like
Cube.transform.position = RectangleParent.transform.position
+ corner.x * RectangleParent.transform.right
+ corner.y * RectangleParent.transform.up
+ corner.z * RectangleParent.transform.forward
+ stepX * RectangleParent.transform.right
+ (center.y + 0.15f) * RectangleParent.transform.up
+ (stepZ * 1.5f + i * stepZ) * RectangleParent.transform.forward;
or alternatively you should rather use localPosition
. Problem here might be that if the scale of RectangleParent
is not 1,1,1
the value of localPosition
might get scaled along with it so you might want to do
Cube.transform.localPosition = new Vector3(
corner.x / RectangleParent.transform.localScale.x,
corner.y / RectangleParent.transform.localScale.y,
corner.z / RectangleParent.transform.localScale.z)
+ new Vector3(
stepX / RectangleParent.transform.localScale.x,
center.y + 0.15f,
(stepZ * 1.5f + i * stepZ) / RectangleParent.transform.localScale.z
);
and then for resetting the scale correctly you might want to do
Cube.transform.localScale = new Vector3(
1 / RectangleParent.transform.localScale.x,
1 / RectangleParent.transform.localScale.y,
1 / RectangleParent.transform.localScale.z
);
using
private void PlaceObjects()
{
var center = RectangleParent.GetComponent<MeshRenderer>().bounds.center;
var size = RectangleParent.GetComponent<MeshRenderer>().bounds.size;
var corner = -new Vector3(size.x / 2, 0, size.z / 2);
var stepX = size.x / (maxColumns + 1);
var stepZ = size.z / (maxRows + 2);
var placedObjects = NumberOfObjectsToPlace;
for (var i = 0; i < placedObjects; i++)
{
var cube = Instantiate(CubePrefab);
cube.transform.parent = RectangleParent.transform;
cube.transform.localRotation = Quaternion.identity;
cube.transform.localPosition = new Vector3(
corner.x / RectangleParent.transform.localScale.x,
corner.y / RectangleParent.transform.localScale.y,
corner.z / RectangleParent.transform.localScale.z
)
+ new Vector3(
stepX / RectangleParent.transform.localScale.x,
center.y + 0.15f,
(stepZ * 1.5f + i * stepZ) / RectangleParent.transform.localScale.z
);
cube.transform.localScale = new Vector3(
1 / RectangleParent.transform.localScale.x,
1 / RectangleParent.transform.localScale.y,
1 / RectangleParent.transform.localScale.z
);
if (i != maxRows - 1) continue;
i -= maxRows;
placedObjects -= maxRows;
stepX += size.x / (maxColumns + 1);
}
}
Upvotes: 2