(in Unity 3D)
Hi.
I want to show "HPBar" of the character on UI Canvas.
I tried the following method, but it didn't work normally.
Please tell me how to solve this problem...
/// <summary>
/// Follow target's position
/// </summary>
/// <param name="target">target(character's world position)</param>
void ChaseCharacter(Vector3 target)
{
// change world position to screen position (Main Camera)
Vector3 p1 = _worldCam.WorldToScreenPoint(target);
// change screen position to world position (UI Camera)
Vector3 p2 = _uiCam.ScreenToWorldPoint(p1);
// Apply UI Position
transform.position = p2;
}
I've built a minimal example, with a single camera. I guess with some small tweaks it should work on your multi-camera case.
public class UIFollow : MonoBehaviour
{
public GameObject target;
public Vector2 offset;
new private Camera camera;
void Start()
{
camera = GetComponentInParent<Canvas>().worldCamera;
}
void Update()
{
((RectTransform)transform).anchoredPosition = camera.WorldToScreenPoint(target.transform.position) + (Vector3)offset;
}
}
UIFollow is a Component on the "HealthBar" object inside the Canvas. Make sure it's anchors are set to the left bottom corner.
The offset vector is used to place the health bar above the object's center, it's public so it's easier to modify while designing the game.
From the hierarchy tab, add a new object, section UI then select Image, a canvas object should appear if not already created, inside should be the white image created , this Image should already follow your camera to every place because its in the UI screen section not near the player, just resize, make transparent and add your health bar inside it.
Thank you all for your advice.
I solved this problem, but I don't know how it was solved.
I'll upload the resolved code.
Vector3 p1 = _worldCam.WorldToScreenPoint(target);
p1.z = 100;
Vector3 p2 = _uiCam.ScreenToWorldPoint(p1);
transform.position = p2;
Related
I want an UI canvas to follow the camera so it will be in front of the head always and also interactable like VR menu. I'm using the following code to do so.
public class FollowMe : MonoBehaviour
{
public GameObject menuCanvas;
public Camera FirstPersonCamera;
[Range(0, 1)]
public float smoothFactor = 0.5f;
// how far to stay away fromt he center
public float offsetRadius = 0.3f;
public float distanceToHead = 4;
public void Update()
{
// make the UI always face towards the camera
menuCanvas.transform.rotation = FirstPersonCamera.transform.rotation;
var cameraCenter = FirstPersonCamera.transform.position + FirstPersonCamera.transform.forward * distanceToHead;
var currentPos = menuCanvas.transform.position;
// in which direction from the center?
var direction = currentPos - cameraCenter;
// target is in the same direction but offsetRadius
// from the center
var targetPosition = cameraCenter + direction.normalized * offsetRadius;
// finally interpolate towards this position
menuCanvas.transform.position = Vector3.Lerp(currentPos, targetPosition, smoothFactor);
}
}
Unfortunately, the canvas is flickering in front fo the camera and it is not properly positioned. How do I make the menu to follow the camera?|
If there is no reason against it you can use a ScreenSpace - Camera canvas as stated in the docs. Then you can reference your FPS camera as the rendering camera for the canvas.
Easy way to do this is using Screen Space - Camera mode which you can setup from Canvas component and in Render Mode properties.
Second way if you want more control over how your canvas should behave then you can use Canvas Render Mode - "World Space" and then using script you can handle canvas a some gameobject.
I need little help with function WorldToScreenPoint(position), Could somebody guide me little bit ? I am using this function to display name of the city:
public class LabelsTest : MonoBehaviour
{
[SerializeField]
private Text nameLabel;
// Update is called once per frame
void Update()
{
Vector3 cameraPos = Camera.main.WorldToScreenPoint(transform.position);
nameLabel.transform.position = cameraPos;
}
}
But problem is that I see UI with text two times, one above the plane which is perfect:
but when I face away from the plane, I can see the label there, too.:
I don't know if I am doing something wrong or it just not working as it should.
Thanks for help.
You need to prevent the Text from rendering while it is behind the camera. Luckily, WorldToScreenPoint gives you a z component that tells you how far in front of the camera the point is. So, just set the Text to be enabled when z>0 and disabled when z<=0:
public class LabelsTest : MonoBehaviour
{
[SerializeField]
private Text nameLabel;
// Update is called once per frame
void Update()
{
Vector3 cameraPos = Camera.main.WorldToScreenPoint(transform.position);
nameLabel.transform.position = cameraPos;
nameLabel.enabled = cameraPos.z>0;
}
}
That's because your 'Plane' is culling the backface, meaning when the Plane is up at a certain point higher than the Camera's Y position it goes invisible.
Here's a GIF of the problem.
https://gyazo.com/d22c51951d1e8abd07a354af7f48ffef
so this is what happens when Im using vector 3 on my game I want my vector 3 to be on specific position for different screen sizes? is that possible? here is my codes
public virtual void ShuffleButton()
{
Vector3 buttonFirst = gameButtons[0].transform.position;
buttonFirst.x += 297f;
gameButtons[0].transform.position = buttonFirst;
Vector3 buttonSecond = gameButtons[1].transform.position;
buttonSecond.x -= 74.25f;
gameButtons[1].transform.position = buttonSecond;
Vector3 buttonThird = gameButtons[2].transform.position;
buttonThird.x += 74.25f;
gameButtons[2].transform.position = buttonThird;
Vector3 buttonFourth = gameButtons[3].transform.position;
buttonFourth.x -= 148.5f;
gameButtons[3].transform.position = buttonFourth;
Vector3 buttonFifth = gameButtons[4].transform.position;
buttonFifth.x -= 148.5f;
gameButtons[4].transform.position = buttonFifth;
}
You are looking for the position conversion functions like Camera.ScreenToWorldPoint(). These can be found in the Unity Camera class documentation here: https://docs.unity3d.com/ScriptReference/Camera.html
If, for example, you want to place a Sprite in the top-left corner, regardless of screen size, you would use the screen or viewport space. The position of the sprite will have to be translated from this screen/viewport space to world space. You could use Camera.ScreenToWorldPoint() for this.
However, Unity uses three viewspaces: Screen, World and Viewport. You should read up on all three as your problem stems from the fact that you are trying to use world coordinates (transform.position) to set the position of UI elements (which use either the screen or world space; this is dependent on the parent Canvas settings)
I've spent my whole day trying to figure out a problem I'm having with my school project, so I'm off to my last resort: stackoverflow!
My problem:
I'm trying to rotate a character relative to a Camera you can rotate around the character.
input: xbox controller
relevant information:
The camera rotates horizontally around the character, using the right joystick
The character movement happens with the left joystick
The character already moves relative to the Camera, that's working as expected. I'm trying to rotate the character, which happens in a seperate method.
When the left joystick is pulled downwards, the character should always be facing (and moving towards) the camera.
When the left joystick is pulled upwards, the character should always be facing the opposite of (and moving away from) the camera.
I'm leaving a lot of code out, just to keep it readable for you guys. If you need something, just ask and I'll provide.
What I have so far: https://imgur.com/TERUXV6
Why it's wrong: The character rotation is perfect. However, I'm cheating here. The camera rotates according to the world coordinates. As soon as I rotate the camera, this is obvious.
The following script is attached to the Character GameObject.
public class CharacterBehaviour : MonoBehaviour
{
public GameObject HumanoidModel;
[SerializeField]private Transform _mainCameraTransform;
private void Update()
{
ApplyMovement();
RotateCharacter();
}
private void ApplyMovement()
{
//get input movement vector
Vector3 inputMovement = new Vector3(_inputMoveCharacterXAxis, 0, _inputMoveCharacterZAxis);
//make sure camera forward is player movement forward
Vector3 mainCameraForwardXz = Vector3.Scale(_mainCameraTransform.forward, new Vector3(1, 0, 1)); //multiplied by (1, 0, 1) to remove Y component
Vector3 mainCameraRightXz = Vector3.Scale(_mainCameraTransform.right, new Vector3(1, 0, 1)); //multiplied by (1, 0, 1) to remove Y component
Vector3 movementInCameraForwardDirection = mainCameraForwardXz * inputMovement.z;
Vector3 movementInCameraRightDirection = mainCameraRightXz * inputMovement.x;
Vector3 movementForward = movementInCameraForwardDirection + movementInCameraRightDirection;
_velocity = movementForward * MaximumSpeed;
}
private void RotateCharacter()
{
Vector3 inputDirection = new Vector3(_inputMoveCharacterXAxis, 0, _inputMoveCharacterZAxis);
HumanoidModel.transform.LookAt(HumanoidModel.transform.position +
HumanoidModel.transform.forward + inputDirection);
}
The following script is attached to the Main Camera GameObject
public class CameraBehaviour : MonoBehaviour
{
[SerializeField] private Transform _characterTransform;
[SerializeField] private Transform _mainCameraTransform;
private void Update ()
{
RotateCamera();
}
// Rotate camera horizontally
private void RotateCamera()
{
_mainCameraTransform.RotateAround(_characterTransform.position, Vector3.up, _inputRotateCameraHorizontal);
}
}
The source of the problem is in the RotateCharacter() function. I know I need to get some calculations in there to make the character rotation relative to the camera rotation, I just can't figure out what that calculation is, and why.
Thanks in advance!
Thrindil
so heres what you need...
camDefault, a Vector3 for the cameras initial position behind the char.
camCur, a Vector3 for the cameras current position(to track where it is in orbit around the character)
you need to set camDefault in Awake() to the its current position at that time, IE camDefault = cam.transform.position);
then in a fixed update,
camCur= cam.transform.position;
then,
if(Input//your horizontal axis here//==0){
if(camCur!=camDefault){
//translate camera to cam default
cam.tranform.translate(camDefault);
cam.lookat(player.transform.forward);
}
}
keep in mind that some of this is pseudocode, just a general direction. but the unity methods are there. if properly implemented this script will allow you to rotate around your char with right stick, than the camera will slide back behind you when you let go.
I believe, for your sanity, it would be easier to make the camera a direct child of ybot, so it rotates with it and you dont need to do it maually the camera will always stay behind the player. but thats just my opinion. as it sits now, the camera, and the model are children of player, if you want the camera to turn with the player, just make it a child of that model.
in this case, you could store the initial rotation, and current rotation as above, and us your stick to look left and right and then snap back to forward when you let the stick go.
I am using Vuforia and Unity3D to develop an application. For this, I need to get the camera position (x,y,z) in real world unit from an image target while tracking the image with a mobile phone. I was wondering if it is possible to get such position information in Vuforia . if Yes, any sample code would be highly appreciated.
Try something like this.
public class ExampleClass : MonoBehaviour {
public Transform target;
Camera camera;
void Start() {
camera = GetComponent<Camera>();
}
void Update() {
Vector3 screenPos = camera.WorldToScreenPoint(target.position);
Debug.Log("target is " + screenPos.x + " pixels from the left");
}
}
What this does is
Transforms position from world space into screen space.
Screenspace is defined in pixels. The bottom-left of the screen is (0,0); the right-top is (pixelWidth,pixelHeight). The z position is in world units from the camera.
May not be exactly what you want but its a starting point.
EDIT:
This returns world Space not local space so this should be exactly what you want
public class ExampleClass : MonoBehaviour {
public GameObject someObject;
public Vector3 thePosition;
void Start() {
// Instantiate an object to the right of the current object
thePosition = transform.TransformPoint(Vector3.right * 2);
Instantiate(someObject, thePosition, someObject.transform.rotation);
}
}
Note that the returned position is affected by scale. Use Transform.TransformDirection if you are dealing with direction vectors. You can perform the opposite conversion, from world to local space using Transform.InverseTransformPoint.