Make Canvas to follow the camera - c#

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.

Related

how to find a position of an Object from World Space and convert to Canvas UI with render mode : Screen Space - Camera in Unity 2d?

I am working in a Game which is pretty similar to Mario. So when player touches the coin object in World Space, I need to animate by moving that coin object to Coin meter, when the render mode of Canvas is Screen Space - Overlay, I can get the sprite object position easily with below code
CoinSprite Code
GameObject coinCanvasObject = Instantiate(prefab, canvas.transform);//Instantiate coin inside Canvas view
coinCanvasObject.transform.position = Camera.main.WorldToScreenPoint(coinSpriteObject.transform.position);//getting coin position from World Space and convert to Screen Space and set to coinCanvasobject position
AnimateCoin animate = coinCanvasObject.GetComponent<AnimateCoin>();
animate.animateCoin(coinSpriteObject.transform.position);
coinSpriteObject.SetActive(false);
AnimateCoin
public class AnimateCoin : MonoBehaviour
{
private float speed = 0f;
private bool isSpawn = false;
private Vector3 screenPos;
public void animateCoin(Vector3 screenPosTemp, Camera cam, Canvas canvas)
{
screenPos = Camera.main.WorldToScreenPoint(screenPosTemp);
isSpawn = true;
}
private void Update()
{
if (isSpawn)
{
speed += 0.025f;
transform.position = Vector3.Lerp(screenPos, targetObject.transform.position, speed);
if (Vector3.Distance(transform.position, targetObject.transform.position) <= 0)
{
StartCoroutine(deActivateCoin());
}
}
}
private IEnumerator deActivateCoin()
{
isSpawn = false;
yield return new WaitForSeconds(0.2f);
gameObject.SetActive(false);
}
}
Since I need to bring particle effect into Canvas view, I am changing the Canvas render mode to Screen Space - Camera.
When I change the Canvas to this render mode I could not get the exact sprite object position to trail the coin effect.
Hope this helps:
public Camera cam; // Camera containing the canvas
public Transform target; // object in the 3D World
public RectTransform icon; // icon to place in the canvas
public Canvas canvas; // canvas with "Render mode: Screen Space - Camera"
void Update()
{
Vector3 screenPos = cam.WorldToScreenPoint(target.position);
float h = Screen.height;
float w = Screen.width;
float x = screenPos.x - (w / 2);
float y = screenPos.y - (h / 2);
float s = canvas.scaleFactor;
icon.anchoredPosition = new Vector2(x, y) / s;
}
PD: It worked perfectly for me in a 2D video game, I didn't test it in a 3D game, but I think it should work too.
I rewrote my previous solution because it might not work correctly on some devices with non-standard resolutions.
This code should always work.
uiObject.anchoredPosition = GetUIScreenPosition(myPin.position, cam3d, uiObject.anchorMin);
public static Vector2 GetUIScreenPosition(Vector3 obj3dPosition, Camera cam3d, Vector2 anchor)
{
Vector2 rootScreen = _rootCanvasRect.sizeDelta;
Vector3 screenPos = cam3d.WorldToViewportPoint(obj3dPosition);
return (rootScreen * screenPos) - (rootScreen * anchor);
}
We take the sizeDelta of our UI Canvas, because it may differ from the screen resolution of the device.
Then we cast the WorldToViewportPoint from our 3d camera to get the relative position on the screen in the format from 0 to 1 by X and Y.
With anchors in the lower left corner ((0,0)(0,0)) this is our final anchoredPosition. However with anchors for example in the center ((0.5,0.5)(0.5,0.5)) we need to adjust the positions by subtracting half the canvas size.
In this example, we will get an unpredictable result when using different min and max anchors in the final object. For example ((0,25,0.25)(0.75,0.75)). But I sincerely doubt that you really need such anchors on an object with a dynamic position depending on the 3d object.

My scroll wheel isn't working at all in unity w/ c#?

I'm trying to modify a script that lets the player zoom the camera. Before, scrolling to change the fov worked fine but i wasn't happy with the high fov stretching around the edges so I decided to switch to physical camera movement. For some reason my scroll input doesn't work anymore? This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class cameraManager : MonoBehaviour
{
public GameObject cameraAnchor;
public int cameraState;
public Transform playerPos;
public float maxZoomX;
public float maxZoomY;
public float zoomSensitivity;
// Update is called once per frame
void Update()
{
cameraAnchor.transform.position = (playerPos.position + new Vector3(6,10,0)); //camera anchor position relative to player
if (cameraState == 3){
Vector3 zoom = Camera.current.transform.position;
zoom.x += Input.GetAxis("Mouse ScrollWheel") * zoomSensitivity; // changing camera location with scroll wheel
zoom.y += Input.GetAxis("Mouse ScrollWheel") * zoomSensitivity; // changing camera location with scroll wheel
zoom.x = Mathf.Clamp(zoom.x, cameraAnchor.transform.position.x, cameraAnchor.transform.position.x + maxZoomX); // clamping zoom
zoom.y = Mathf.Clamp(zoom.y, cameraAnchor.transform.position.y, cameraAnchor.transform.position.y + maxZoomY); // clamping zoom
print(Input.GetAxis("Mouse ScrollWheel"));//testing scroll input
Camera.current.transform.position = zoom; //setting zoom
}
else{
Camera.current.transform.position = cameraAnchor.transform.position; //reset camera anchor if not in 3rd person
}
}
}
As you can see above, i've tested scrolling with print, which constantly produces a 0, regardless of whether i'm scrolling or not. I've looked at the input settings for the project and everything looks fine there.
Edit: here's a screenshot of my input page
I had this same problem. I loaded up a new project, copied the Mouse ScrollWheel entry from the input settings, and then pasted it into my old project. This resolved the issue. I didn't figure out what caused the issue in the first place.

Object rotation is not correct when rotating the camera

I have a camera which is showing the userInterface (canvas) object into the front of my camera. I am only updating my userinterface position if the camera raycast is not hitting my userInterface object collider. something like this
public class UIPlacerAtCamFront : MonoBehaviour {
public GameObject userInterface;
public float placementDistance;
Vector3 uiPlacementPosition;
RaycastHit objectHit;
void Update () {
Vector3 fwd = this.transform.TransformDirection(Vector3.forward);
//Debug.DrawRay(this.transform.position, fwd * 50, Color.green);
if (Physics.Raycast(this.transform.position, fwd, out objectHit, 50))
{
//raycast hitting the userInterface collider, so do nothing, userinterface is infornt of the camrea already
}
else
{
//raycast is not hitting userInterfae collider, so update UserInterface position accoding to the camera
uiPlacementPosition = this.transform.position + this.transform.forward * placementDistance;
userInterface.transform.position = uiPlacementPosition;
}
//Continuously update userInterface rotation according to camera
userInterface.transform.rotation = this.transform.rotation;
}
}
The above script has attached with my camera, it displaying the object correctly but as i start to rotate my camera my UI object rotation looks very strange as below image suggested
As i rotate, this problem occurs
I know that the problem is in rotation, so I tired to change my this rotation code
userInterface.transform.rotation = this.transform.rotation;
to this
userInterface.transform.localEulerAngles = new Vector3 (this.transform.localEulerAngles.x,
0,
this.transform.localEulerAngles.z);
but it bring another strange rotation for me, like given below
I want that my userinteface object face my camera correclty, even my camera watching the start or end of my userinteface object. How can i rotate my UI according to camera rotation correctly?
If I understand it correctly. You want a behavior similar to sliding google maps. Only that the camera has to rotate and the picture has to adjust its position and rotation for the behavior.
The following code should do that:
void Update() {
userInterface.transform.rotation = this.transform.rotation;
// Project camera to canvas plane
Vector3 projection = Vector3.ProjectOnPlane(this.transform.position - userInterface.transform.position, userInterface.transform.forward)
+ userInterface.transform.position;
// Get distance from camera to projected position (basically, distance from point to plane)
float curDistance = (this.transform.position - projection).magnitude;
// Correct that distance with desired distance
userInterface.transform.position += this.transform.forward * (placementDistance - curDistance);
}

Unity C# camera movement

I'm currently trying to create a Camera Control for unity (to follow around a prefab and be able to zoom and such ...
I am very new to C#
an issue I am having with this script is that
camera zooming to 0,0,0. (when I need it to stay at it's current Y-axis, I tried changing the void "Move()" but the vector requires 3 m_....'s
I also need to write a piece of code that will allow the player to zoom the camera in and out using the
scroll wheel... (In "Public Void Update()"...
I've been looking through guides and videos and can't find anything to assist me with this..
this is the section of code I require help with :
private void FixedUpdate()
{
Move();
}
private void Move()
{
m_DesiredPosition = m_target.position;
transform.position = Vector3.SmoothDamp(transform.position,
m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
}
public void Update()
{
// Get the scroll value of the mouse scroll wheel
// float scroll = Input.GetAxis("Mouse ScrollWheel");
// Is the scroll value not 0?
// Modify the orthographic size by the scroll value
Camera.main.orthographicSize = 4.8f;
}
For keeping the camera at Y = 0 simply override Y:
m_DesiredPosition = m_Target.position;
m_DesiredPosition.Y = 0;
transform.position = Vector3.SmoothDamp(transform.position,
m_DesiredPosition, ref m_MoveVelocity, m_DampTime);
For zooming the camera you'll want to add/subtract the value to orthographicsize instead of simply setting it:
// Zoom in
Camera.main.orthographicSize -= 4.8f;
// Zoom out
Camera.main.orthographicSize += 4.8f;

Rotation of a Sprite Around Its Pivot

I have a class below that I attach to a object in order to make it rotate around its pivot. I sent the pivot of the sprite via the inspector.
This works exactly how I want it too, BUT the issue I am having is that whenever I touch and drag it, and then touch and drag it again, it snaps to a new position.
What I would like for it to do is, when it is rotated and then rotated again, the sprite stays in its same rotation and not snap to a new position and I would like the angle of the sprite to be reset to 0. The next then is that I want the angle to continually rotate. So if I rotate it in the positive direction, the angle should keep increasing in the positive direction and not change..Such as 0---> 360 ----> 720 -----> etc, etc. And then when the mouse is released, the sprite stays in the same position but the angle is now set back to 0. And then when clicked again to rotate, it rotates from that exact position.
Here is my code thus far which works well for rotating, but I would like to modify it to achieve the above scenario. Any help with this?
public class Steering : MonoBehaviour {
float prevAngle,wheelAngle,wheelNewAngle = 0;
public SpriteRenderer sprite;
void Start () {
}
void Update () {
}
public float GetAngle(){
return wheelAngle;
}
void OnMouseDrag(){
Vector3 mouse_pos = Input.mousePosition;
Vector3 player_pos = Camera.main.WorldToScreenPoint(this.transform.position);
mouse_pos.x = mouse_pos.x - player_pos.x;
mouse_pos.y = mouse_pos.y - player_pos.y;
wheelNewAngle = Mathf.Atan2 (mouse_pos.y, mouse_pos.x) * Mathf.Rad2Deg;
if (Input.mousePosition.x > sprite.bounds.center.x) {
wheelAngle += wheelNewAngle - prevAngle;
} else {
wheelAngle -= wheelNewAngle - prevAngle;
}
this.transform.rotation = Quaternion.Euler (new Vector3(0, 0, wheelAngle));
Debug.Log (wheelAngle);
prevAngle = wheelNewAngle;
}
void OnMouseUp(){
prevAngle = wheelNewAngle;
wheelAngle = 0;
}
}
By angle of the sprite, do you mean the rotation? I'm not sure how the position is changing if there's nothing in your code doing that. Does it always move to the same position? I'm having a little trouble visualizing how your system is supposed to look but I hope this helps.
It looks like you might want to store the previous mouse position so you can get the relative amount to rotate each frame.
At the top:
Vector3 prevMousePos = Vector3.zero;
This method will help get the position when the player pressed:
void OnMouseDown(){
prevMousePos = Input.mousePosition;
}
Then in OnMouseDrag() get the difference between the two mouse positions to get the relative position (if you moved the mouse left, right, up, or down since pressing):
Vector3 mouseDiff = Input.mousePosition - prevMousePos;
With this it will use the relative mouse position after pressing instead of the current one, which should smooth things out.

Categories

Resources