Reputation: 1580
I am trying to copy the Zelda health system. The code looks really fine and works fine.
But the heart containers are placed wrong. They get instantiated below the canvas.
This is the important code, the heart containers are correct, just at the wrong position.
The calculation of x and y is correct, but on the canvas it is not.
private Transform healthBar = GameObject.FindGameObjectWithTag("HealthController").transform; // container for the heartContainers
private GameObject healthWrapperObject = Resources.Load("HealthContainer") as GameObject; // the backgroundImage and parent of the heart
private List<Image> healthContainers = new List<Image>(); // list of hearts for later usages
private int maxHealth = 6;
private int currentHealth;
private int healthPerHealthContainer = 4; // 4 lifepoints per heart
private int healthContainersPerRow = 5; // 5 hearts per row
private int healthContainerStartPositionX = 0; // Healthbar starts at 0 on x
private int healthContainerStartPositionY = 0; // Healthbar starts at 0 on y
private int healthContainerSpacingX = 10; // horizontal spacing
private int healthContainerSpacingY = -10; // vertical spacing
private void Start()
{
currentHealth = maxHealth;
InitializeHealthBar();
}
public void InitializeHealthBar()
{
int neededHealthContainers = maxHealth % healthPerHealthContainer == 0 ? maxHealth / healthPerHealthContainer : maxHealth / healthPerHealthContainer + 1; // Calculate the needed container count
int counter = 0; // counts the hearts per row
int x = healthContainerStartPositionX; // horizontal position of the heartContainer
int y = healthContainerStartPositionY; // vertical position of the heartContainer
for (int i = 0; i < neededHealthContainers; i++)
{
counter++;
if (counter >= healthContainersPerRow) // start a new line after 5 hearts per row
{
x = healthContainerStartPositionX; // move back to the left
y += healthContainerSpacingY; // go for the next line
counter = 0; // reset the counter
}
else
x += healthContainerSpacingX; // place the new container right next to the previous
Transform newHealthContainerTransform = Instantiate(healthWrapperObject, new Vector2(x, y), healthWrapperObject.transform.rotation).transform; // create the healthContainer parent / backgroundImage
newHealthContainerTransform.SetParent(healthBar); // take the container and make it a child of the healthBar
healthContainers.Add(newHealthContainerTransform.GetChild(0).GetComponent<Image>()); // get the heart of the heartContainer and add it to the heartList
}
}
I added the transform settings for the healthBar, the healthContainer / backgroundImage and the heart ("healthfill").
On all 3 elements I pressed Strg+Alt and Shift for anchoring them.
The heartcontainter should be added to the healthbar, the heart is a child of the heartcontainer and is set to stretch (it should be the same size as its parent)
Why are the UI prefab Objects instantiated below the canvas?
Upvotes: 0
Views: 976
Reputation: 125275
I assume you are getting something like this:
You fix this by pass false
to the second parameter of the SetParent
function. By doing this, you will make the Transform keep its local orientation rather than its global orientation.
Simply replace :
newHealthContainerTransform.SetParent(healthBar);
with:
newHealthContainerTransform.SetParent(healthBar, false)
You can also set the parent Object and make the instantiated Object's Transform keep its local orientation in the Instantiate
function. The only disadvantage of this is that you now have to set the position of object in another line of code instead of the Instantiate
function like before.
Transform newHealthContainerTransform = Instantiate(healthWrapperObject, healthBar, false).transform;
newHealthContainerTransform.GetComponent<RectTransform>().anchoredPosition3D = new Vector2(x, y);
When moving a UI Object you should be modifying it's RectTransform
variables instead of the Transform
variables.
Below are other useful variables that determines where to position the UI:
These are anchoredPosition
, anchoredPosition3D
, anchorMax
and anchorMin
which can be modified with:
yourUIObj.GetComponent<RectTransform>().anchoredPosition = ...
yourUIObj.GetComponent<RectTransform>().anchoredPosition3D = ...
yourUIObj.GetComponent<RectTransform>().anchorMax = ...
yourUIObj.GetComponent<RectTransform>().anchorMin = ...
Upvotes: 2