Canvas rotating when I change it to worldSpace, Unity - unity3d

I've got a canvas that changes from Overlay to worldSpace when an event occurs, but when it changes to Overlay from worldSpace, the rotation of the canvas is changed, which I don't want it to be.
Images:
As you can see in the order that the images are, it starts with no rotation in worldSpace, then the event occurs changes it to overlay and the rotation is now 140, after the event and I'm back in worldSpace, it is still 140 degrees.
I don't know what is wrong with this. Please help if you can

This happens because, internally, the Canvas is being transformed into camera space when set to Overlay. That's how it renders. Your solution would be to cache the transform before changing the Render Mode.
Something like this, given a component:
using UnityEngine;
[RequireComponent(typeof(Canvas))]
public class CanvasRenderModeSwitcher : MonoBehaviour
{
private Canvas canvas;
private Vector3 position;
private Vector3 scale;
private Quaternion rotation;
private void OnEnable()
{
canvas = GetComponent<Canvas>();
}
public void SetRenderMode(RenderMode renderMode)
{
if (renderMode == RenderMode.WorldSpace)
{
// Set the render mode before values are reset.
canvas.renderMode = renderMode;
// Restore the values.
transform.position = position;
transform.rotation = rotation;
transform.localScale = scale;
}
else
{
// Cache the values.
position = transform.position;
rotation = transform.rotation;
scale = transform.localScale;
// Set the render mode after values are cached.
canvas.renderMode = renderMode;
}
}
}

Related

How to make limited camera movement in Unity C#

I am making a FNAF fan game using Unity, and I need limited camera movement, like shown in this video. I've been trying to figure this out but I found no tutorials nor any answers. If you could link a script for this I would be very greatful!
https://vimeo.com/710535461
Attach this code to the camera and you can limit the camera movement by setting two angles in the inspector. Remember that this code limits localEulerAngles values and always must set the camera rotation to zero, To adjust its rotation, place the camera as child of an empty object and then rotate the parent.
public class LimitedCamera : MonoBehaviour
{
public float LimitAngleX = 10f;
public float LimitAngleY = 10f;
private float AngleX;
private float AngleY;
public void Update()
{
var angles = transform.localEulerAngles;
var xAxis = Input.GetAxis("Mouse X");
var yAxis = Input.GetAxis("Mouse Y");
AngleX = Mathf.Clamp (AngleX-yAxis, -LimitAngleX, LimitAngleX);
AngleY = Mathf.Clamp (AngleY+xAxis, -LimitAngleY, LimitAngleY);
angles.x = AngleX;
angles.y = AngleY;
transform.localRotation = Quaternion.Euler (angles);
transform.localEulerAngles = angles;
}
}

How can I stop getting mouse position of UI Elements in Unity2D?

I'm making a mobile game where there is a simple circle with a handle attached to it, it can be controlled and can be rotated with mouse position, I'm using below code for handle control.
public class Controller : MonoBehaviour
{
private float m_force = 0.04f;
// amount of force for the player (circle and handle both)
public GameObject firePoint; // It is the tip of the handle which will shoot bullets
public float senstivity = 1f;
// senstivity control
public void ControlSenstivity(float index)
{
senstivity = index;
}
void Update()
{
//Get the Screen positions of the object
Vector2 positionOnScreen = Camera.main.WorldToViewportPoint(transform.position) ;
//Get the Screen position of the mouse
Vector2 mouseOnScreen = Camera.main.ScreenToViewportPoint(Input.mousePosition) ;
//Get the angle between the two points
float angle = AngleBetweenTwoPoints(positionOnScreen, mouseOnScreen) ;
// it will control the rotation of player (circle and handle both)
transform.rotation = Quaternion.Euler(new Vector3(0f, 0f, angle) * senstivity);
}
float AngleBetweenTwoPoints(Vector3 a, Vector3 b)
{
return Mathf.Atan2(a.y - b.y, a.x - b.x) * Mathf.Rad2Deg ;
}
// Below function for adding force to the player (both the circle and the handle), this function I added for mobile input whenever the button is pressed
public void AddForce()
{
transform.Translate(-firePoint.transform.localPosition.x, 0, 0 * m_force);
}
}
In this mobile game the user can rotate the player by dragging on the screen and can move the player by exerting force in the opposite direction of fire point whenever the add force button is pressed but the problem is that whenever I press the button the player takes Input.mousePosition of that button position and get rotated towards the button, that's why it will always move in one direction that is opposite of button. I wanted to know what can I do to not get Input.mousePosition of button which is in the canvas and can originally get position only of camera space. Any response will be appreciated, Thanks in advance!
You can use EventSystem.IsPointerOverGameObject. This method will check if your pointer(mouse/joystick) is on any of the UI elements.
Add if condition before getting mouse position.
// This will ignore all UI game objects
if (!EventSystem.current.IsPointerOverGameObject())
{
//Get the Screen positions of the object
Vector2 positionOnScreen = Camera.main.WorldToViewportPoint(transform.position);
}

the GameObject rotates incorrectly on the z-axis

there is a circle, it needs to be rotated by pressing the button, with a certain speed along the z axis, and when it turns 90, the rotation will stop, but for some reason the rotation is not working properly
public GameObject Circle;
private bool RotationActive;
//rotation value at which the circle stops rotation
private float RotatePost;
private float RotationSpeed;
private float CircleRotateZ;
void Start()
{
RotationActive = false;
RotationSpeed = 0.5f;
RotatePost = 90;
}
//function is bound to a button
public void RotateActive(){
RotationActive = true;
}
void FixedUpdate()
{
if (RotationActive == true)
{
CircleRotateZ = Circle.transform.rotation.z;
//if the circle along the z axis is rotated more than Rotation Post...
if (CircleRotateZ >= RotatePost )
{
RotatePost = CircleRotateZ + 90;
RotationActive = false;
}
//assignment of a new coordinate
Circle.transform.Rotate(new Vector3(0,0,RotationSpeed + CircleRotateZ));
}
}
You are trying to grab the rotation from the Quaternion which is not the angle of the object. Instead you should use:
CircleRotateZ = Circle.transform.eulerAngles.z;
Also the way you are currently rotating will make it speed up over time. The Rotate functions rotates the object by the amount, not to the amount given, so if you only want to rotate by the rotation speed you should use:
Circle.transform.Rotate(new Vector3(0, 0, RotationSpeed));
What do you mean by not working properly. You mean it doesn't move at all? If it doesn't move at all, check if you dragged the circle game object to the game object field in the Inspector. One more thing, why didn't you call the 'RotateActive' function?

Orbiting target with camera and changing height

I want to be able to use joystick (left-right) to make the camera orbit around target. I have this handled with the code below:
using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;
public class OrbitCamera : MonoBehaviour {
public Transform target;
public float turnSpeed;
public float height;
public float distance;
private Vector3 offsetX;
void Start()
{
offsetX = new Vector3 (0, height, distance);
}
void LateUpdate()
{
offsetX = Quaternion.AngleAxis (CrossPlatformInputManager.GetAxis ("hOrbit") * turnSpeed, Vector3.down) * offsetX;
transform.position = target.position + offsetX;
transform.LookAt (target.position);
}
}
I need to extend this script so that the player can move camera also up and down using the same joystick. So what I want is the camera to be able to move around player in a shape of sphere, always looking at the player. Thanks in advance.
Use a boom camera
A boom camera is wonderfully easy to setup and has a range of convenient cinematic controls:
To set it up, you simply create a new game object which we'll call the dolly. You then simply parent the camera to the dolly and tidy up the positions and rotations:
Camera
Transform: 0,0,-distance
Rotation: 0,0,0
Dolly
Transform: 0,height,0
Rotation: 0,0,0
Why a boom camera is great
Rotate the dolly on x and y and you'll get the camera moving in a sphere. (Note that dragging the rotation gizmo in scene view doesn't show the effect properly because of axis alignment; edit the x/y rotation values in the inspector only).
That -distance z value is the zoom. Change the local position of the camera to zoom in/out.
Local rotating the camera gives interesting tilt/pan effects.
Making it work in your case
You'd attach the script to the dolly gameobject, then use the joystick input to rotate it on x/y:
using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;
public class OrbitCamera : MonoBehaviour {
// Height and distance are now set in the scene (by positioning the dolly and changing that camera z value).
public float turnSpeed;
private float horizontal;
private float vertical;
void LateUpdate()
{
// Update horizontal/ vertical angles:
horizontal += CrossPlatformInputManager.GetAxis ("hOrbit") * turnSpeed;
vertical += CrossPlatformInputManager.GetAxis ("vOrbit") * turnSpeed;
// Update the rotation:
transform.rotation = Quaternion.Euler(horizontal, vertical, 0f);
}
}

Find all objects between player and camera

I am using an orthographic projection for camera to follow a player. I would like to find all gameobjects between the player and the camera so I can change the opacity so they are partially transparent while blocking the camera's view. I read about raycasting, but it seems it would give only the first object between the player and camera. What approaches are there to accomplish this?
Just use Physics.RaycastAll like this:
public class CameraScript : MonoBehaviour
{
//Attach this script to the camera//
public GameObject player;
void Update()
{
float dist = Vector3.Distance(transform.Position, player.transform.position);
RaycastHit[] hits = hits = Physics.RaycastAll(transform.position,
transform.forward, 100.0F);
foreach (RaycastHit h in hits)
{
//Change the opacity of the of each object to semitransparent.
}
}
}