I want to know how to move an object to another object smoothly, as if I'm throwing it the other object.
Say I have Object A and Object B.
I want, if I click Object B, then Object A will smoothly go to Object B.
I did this:
using UnityEngine;
using System.Collections;
public class GreenEnvelope : MonoBehaviour
{
void Start()
{
if(Input.GetMouseButton(0))
{
Update();
}
}
void Update()
{
GreenMail();
}
private void GreenMail()
{
//the speed, in units per second, we want to move towards the target
float speed = 40;
float rotateSpeed = 100f;
//move towards the center of the world (or where ever you like)
Vector3 targetPosition = new Vector3(-23.77f, -9.719998f, 0);
Vector3 currentPosition = this.transform.position;
//first, check to see if we're close enough to the target
if (Vector3.Distance(currentPosition, targetPosition) > .1f)
{
Vector3 directionOfTravel = targetPosition - currentPosition;
//now normalize the direction, since we only want the direction information
directionOfTravel.Normalize();
//scale the movement on each axis by the directionOfTravel vector components
this.transform.Translate(
(directionOfTravel.x * speed * Time.deltaTime),
(directionOfTravel.y * speed * Time.deltaTime),
(directionOfTravel.z * speed * Time.deltaTime),
Space.World);
transform.Rotate(Vector3.up, rotateSpeed * Time.deltaTime);
}
}
}
But I have to keep clicking the object in order for it to move... I have to keep clicking it everyFrame... that's not what I want. I want to click my "Object B" just once, and my "Object A" will just smoothly go to "Object B"
1- Update method is a method that run in every frame. So you need to detect mouse click in update method and then call another method, something like this:
void Start()
{
}
void Update()
{
if(Input.GetMouseButton(0))
{
// Do what ever you want
}
}
2- This movement must be in Update method to work smoothly, For this, you can use a Boolean flag. Like this:
using UnityEngine;
using System.Collections;
public class GreenEnvelope : MonoBehaviour
{
bool isMove = false;
float speed = 40;
Vector3 targetPosition;
Vector3 currentPosition;
Vector3 directionOfTravel ;
void Start()
{
}
void Update()
{
if(Input.GetMouseButton(0))
{
isMove = true;
}
if (isMove == true)
{
GreenMail();
}
}
private void GreenMail()
{
targetPosition = objB.transform.position; // Get position of object B
currentPosition = this.transform.position; // Get position of object A
directionOfTravel = targetPosition - currentPosition;
if (Vector3.Distance(currentPosition, targetPosition) > .1f)
{
this.transform.Translate(
(directionOfTravel.x * speed * Time.deltaTime),
(directionOfTravel.y * speed * Time.deltaTime),
(directionOfTravel.z * speed * Time.deltaTime),
Space.World);
}
else
{
isMove = false;
}
}
}
Related
I've been trying to figure this out for the past few hours and I figure there must be something off about my code making this extra difficult. I'm trying to make a first-person controller with the new input system and stop the camera from going 360 degrees vertically. I have the horizontal rotation applied to the player and the vertical rotation applied to a camera that is a child of said player. This is what I got sorry if it's a CF.
I've Tried Mathf.clamp and euler angles but I can't seem to get anything to work.
using UnityEngine;
using UnityEngine.InputSystem;
public class FirstPersonController : MonoBehaviour
{
public AICOde PlayerControls;
Vector2 moveDirection = Vector2.zero;
public Vector3 jumpForce;
float hlookDirection;
float vlookDirection;
public float isJumping;
public InputAction move;
public InputAction jump;
public InputAction look;
public Rigidbody rb;
public bool isOnGround;
public float moveSpeed;
public float sensitivity;
public Camera playerCamera;
public Quaternion cameraRotation;
private void Awake()
{
PlayerControls = new AICOde();
}
private void Start()
{
playerCamera = gameObject.GetComponentInChildren<Camera>();
Cursor.lockState = CursorLockMode.Locked;
}
private void OnEnable()
{
jump = PlayerControls.Player.Jump;
move = PlayerControls.Player.Move;
look = PlayerControls.Player.Look;
move.Enable();
jump.Enable();
look.Enable();
}
private void OnDisable()
{
move.Disable();
jump.Disable();
look.Disable();
}
private void Update()
{
cameraRotation = playerCamera.transform.rotation;
hlookDirection = look.ReadValue<Vector2>().x;
vlookDirection = look.ReadValue<Vector2>().y;
moveDirection = move.ReadValue<Vector2>();
isJumping = jump.ReadValue<float>();
}
private void FixedUpdate()
{
//MOVE PLAYER
rb.velocity = transform.TransformDirection (new Vector3(moveDirection.x * moveSpeed, rb.velocity.y, moveDirection.y * moveSpeed));
//ROTATE PLAYER WITH MOUSE
gameObject.transform.Rotate(Vector3.up, hlookDirection * sensitivity * Time.deltaTime );
//ROTATE CAMERA WITH MOUSE
playerCamera.transform.Rotate(Vector3.left,vlookDirection * sensitivity * Time.deltaTime);
//JUMP
if (isJumping > 0 && isOnGround == true)
{
rb.AddForce(jumpForce, ForceMode.Impulse);
}
if (isJumping > 0)
{
isOnGround = false;
}
if (isOnGround)
{
moveSpeed = 5f;
}
else
{
moveSpeed = 4f;
}
}
//MAKE SURE PLAYER IS ON GROUND BEFORE JUMPING
private void OnCollisionEnter(Collision collision)
{
if(collision.collider.CompareTag("Ground"))
{
isOnGround = true;
}
else
{
isOnGround = false;
}
}
}
You could track how much you have rotated up or down already. Define a float currentUpDownAngle = 0f; in your FirstPersonController. Then, instead of
//ROTATE CAMERA WITH MOUSE
playerCamera.transform.Rotate(Vector3.left,vlookDirection * sensitivity * Time.deltaTime);
you do
//ROTATE CAMERA WITH MOUSE
float MAX_UPDOWN_ANGLE = 60f; // define a limit (maybe somewhere else)
float change = vlookDirection * sensitivity * Time.deltaTime; // get the wanted change
// check if the change would exceed the maximum, we do it for both directions at once
// if you want another minimum angle, divide the code in two parts
if (Mathf.Abs(currentUpDownAngle + change) > MAX_UPDOWN_ANGLE) { // do we exceed?
float limit = Mathf.Sign(change) * MAX_UPDOWN_ANGLE; // get up or down limit
change = limit - currentUpDownAngle; // get the rest to limit
currentUpDownAngle = limit; // snap to the limit
}
else {
currentUpDownAngle += change; // no limit hit, free change
}
// rotates at most to the limit
playerCamera.transform.Rotate(Vector3.left, change);
I'm trying to learn how to make camera follow player in Unity. everything went fine. the scripts works, no problem with the game, it just when my Character(Player) dead(destroyed), the console keep updating this error message
MissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
UnityEngine.Transform.get_position () (at <f53c831f77784ef08ef348217b5117fa>:0)
CameraClamp.Update () (at Assets/Scripts/CameraClamp.cs:12)
and this
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
CameraFollow.FixedUpdate () (at Assets/Scripts/CameraFollow.cs:25)
and here's the scripts
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public GameObject FollowObject;
public Vector2 followOffset;
public float speed = 3f;
private Rigidbody2D rb;
private Vector2 threshold;
// Start is called before the first frame update
void Start()
{
threshold = calculateThreshold();
rb = FollowObject.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
Vector2 follow = FollowObject.transform.position;
float xDifference = Vector2.Distance(Vector2.right * transform.position.x, Vector2.right * follow.x);
float yDifference = Vector2.Distance(Vector2.up * transform.position.y, Vector2.up * follow.y);
Vector3 newPosition = transform.position;
if(Mathf.Abs(xDifference) >= threshold.x)
{
newPosition.x = follow.x;
}
if(Mathf.Abs(yDifference) >= threshold.y)
{
newPosition.y = follow.y;
}
float moveSpeed = rb.velocity.magnitude > speed ? rb.velocity.magnitude : speed;
transform.position = Vector3.MoveTowards(transform.position, newPosition, moveSpeed * Time.deltaTime);
}
private Vector3 calculateThreshold(){
Rect aspect = Camera.main.pixelRect;
Vector2 t = new Vector2 (Camera.main.orthographicSize * aspect.width / aspect.height, Camera.main.orthographicSize);
t.x -= followOffset.x;
t.y -= followOffset.y;
return t;
}
private void OnDrawGizmos() {
Gizmos.color = Color.blue;
Vector2 border = calculateThreshold();
Gizmos.DrawWireCube(transform.position, new Vector3(border.x * 2, border.y * 2, 1));
}
}
How to get rid of the error message?
There's two reasonable solutions
When you delete the player, you should delete this script too. This could be achieved by deleting the first parent of both FollowObject, CameraFollow, and Camera lamp. If they don't have a common parent, consider refactoring it so they do
Check for null before accessing the transform
void FixedUpdate()
{
if(FollowObject.transform == null)
{
Destroy(this);
}
}
Camera rotate by mouse input, How to rotate the move to the default position?
public class CameraOrbit : MonoBehaviour
{
public float turnSpeed = 1.0f;
public Transform player;
private Vector3 offset;
private void Start()
{
offset = new Vector3(0, 2.5f, -5);
}
private void LateUpdate()
{
if (Input.GetMouseButton(0))
{
offset = Quaternion.AngleAxis(Input.GetAxis("Mouse X") * turnSpeed, Vector3.up) * offset;
transform.localPosition = offset;
transform.LookAt(player.position);
}
}
}
This kind of thing moves directly into position and I want to smooth it over.
public void RevertCamera()
{
offset = new Vector3(0, 2.5f, -5);
transform.localPosition = offset;
transform.LookAt(player.position);
}
I have tried multiple variations of this, but none of them seem to work.
the easiest way is to use the camera's transform's RotateAround(...) method:
void LateUpdate
{
if(Input.GetMouseDown(0))
{
float delta = Input.GetAxis("Mouse X") * turnSpeed;
transform.RotateAround(player.position, Vector3.up, delta);
}
}
(taken from: https://docs.unity3d.com/ScriptReference/Transform.RotateAround.html)
Suggestion: I usually set up a camera rig, if I want to control camera movement focused on a certain target.
Though this might be overengineered for a simple RotateAround call.
If you want to achieve smooth transitions. I would advise you to use Slerp on the Quaternion and interpolate between your 2 rotation points.
Slerp Example:
// Interpolates rotation between the rotations "from" and "to"
// (Choose from and to not to be the same as
// the object you attach this script to)
using UnityEngine;
using System.Collections;
public class SlerpExample: MonoBehaviour {
[SerializeField]private Transform from;
[SerializeField]private Transform player;
private bool revertCamera = false;
private float timeCount = 0.0f;
private void Update() {
timeCount = timeCount + Time.deltaTime;
if (revertCamera) {
timeCount = 0.0f;
transform.rotation = Quaternion
.Slerp(from.rotation, player.rotation, timeCount);
if (transform.rotation == player.rotation) {
reverCamera = false;
}
}
}
private void RevertCamera() {
revertCamera = true;
}
}
Slerp
I'm making a first-person game in a hollow-sphere world and moving the player around by making it the child of an object in the center of the world which I then rotate. There are objects inside the sphere that I don't want the player to walk through.
Attaching colliders and rigid bodies causes the player, upon collision with said objects, to become dislocated from the parent and roll off in whatever direction is dictated by collision physics. I would seem to instead need a Trigger instead of a Collider here, but I'm unsure of what directions to feed OnTriggerEnter in order to preserve the player's movement outside of the Trigger, while not allowing it to go further into the Trigger.
So what I need is a way to make sure that the following criteria are fulfilled:
Parent center-piece and child player-object always remain in their
original relation.
Collision with another object prevents rotation of the parent object
in the direction of said object.
If it's of any help, below is the player script, which is attached to the parent object in the center of the sphere-world.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class PlayerController2 : MonoBehaviour
{
public float XSensitivity = 2f;
public float YSensitivity = 2f;
public bool clampVerticalRotation = true;
public float MinimumX = -90F;
public float MaximumX = 90F;
public float speed = 1;
public bool smooth;
public float smoothTime = 5f;
public bool lockCursor = true;
public bool playerMovement = false;
private Quaternion m_PlayerTargetRot;
private Quaternion m_CameraTargetRot;
private bool m_cursorIsLocked = true;
private Transform player;
public Transform cam;
// Use this for initialization
void Awake()
{
player = GetComponent<Transform>();
m_PlayerTargetRot = player.localRotation;
m_CameraTargetRot = cam.localRotation;
}
// Update is called once per frame
void Update()
{
float xRot = CrossPlatformInputManager.GetAxis("Mouse Y") * YSensitivity; //mouselook, lookrotation()
float yRot = CrossPlatformInputManager.GetAxis("Mouse X") * XSensitivity;
if (playerMovement)
{
Vector2 input = new Vector2
{
x = CrossPlatformInputManager.GetAxis("Horizontal") * speed,
y = CrossPlatformInputManager.GetAxis("Vertical") * speed
};
m_PlayerTargetRot *= Quaternion.Euler(-input.y, yRot, input.x);
}
else
m_PlayerTargetRot *= Quaternion.Euler(0f, yRot, 0f);
m_CameraTargetRot *= Quaternion.Euler(-xRot, 0.0f, 0.0f);
if (clampVerticalRotation)
m_CameraTargetRot = ClampRotationAroundXAxis(m_CameraTargetRot);
cam.localRotation = Quaternion.Slerp(cam.localRotation, m_CameraTargetRot, smoothTime * Time.deltaTime);
player.localRotation = Quaternion.Slerp(player.localRotation, m_PlayerTargetRot, smoothTime * Time.deltaTime);
UpdateCursorLock();
}
public void SetCursorLock(bool value)
{
lockCursor = value;
if (!lockCursor)
{//we force unlock the cursor if the user disable the cursor locking helper
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
public void UpdateCursorLock()
{
//if the user set "lockCursor" we check & properly lock the cursos
if (lockCursor)
InternalLockUpdate();
}
private void InternalLockUpdate()
{
if (Input.GetKeyUp(KeyCode.Escape))
{
m_cursorIsLocked = false;
}
else if (Input.GetMouseButtonUp(0))
{
m_cursorIsLocked = true;
}
if (m_cursorIsLocked)
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
else if (!m_cursorIsLocked)
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
Quaternion ClampRotationAroundXAxis(Quaternion q) //I haven't dissected this yet, but it works... (taken from Unity's "MouseLook.cs") like much of the above.
{
q.x /= q.w;
q.y /= q.w;
q.z /= q.w;
q.w = 1.0f;
float angleX = 2.0f * Mathf.Rad2Deg * Mathf.Atan(q.x);
angleX = Mathf.Clamp(angleX, MinimumX, MaximumX);
q.x = Mathf.Tan(0.5f * Mathf.Deg2Rad * angleX);
return q;
}
}
I have an object called Ball, and I added keyboard interactivity to it(WASD to move the ball)
I need the camera to stay behind and follow the ball, but I am getting errors.
using UnityEngine;
using System.Collections;
public class ballmain : MonoBehaviour {
public bool isMoving = false;
public string direction;
public float camX;
public float camY;
public float camZ;
// Use this for initialization
void Start () {
Debug.Log("Can this run!!!");
}
// Update is called once per frame
void Update () {
camX = rigidbody.transform.position.x -=10;
camY = rigidbody.transform.position.y -=10;
camZ = rigidbody.transform.position.z;
camera.transform.position = new Vector3(camX, camY, camZ);
//followed by code that makes ball move
}
}
I get error "Assets/ballmain.cs(18,44): error CS1612: Cannot modify a value type return value of 'UnityEngine.Transform.position'. Consider storing the value in a temporary variable"
Does anyone know the answer? If I comment out the code about the camera the ball can move around.
here you go . a full code.
Simple Following
using UnityEngine;
using System.Collections;
public class Follow: MonoBehaviour {
public Transform target;
public float smooth= 5.0f;
void Update (){
transform.position = Vector3.Lerp (
transform.position, target.position,
Time.deltaTime * smooth);
}
}
Advanced Following
using UnityEngine;
using System.Collections;
public class SmoothFollowScript: MonoBehaviour {
// The target we are following
public Transform target;
// The distance in the x-z plane to the target
public int distance = 10.0;
// the height we want the camera to be above the target
public int height = 10.0;
// How much we
public heightDamping = 2.0;
public rotationDamping = 0.6;
void LateUpdate (){
// Early out if we don't have a target
if (TargetScript.russ == true){
if (!target)
return;
// Calculate the current rotation angles
wantedRotationAngle = target.eulerAngles.y;
wantedHeight = target.position.y + height;
currentRotationAngle = transform.eulerAngles.y;
currentHeight = transform.position.y;
// Damp the rotation around the y-axis
currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);
// Damp the height
currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * Time.deltaTime);
// Convert the angle into a rotation
currentRotation = Quaternion.Euler (0, currentRotationAngle, 0);
// Set the position of the camera on the x-z plane to:
// distance meters behind the target
transform.position = target.position;
transform.position -= currentRotation * Vector3.forward * distance;
// Set the height of the camera
transform.position.y = currentHeight;
// Always look at the target
transform.LookAt (target);
}
}
}
If you just simply want to follow the target object align the position of the camera the way you want it and make the camera the child of the target object and the rest will do
Here're one script I found useful during my game development. I didn't create them so I give credit to wiki.unity3d.com for providing this amazing script.
Smooth Follow:
using UnityEngine;
using System.Collections;
public class SmoothFollow2 : MonoBehaviour {
public Transform target;
public float distance = 3.0f;
public float height = 3.0f;
public float damping = 5.0f;
public bool smoothRotation = true;
public bool followBehind = true;
public float rotationDamping = 10.0f;
void Update () {
Vector3 wantedPosition;
if(followBehind)
wantedPosition = target.TransformPoint(0, height, -distance);
else
wantedPosition = target.TransformPoint(0, height, distance);
transform.position = Vector3.Lerp (transform.position, wantedPosition, Time.deltaTime * damping);
if (smoothRotation) {
Quaternion wantedRotation = Quaternion.LookRotation(target.position - transform.position, target.up);
transform.rotation = Quaternion.Slerp (transform.rotation, wantedRotation, Time.deltaTime * rotationDamping);
}
else transform.LookAt (target, target.up);
}
}
More information about my work
Include Standard Mobile Asset to your project. It contains a SmoothFollow2D.js code in its script section. Attach this code with the gameobject and initialize public variables. This will simply do the job for you.
I found this simple and useful unity 2d camera follow script.
using UnityEngine;
using System.Collections;
public class FollowCamera : MonoBehaviour {
public float interpVelocity;
public float minDistance;
public float followDistance;
public GameObject target;
public Vector3 offset;
Vector3 targetPos;
// Use this for initialization
void Start () {
targetPos = transform.position;
}
// Update is called once per frame
void FixedUpdate () {
if (target)
{
Vector3 posNoZ = transform.position;
posNoZ.z = target.transform.position.z;
Vector3 targetDirection = (target.transform.position - posNoZ);
interpVelocity = targetDirection.magnitude * 5f;
targetPos = transform.position + (targetDirection.normalized * interpVelocity * Time.deltaTime);
transform.position = Vector3.Lerp( transform.position, targetPos + offset, 0.25f);
}
}
}
source unity2d camera follow script
The -= in these lines:
camX = rigidbody.transform.position.x -=10;
camY = rigidbody.transform.position.y -=10;
is wrong. The -= will attempt to modify the rigidbody.transform.position. You just want -.
However, as it stands, the camera won't track changes in the target's Z position, nor will it track properly if the camera is rotated. To get the correct position you need (in vectors):-
cam_pos = target_pos - dist_to_target * cam_look_at