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);
}
}
Related
I'm creating a 2D horizontal side-scroller and I have enemies being spawned whose rigidbody component is being used to give them a velocity like so:
using UnityEngine;
using System.Collections;
public class Mover : MonoBehaviour
{
public float speed;
public new Rigidbody2D rigidbody;
public bool random;
void Start()
{
if (random) {
rigidbody.velocity = Random.value * transform.right * speed;
}
else
{
rigidbody.velocity = transform.right * speed;
}
}
}
How can I have these enemies also move up and down constantly on the the Y-axis while they are moving with a velocity on the X-axis? Everything I have tried seems to interfere with the velocity of the objects. I am basically trying to create a simple behavioral pattern so as to make the targets harder for the player to aim at.
Any ideas?
This is just a starting point, but you would have to experiment with different ways to do it to get the behavior you want. Maybe you can try using rigidbody.AddForce too.
If you haven't already, I recommend watching the video tutorials for the 2D platformer.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Mover : MonoBehaviour {
public float speed, waveSpeed;
new Rigidbody2D rigidbody;
public bool random;
// Use this for initialization
void Start () {
rigidbody = GetComponent<Rigidbody2D>();
if (random) {
rigidbody.velocity = Random.value * transform.right * speed;
} else {
rigidbody.velocity = transform.right * speed;
}
}
float angle = 0;
// Use this for physics calculations
void FixedUpdate () {
var wave = Mathf.Sin(angle += waveSpeed); // goes from -1 to +1
var p = rigidbody.position;
p.y = wave; // or: yCenter + yHeight * wave
rigidbody.position = p;
}
}
I have found the solution by following the answer given under this link: https://gamedev.stackexchange.com/questions/96878/how-to-animate-objects-with-bobbing-up-and-down-motion-in-unity?newreg=ccb2eaf1b725413ca777a68348637990
Here is my updated code:
public class EnemyMover : MonoBehaviour {
public float speed;
public new Rigidbody2D rigidbody;
public bool random;
float originalY;
public float floatStrength = 1;
void Start()
{
this.originalY = this.transform.position.y;
if (random) {
rigidbody.velocity = Random.value * transform.right * speed;
}else
{
rigidbody.velocity = transform.right * speed;
}
}
void Update()
{
transform.position = new Vector3(transform.position.x,
originalY + ((float)System.Math.Sin(Time.time) * floatStrength),
transform.position.z);
}
}
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;
}
}
}
I am messing around in Unity and wanted to make a mechanic where a box would touch another object and then that object would follow the Player.
I have Cube set up like this:
And a Sphere with a Box Collider with same options.
My Player script is thus:
public class Player : MonoBehaviour {
public float speed = 0.0f;
public float moveX = 0.0f;
public float moveY = 0.0f;
public GameObject player;
public GameObject obj;
//public float force = 0.0f;
private bool collided = false;
// Use this for initialization
void Start () {
player = GameObject.FindWithTag ("Player");
}
// Update is called once per frame
void FixedUpdate () {
moveX = Input.GetAxis ("Horizontal");
moveY = Input.GetAxis ("Vertical");
player.GetComponent<Rigidbody> ().velocity = new Vector2 (moveX * speed, moveY * speed);
}
void OnCollisionEnter (Collision col) {
if (col.gameObject == obj) {
collided = true;
}
}
void OnCollisionExit (Collision col) {
if (col.gameObject == obj) {
collided = false;
}
}
void Update () {
if(collided) {
obj.transform.position = (player.transform.position - obj.transform.position)*speed;
}
}
}
What have I yet to do? Hoping someone can nudge me in the right direction.
I will provide you two scripts.
1st Script is FollowTarget. This will follow your target forcely.
2nd Script is SmoothFollow which will follow your target in a smooth movement.
FollowTarget.cs
using System;
using UnityEngine;
public class FollowTarget : MonoBehaviour
{
public Transform target;
public Vector3 offset = new Vector3(0f, 7.5f, 0f);
private void LateUpdate()
{
transform.position = target.position + offset;
}
}
SmoothFollow.cs
using UnityEngine;
public class SmoothFollow : MonoBehaviour
{
// The target we are following
[SerializeField]
private Transform target;
// The distance in the x-z plane to the target
[SerializeField]
private float distance = 10.0f;
// the height we want the camera to be above the target
[SerializeField]
private float height = 5.0f;
[SerializeField]
private float rotationDamping;
[SerializeField]
private float heightDamping;
// Use this for initialization
void Start() { }
// Update is called once per frame
void LateUpdate()
{
// Early out if we don't have a target
if (!target)
return;
// Calculate the current rotation angles
var wantedRotationAngle = target.eulerAngles.y;
var wantedHeight = target.position.y + height;
var currentRotationAngle = transform.eulerAngles.y;
var 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
var 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 = new Vector3(transform.position.x ,currentHeight , transform.position.z);
// Always look at the target
transform.LookAt(target);
}
}
Just choose one of them and then attach it to the gameObject. Like another box that is suppose to follow.
Remove your Update() function in your script as you don't need it anymore.
Also Remove your OnCollisionExit()
void OnCollisionEnter (Collision col) {
if (col.gameObject == obj) {
// If you choose to use SmoothFollow Uncomment this.
//col.GetComponent<SmoothFollow>().target = this.transform;
// If you choose to use FollowTarget Uncomment this
//col.GetComponent<FollowTarget>().target = this.transform;
}
}
This is Player script:
public class player
{ public projectile pro;
pro = GetComponent<projectile>();
void Update()
{
GameObject go = GameObject.Find("enemy");
Transform playerTransform = go.transform;
Vector3 posi = playerTransform.position;
pro.Target = posi; // getting error here
Instantiate(bulletprefab, position, Quaternion.identity);
}
}
This is Projectile Script:
Requirement: Get updated position of Target in Projectile but since projectileMotion() method is being called from Start() and I want the Target current's position at point when Instantiate is called in Player so as to calculate the Target_Distance appropriately in Projectile class,
But looks like the assignment from a Vector3 to _pro.Target which is a vector3 only is not allowed. Ho can I fix this?
public class projectile : MonoBehaviour
{
public Vector3 Target;
public GameObject bulletprefab;
public float firingAngle = 45.0f;
public float gravity = 9.8f;
public Transform Projectile;
private Transform myTransform;
void Awake()
{
myTransform = transform;
}
void Start()
{ myTransform.LookAt(Target);
StartCoroutine (ProjectileMotion ());
}
IEnumerator ProjectileMotion()
{
yield return new WaitForSeconds(0.25f);
Projectile.position = myTransform.position + new Vector3(0, 0.0f, 0);
// Calculating distance to target
float target_Distance = Vector3.Distance(Projectile.position, Target );
Debug.Log ("realUPDATEDOR not" + Target);
float projectile_Velocity = target_Distance / (Mathf.Sin(2 * firingAngle* Mathf.Deg2Rad) / gravity);
// X Y componenent of the velocity
float Vx = Mathf.Sqrt(projectile_Velocity) * Mathf.Cos(firingAngle * Mathf.Deg2Rad);
float Vy = Mathf.Sqrt(projectile_Velocity) * Mathf.Sin(firingAngle * Mathf.Deg2Rad);
// flight time since depends on horizontal component of velocity
float flightDuration = target_Distance / Vx;
// projectile rotated at target
Projectile.rotation = Quaternion.LookRotation(Target - Projectile.position);
float elapse_time = 0;
while (elapse_time < flightDuration) //looping and incrementing elapsed time
{
Projectile.Translate(0, (Vy - (gravity * elapse_time)) * Time.deltaTime, Vx * Time.deltaTime);
elapse_time += Time.deltaTime;
yield return null;
}
}
}
Target is present is Projectile class and is Vector3 only, how to fix this error?
the code you get a reference to the "projectile" script wont work.
change :
public projectile pro;
pro = GetComponent<projectile>();
to something like this:
public projectile pro;
void Start()
{
pro = GetComponent<projectile>();
}
Also as a suggestion you might wanna reduce the GameObject.Find uses inside the update function cause of its high cost.
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