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);
}
Related
I'm making a 2D shooter game where the player's arm should be able to pivot based on your mouse position. I have a "joint" object set to the shoulder of the arm for it to rotate around. Everything I've searched pointed me to transform.RotateAround, so I used that, but the problem is the arm doesn't FACE the mouse, it just continuously rotates based on the angle of the mouse. I know of transform.rotation, but I don't believe you can rotate around a point like that. Here's what I currently have:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateArm : MonoBehaviour
{
public GameObject joint;
public Camera cam;
private Vector3 mousePosition;
private Vector3 lookAtPosition;
void Update()
{
mousePosition = Input.mousePosition;
lookAtPosition = cam.ScreenToWorldPoint(mousePosition);
var angle = Vector2.Angle(lookAtPosition, joint.transform.position);
transform.RotateAround(joint.transform.position, Vector3.forward, angle);
}
}
Calculate the angle between the arm's current forward direction and the direction towards the mouse, then use that angle to set the arm's rotation.
void Update()
{
mousePosition = Input.mousePosition;
lookAtPosition = cam.ScreenToWorldPoint(mousePosition);
Vector3 direction = lookAtPosition - joint.transform.position;
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
transform.rotation = rotation;
}
I found the solution to my problem. All I had to do was add the arm as a child object of the joint. I attached my rotate script to the joint, and made the joint rotate toward the mouse. This made the arm rotate perfectly around the joint.
I'm currently working on a 2D platforming game using Unity. When the player jumps, I prevent the camera from following them in order to allow the player to see what is beneath them. However, I have a mechanic implemented that allows the player to perform a double jump when they grab an enemy, and this double jump makes the player jump past the boundary of the screen. I was wondering how I would go about getting the camera to smoothy follow the player only when they exit certain boundaries. I have basic code written that does this in a choppy way. I will include gifs to show how my game currently behaves, and an example of how I want it to behave.
Here is the code I have written in my camera controller:
transform.position = new Vector3(player.position.x, 50, -100);
if (player.position.y > 50)
{
transform.position = player.position - transform.forward * camDist + Vector3.up * playerHeight;
}
Below is an embeded imgur gif of what my code does now:
<blockquote class="imgur-embed-pub" lang="en" data-id="a/houedOV" data-context="false" ></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
and below here is an example of what I am trying to achieve:
<blockquote class="imgur-embed-pub" lang="en" data-id="a/deg5yeq"></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>
You should moving camera from origin to destination instead of set camera to destination immediately (1 frame or 1 update called)
Try to set camera position with this code
void Update(){
// ...
Vector2 destination = Vector2.zero; // your camera destination you expected
float maxMoveDistance = 1; // maximum distance to move camera in each frame
camera.transform.position = Vector2.MoveTowards(camera.transform.position, destination, maxMoveDistance); // move camera to destination
}
ok, I figured out the answer to my own question!
It was as simple as this:
void Update()
{
if (player.position.y > 50)
{
transform.position = new Vector3(player.position.x, player.position.y, -100);
}
else
{
transform.position = new Vector3(player.position.x, 50, -100);
}
I am using unity 2018.3.5f1 so a few solutions to this problem don't work.
Starting from the Roll-A-Ball demo project, I want to extend the camera script to follow the player, but also keeping track of the direction of movement. Ex: If the ball starts moving to the side, I need the camera to rotate around the player's axis to position behind him, and then start following him.
I have tried making the camera a child to the ball i'm trying to control and i've tried making a script but it won't follow the ball correctly it keeps rotating the camera as well as the ball (i'm using this bit of code and trying to modify it as it's the only one that works)
here is the code I have at the moment:
using UnityEngine;
using System.Collections;
public class CompleteCameraController : MonoBehaviour
{
public GameObject player; //Public variable to store a reference to the player game object
private Vector3 offset; //Private variable to store the offset distance between the player and camera
// Use this for initialization
void Start()
{
//Calculate and store the offset value by getting the distance between the player's position and camera's position.
offset = transform.position - player.transform.position;
}
// LateUpdate is called after Update each frame
void LateUpdate()
{
// Set the position of the camera's transform to be the same as the player's, but offset by the calculated offset distance.
transform.position = player.transform.position + offset;
}
}
I understand why it is rotating but no reasearch is helping me find out how to lock the camera so it is looking behind the ball at all times
Have you tried adding some restraints to your camera? If it is only supposed to turn to follow the ball, you can freeze the position of 2 axes (x and z), and only let the camera rotate around the y axis of the ball.
You can play around with the restraints on the Inspector, or use GetComponent<Rigidbody>().constraints = RigidbodyConstraints.FreezeRotationX; in the camera script.
(EDIT) Sorry, this is how you would do it if the gameObject has a rigidbody, but the idea is the same if it doesn't have one.
When you're setting the position or rotation of the camera, think about which components of the position/rotation you actually want to change (x,y,z).
Use offset = new Vector3 (offset.x, offset.y, offset.z)and replace anything that shouldn't change with a constant.
Also, when you made the Camera the child of the ball, you could have set it so that every frame, the Camera updates in such a way that it won't roll with the ball. You could do this by putting code in the update method of the camera that sets the component x, y, or z equal to some constant. Whatever axis the ground plane is on is probably the correct choice.
If you want the same camera angle that the camera should follow while following the ball (similar to Temple Run), then try the below code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class CompleteCameraController : MonoBehaviour
{
public Transform Player;
public float distanceFromObject = 3f;
void Update()
{
Vector3 lookOnObject = Player.position - transform.position;
lookOnObject = Player.position - transform.position;
transform.forward = lookOnObject.normalized;
Vector3 playerLastPosition;
playerLastPosition = Player.position - lookOnObject.normalized * distanceFromObject;
playerLastPosition.y = Player.position.y + distanceFromObject / 2;
transform.position = playerLastPosition;
}
When the ball moves left or right, the camera will follow the same angle as the ball moves towards.
(For Unity 5.3.5f1)
Right now I am working on a 3D camera that is orbiting horizontally around the player. The player is a RigidBody rolling sphere. The player can freely rotate the axis horizontally but when there is no input I want the rotation to reset back to the direction of the velocity.
Right now all I need to know is how to situate the camera behind the player's direction of velocity by rotating the camera around the player from its previous rotation.
Here is a crude drawing of what I am looking for:
Currently to update the camera to orbit around the player I use this script on the camera (with comments):
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
public GameObject Player;
//I assume you would use this PlayerRB to find data regarding the movement or velocity of the player.
//public Rigidbody PlayerRB;
private float moveHorizontalCamera;
private Vector3 offset;
// Use this for initialization
void Start ()
{ //the offset of the camera to the player
offset = new Vector3(Player.transform.position.x - transform.position.x, transform.position.y - Player.transform.position.y, transform.position.z - Player.transform.position.z);
}
// Update is called once per frame
void Update ()
{
moveHorizontalCamera = Input.GetAxis("Joy X"); //"Joy X" is my right joystick moving left, none, or right resulting in -1, 0, or 1 respectively
//Copied this part from the web, so I half understand what it does.
offset = Quaternion.AngleAxis(moveHorizontalCamera, Vector3.up) * offset;
transform.position = Player.transform.position + offset;
transform.LookAt(Player.transform.position);
}
}
Any help at all would be great!
I would suggest you use Vector3.RotateTowards (https://docs.unity3d.com/ScriptReference/Vector3.RotateTowards.html)
You take the Vector that is currently pointing from the Player to the camera (transform.position - Player.transform.position) and rotate it towards -Player.GetComponent<Rigidbody>().velocity.normalized * desiredDistance (the vector pointing in the opposite direction of the players velocity with magnitude corresponding the desired distance of the camera to the player). You can then use Vector3.RotateTowards to rotate the camera (smoothly or immediately) around the Player by setting the cameras position accordingly.
Something like:
transform.position = Player.transform.position + Vector3.RotateTowards(transform.position - Player.transform.position, -Player.GetComponent<Rigidbody>().velocity.normalized * desiredDistance, step, .0f);
where step if the angle update in radians. (Note: you should avoid calling GetComponent<Rigidbody>() every Update. You are better off storing it somewhere)
I hope I understood your question correctly and this helps.
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.