- Home /
How to make an Image's position fixed on Canvas
Hello,my name is Saulo and I need some help with my UI.
So,I have this game that you can use a npc to go to a place and build a tower on top of it.When the builder arrives the place,I instatiate a "loading" UI such as the image below to derteminate when the building will be complete:
The problem is,I have an Script to move the camera,and since I'm instantiating the UI on the Canvas,when I move my camera,everything moves together:
And I get this horrible effect of a loading bar floating around. I would like to know how can I make my image to have a position fixed in the world and not to be related to the canvas position. So if I move my camera,the UI loading bar doesn't come with it.
I know there's an option on canvas to set it to be rendered as world space.Altough,as you can see I have other UI elemets that I would like to keep it with the camera,such as the scoreboard.
Thank you very much.
Answer by zMalik · Jul 23, 2017 at 10:02 PM
Ok,so I apologize for my inconvinience. It turned out that it was simplier than I tought .As @hexagonius said,we can create more than one canvas in the scene.So,I just created another canvas(Canvas2) and set it's RenderMode to "World Space".Also,as my game is top-down camera,I rotated this canvas 90º on the x axis and adjust its size so it could cover all my map.After that I was looking for a way to convert the world space coordinates (where my timer would be instantiated) to screen coordinates and then instantiate the object on the canvas.Altough,as Canvas2 is set to world space,we don't have to convert anything(And took me a lot of testing to come up with that). If any of you are interested in this,here's my final code:
public class FloatingTimeBuildingController : MonoBehaviour {
private static FloatingTimeBuild popupTimer;
private static GameObject canvas;
public static void Initialize(){
canvas = GameObject.Find ("Canvas2");
if(!popupTimer)
popupTimer = Resources.Load<FloatingTimeBuild> ("Timer/TimerParent");
}
public static void CreateFloatingText(Transform location,float timeToBuild){
FloatingTimeBuild instance = Instantiate (popupTimer);
instance.timeToBuild = timeToBuild;
instance.transform.SetParent (canvas.transform,false);
instance.transform.position = new Vector3(location.position.x + 40,location.position.y + 50,location.position.z + 80);
}
}
Wich "location" is the transform in the world space where I want to instantiate my timer and time to build to run the corroutine.We have to call "Initialize" function in a game manager. Also,I had to make some few adjustments on the coordinates to fit my purpose.
Thank you all.
Answer by hexagonius · Jun 12, 2017 at 06:19 PM
You can have multiple canvases, no need to fit all into one. They can be different too.
You can attach a script into the loading bar which positions the bar every frame to where it should be, coverting it's world to it's canvas space. I think there's even a position value for a recttransform that does that, position3d or something.
Hello,thank you very much for the answer @hexagonius .Altough,I spent many hours trying to solve the problem I just can't get it to work.Can you please give me some more information?
So,I tried to create another canvas and set it's Render to "World Space".Then I rotated the Canvas gameobject in 90º on X axis(Because my game is top-down view),but I can't get the loading UI to instantiate in the correct position.It instantiates,but in some random position far away from where I want.Can you give me some help please? Here's my code:
public class FloatingTimeBuildingController : $$anonymous$$onoBehaviour {
private static FloatingTimeBuild popupTimer;
private static GameObject canvas;
public static void Initialize(){
canvas = GameObject.Find ("Canvas2");
if(!popupTimer)
popupTimer = Resources.Load<FloatingTimeBuild> ("Timer/TimerParent");
}
public static void CreateFloatingText(Transform location){
//Location is the transform of the tile the building is going to be built.
FloatingTimeBuild instance = Instantiate (popupTimer);
Vector2 screenPosition = Camera.main.WorldToScreenPoint(new Vector3(location.position.x,location.position.y,location.position.z));
instance.transform.SetParent (canvas.transform,false);
instance.transform.position = screenPosition;
}
}
Answer by Davinder_Singh · Jun 13, 2017 at 03:58 AM
@zMalik,,, you can try setting the position of your loading bar using Vector3 via a script. If that doesn't work, you can also try to make the loading bar the child of an empty game object whose position is fixed on screen and hence the position of loading bar will also be fixed. If it still doesn't works, please tell me.