- Home /
nullifying targetObject after a Smooth LookAt Transition
A bit of context first, I'm making a game where the main camera is fixed at a position and it will look at different game objects depending on the input of the player. In this scene I have 3 game objects and the player would input either A and D to transition the camera perspective to the object on the left or right.
I managed to create a smooth transition based on a answer from the unity forums (https://forum.unity.com/threads/transform-lookat-smooth-transition-instead-of-instant-snapping.522119/) and I was able to achieve the smooth transition I wanted. However I face a problem now: the function to do the rotation keeps getting called in the update function.
Heres the code: using System.Collections; using System.Collections.Generic; using UnityEngine;
public class CameraBehaviour : MonoBehaviour
{
// Start is called before the first frame update
Vector3 targetDirection;
private Transform targetObject = null;
private float speed;
private float distance;
void Start()
{
speed = 5f;
targetObject = null;
distance = 0;
}
// Update is called once per frame
void Update()
{
if(targetObject != null)
{
SmoothTransition();
Debug.Log("SmoothTransition() is being called");
checkIfDone();
}
}
public void TransitionTo(Transform targetObject)
{
this.targetObject = targetObject;
distance = Vector3.Distance(targetObject.position, transform.position);
}
private void SmoothTransition()
{
Vector3 targetDir = targetObject.position - transform.position;
targetDir.y = 0;
float step = speed * Time.deltaTime;
Vector3 newDirection = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
transform.rotation = Quaternion.LookRotation(newDirection);
}
private void checkIfDone()
{
RaycastHit hit;
Debug.DrawRay(transform.position, transform.forward, Color.red);
if (Physics.Raycast(transform.position, transform.forward, out hit, distance))
{
Debug.Log(transform.gameObject.name + "is hit");
if (hit.transform.Equals(targetObject))
{
targetObject = null;
Debug.Log("TargetObject has been nullified");
}
}
}
}
The function keeps getting called because of the condition in the update function. My reason for putting that condition is to make sure the function won't be called all the time and would optimize the game. In order to make the condition false, there would be a function that would use raycasting to check if the camera is already looking at the targetObject. If it is already looking at the targetObject, then targetObject would be null.
However it seems that the targetObject is not nulled out when i tested the code. My question is how do I correctly make sure that that the camera is looking at the targetObject?
Answer by icehex · May 08, 2020 at 06:40 AM
Hi @GamesWerfer instead of using a raycast to see if you're pointing at the camera, why not just see if the forward vector is close enough to the target vector? Try this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraBehavior : MonoBehaviour
{
// Start is called before the first frame update
Vector3 targetDirection;
private Transform targetObject;
private float speed;
private float distance;
void Start()
{
speed = 0.05f;
distance = 0;
}
// Update is called once per frame
void Update()
{
if (targetObject != null)
{
SmoothTransition();
Debug.Log("SmoothTransition() is being called");
}
}
public void TransitionTo(Transform targetObject)
{
this.targetObject = targetObject;
distance = Vector3.Distance(targetObject.position, transform.position);
}
private void SmoothTransition()
{
Vector3 targetDir = targetObject.position - transform.position;
targetDir.y = 0;
targetDir = targetDir.normalized;
if (Mathf.Abs(targetDir.x - transform.forward.x) < 0.01f && Mathf.Abs(targetDir.z - transform.forward.z) < 0.01f)
{
Debug.Log("No more rotation needed");
targetObject = null;
return;
}
float step = speed * Time.deltaTime;
Vector3 newDirection = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
transform.rotation = Quaternion.LookRotation(newDirection);
}
}
This worked, it nulled out the targetObject variable after completing the rotation. Although it seems that the smoothTransition() function was still called once after nulling targetObject.
I kind of don't understand the math of your solution. So essentially I just need to calculate the current forward vector of the camera and compare it with the target direction vector?
Thank you very much for the solution!
Yea the code you had basically takes your object's direction and tries to align it with the direction to your target. So the maths there just check the target direction's x and z components versus your object's transform. Once your screen's 'aim' lines up with your target, the x and z components should be zero (or near to zero given $$anonymous$$ors errors).
Answer by GamesWerfer · May 09, 2020 at 05:23 AM
I actually did more testing and found out that one line of code that I copied from the forums is the reason why my checkIfDone() function isn't working. It seems because I set my targetDir's y component to 0, the raycast would miss the exact position of the targetObject. But I would like to thank @icehex again for providing me with a solution
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraBehaviour : MonoBehaviour
{
// Start is called before the first frame update
Vector3 targetDirection;
private Transform targetObject = null;
private float speed;
private float distance;
void Start()
{
speed = 5f;
targetObject = null;
distance = 0;
}
// Update is called once per frame
void Update()
{
if(targetObject != null)
{
SmoothTransition();
Debug.Log("SmoothTransition() is being called");
checkIfDone();
}
}
public void TransitionTo(Transform targetObject)
{
this.targetObject = targetObject;
distance = Vector3.Distance(targetObject.position, transform.position);
}
private void SmoothTransition()
{
Vector3 targetDir = targetObject.position - transform.position;
//targetDir.y = 0;
targetDir = targetDir.normalized;
/*
if(Mathf.Abs(targetDir.x - transform.forward.x) < 0.01f && Mathf.Abs(targetDir.z - transform.forward.z) < 0.01f)
{
Debug.Log("No More Rotation Needed");
targetObject = null;
return;
}*/
float step = speed * Time.deltaTime;
Vector3 newDirection = Vector3.RotateTowards(transform.forward, targetDir, step, 0.0f);
transform.rotation = Quaternion.LookRotation(newDirection);
}
private void checkIfDone()
{
RaycastHit hit;
Debug.DrawRay(transform.position, transform.forward, Color.red);
if (Physics.Raycast(transform.position, transform.forward, out hit, distance))
{
Debug.Log(transform.gameObject.name + "is hit");
if (hit.transform.Equals(targetObject))
{
targetObject = null;
Debug.Log("TargetObject has been nullified");
}
}
}
}
Your answer
Follow this Question
Related Questions
Keep camera at certain distance from character when rotating 3 Answers
Player rotation = Camera Rotation 0 Answers
How do i lock the position of the camera above the player relative to the origin point? 0 Answers
How do I set a child object to not rotate if the parent WILL be rotating? 1 Answer
Workaround for Quaternion.eulerAngles 360 Degree Limit? 1 Answer