I need to place a stack of boxes on top of each other based on the height of the previous box.
The box's heights are dynamic.
foreach( cBox box in currentLevel.mMiddleRack.BoxWeightList)
{
box.mBoxImage = (GameObject) Instantiate(boxTemplate);
box.setBoxPosition(firstBoxPostion.x, firstBoxPostion.y, firstBoxPostion.z);
firstBoxPostion.y += box.mBoxImage.transform.localScale.y;
firstBoxPostion.z -= 1.0f;
box.shapeBox();
}
The Result
Transform.localscale doesn't provide the size of the object, unless the object coincidentally happens to have the same scale as its size (primitive object, which has a size of (1,1,1)).
Try getting the size of the object by using BoxCollider or, if using 2D physics, BoxCollider2D. Use the size variable to help calculate the position of the boxes.
Related
I have written some code that snaps a cylinder to an existing cylinder using a for loop on a gameobject list I call cylinders. Below is the code I use for "snapping" the cylinder to another cylinder using the mouse position and a "translucentPrefab". I would like to know if there is another object obstructing the placement. For performance reasons I would like to avoid using another for loop through my list to check each position. Is there any good solution for this. Could I use a "fake" 2d array since I mostly use full integer boxes and set squares to occupied in that array. Or is there a smarter approach?
`if (worldMousePosition.x > centerPoint.x && Vector3.Distance(worldMousePosition, centerPoint) < snappingRange)
{
translucentPrefab.transform.position = rightPosition;
snapped = true;
left = false;
if (renderer != null)
{
// Set the prefab material to translucent and green
material.color = new Color(0, 1, 1, 0.5f);
}
}`
I have tried using box colliders in many ways to check in the same space as the new cylinder, however all attempts have been a faliure.
I suggest you to use Physics.SphereCastAll at point where you cursor is and just iterate over all object that SphereCastAll returns.
And if you don't want objects to count toward physics you can add special physic layer for just this. And that adjust collision matrix.
I have a line with line renderer attached to it . The user can move the line and rotate it. How do I go about getting the new positions of the line renderer which has been moved or rotated? since the coordinates of vertices of line renderer do not change , only the positions and the rotation of the line object as a whole changes .
The positions in the bottom part of image do not change on moving or rotating it. These positions are returned by the getpositions() method which is not useful in my case.
The LineRenderer in unity takes a list of points (stored as Vector3s) and draws a line through them. It does this in one of two ways.
Local Space: (Default) All points are positioned relative to
transform. So if your GameObject moves or rotates, the line would
also move and rotate.
World Space: (You would need to check the Use World Space
Checkbox) The line will be rendered in a fixed position in the
world that exactly matched the Positions in the list. If the
gameObject moves or rotates, the line would be unchanged
So what you really want to know is
"How do I get the world space position of a local space point in my line?"
This common use case is addressed by methods on a gameObjects transform
Transform.TransformPoint
It takes a local space point (which is how the data is stored in the line renderer by default) and transforms it to world space.
An Example:
using UnityEngine;
using System.Collections;
public class LineRendererToWorldSpace : MonoBehaviour
{
private LineRenderer lr;
void Start()
{
lr = GetComponent<LineRenderer>();
// Set some positions in the line renderer which are interpreted as local space
// These are what you would see in the inspector in Unity's UI
Vector3[] positions = new Vector3[3];
positions[0] = new Vector3(-2.0f, -2.0f, 0.0f);
positions[1] = new Vector3(0.0f, 2.0f, 0.0f);
positions[2] = new Vector3(2.0f, -2.0f, 0.0f);
lr.positionCount = positions.Length;
lr.SetPositions(positions);
}
Vector3[] GetLinePointsInWorldSpace()
{
Vector3[] positions;
//Get the positions which are shown in the inspector
var numberOfPositions = lr.GetPositions(positions);
//Iterate through all points, and transform them to world space
for(var i = 0; i < numberOfPositions; i += 1)
{
positions[i] = transform.TransformPoint(positions[i]);
}
//the points returned are in world space
return positions;
}
}
This code is just for demonstration purposes, as I am not exactly sure of the use case.
Also, my links are to 2018.2 which is a very recent version of unity, however the logic and methods used should be quite similar going back.
I discovered something interesting about Unity Sprite and textures (Texture2D). I crated a 50x50 .png and render it in Unity by attaching to a GameObject and using SpriteRenderer.
What I realized, whenever I call a Unity related method (sprite.texture.width, sprite.rect.width, sprite.textureRect.width, etc.), it always return 50. However, the real size of the image turns into 24x24 or 12x12 depending on the resolution on my screen.
Of course, this is no big surprise since the projection, etc. is applied before Unity render the things on the screen; however, the interesting part I couldn't find any method or easy way to get the size of the Sprite after the projection is applied.
I can still make my own projection to come up with the related size; however, I would like to know whether there is an easier way to get this information.
Thank you!
The way #Draco18s mentioned seems the only way to solve this problem.
So, I crated a Prefab GameObject containing RectTransform and SpriteRenderer, and got the width and height as below:
GameObject twoSide = Instantiate(Resources.Load(mFilePath + "Locater")) as GameObject;
twoSide.GetComponent<RectTransform>().position = Camera.main.ScreenToWorldPoint (new Vector3 (0, 0, 1));
twoSide.GetComponent<RectTransform> ().pivot = new Vector2 (0f, 0f); // RectTransform should have the same pivot location with Sprite
float width = twoSide.GetComponent<RectTransform> ().offsetMax.x - twoSide.GetComponent<RectTransform> ().offsetMin.x;
float height = twoSide.GetComponent<RectTransform> ().offsetMax.y - twoSide.GetComponent<RectTransform> ().offsetMin.y;
I have this code that instantiates GameObjects at the top of the screen and then they fall down.
float RandX = GetRandomXPos();
float RandY = screenSize.y;
Vector3 ballPos = new Vector3(RandX,RandY,0);
GameObject clone = Instantiate(BallPrefab, ballPos, transform.rotation) as GameObject;
This works fine but it spawn them at the top of the screen so they just blink into existence. I want to spawn them at the top of the screen plus the height of the prefab so that it can appear out of view and then fall down into view.
What is the best way to get that height that I need to offset by?
To get the size of the prefab you need to get the information of the Renderer that the prefab has.
To do this you have to get the component in its hierarchy, you can do this by using GetComponentInChildren<Renderer>()
Once you got the Renderer, you can access the bounds size with renderer.bounds.size
This is a Vector3 which has the dimensions of the object, height being the Y component.
You may have more than one Renderer in a prefab so you will need to get them all with GetComponentsInChildren<Renderer>(). and calculate the sum of all the bounds using bounds.Encapsulate
var renderer = target.GetComponentInChildren<Renderer>();
var height = renderer.bounds.size.y;
In my Unity2D project, I am trying to spawn my sprite on top of each other and across the entire height of the device's screen. For example to give an idea, think of a box on top of each other across the entire device's screen height. In my case, I'm spawning arrow sprites instead of boxes
I already got the sprites spawning on top of each other successfully. My problem now is how to calculate how many sprites to spawn to make sure it spreads across the screen's height.
I currently have this snippet of code:
public void SpawnInitialArrows()
{
// get the size of our sprite first
Vector3 arrowSizeInWorld = dummyArrow.GetComponent<Renderer>().bounds.size;
// get screen.height in world coords
float screenHeightInWorld = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).y;
// get the bottom edge of the screen in world coords
Vector3 bottomEdgeInWorld = Camera.main.ScreenToWorldPoint(new Vector3(0,0,0));
// calculate how many arrows to spawn based on screen.height/arrow.size.y
int numberOfArrowsToSpawn = (int)screenHeightInWorld / (int)arrowSizeInWorld.y;
// create a vector3 to store the position of the previous arrow
Vector3 lastArrowPos = Vector3.zero;
for(int i = 0; i < numberOfArrowsToSpawn; ++i)
{
GameObject newArrow = this.SpawnArrow();
// if this is the first arrow in the list, spawn at the bottom of the screen
if(LevelManager.current.arrowList.Count == 0)
{
// we only handle the y position because we're stacking them on top of each other!
newArrow.transform.position = new Vector3(newArrow.transform.position.x,
bottomEdgeInWorld.y + arrowSizeInWorld.y/2,
newArrow.transform.position.z);
}
else
{
// else, spawn on top of the previous arrow
newArrow.transform.position = new Vector3(newArrow.transform.position.x,
lastArrowPos.y + arrowSizeInWorld.y,
newArrow.transform.position.z);
}
// save the position of this arrow so that we know where to spawn the next arrow!
lastArrowPos = new Vector3(newArrow.transform.position.x,
newArrow.transform.position.y,
newArrow.transform.position.z);
LevelManager.current.arrowList.Add(newArrow);
}
}
The problem with my current code is that it doesn't spawn the correct number of sprites to cover the entire height of the device's screen. It only spawns my arrow sprites approximately up to the middle of the screen. What I want is for it to be able to spawn up to the top edge of the screen.
Anyone know where the calculation went wrong? and how to make the current code cleaner?
If sprites are rendered via camera mode in perspective and the sprites appear to have varying sizes when displayed on the screen (sprites farther away from the camera are smaller than sprites that are closer to the camera) then a new way to calculate the numberOfArrowsToSpawn value is needed.
You could try adding sprites with a while loop, instead of using a for loop, just continue creating sprites until the calculated world position for the sprite will no longer be visible to the camera. Check to see if a point will be visible in camera by using the technique Jessy provides in this link:
http://forum.unity3d.com/threads/point-in-camera-view.72523/
I think your screenHeightInWorld is really a screenTopInWorld, a point can be anywhere in the space.
You need the relative screen height in world coordinate.
Which is actially the half of the camera frustum size if you use ortographic projection, as you think of it.
float screenHeightInWorld = Camera.main.orthographicSize / 2.0f;
I did not read the rest, but is probably fine, up to you how you implement this.
I'd simply create an arrow method, something like bool SpawnArrowAboveIfFits(), which can call itself iteratively on the new instances.