Unity camera follows player script - c#

I'm pretty new to Unity. I tried to create a script that the camera would follow the actor (with a little difference). Is there a way to improve the code? It works just fine. But I wonder if I did it the best way. I want to do it about as I wrote, so if you have any tips. Thank you
Maybe change Update to FixedUpdate ?
public GameObject player;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("Cube"); // The player
}
// Update is called once per frame
void Update()
{
transform.position = new Vector3(player.transform.position.x, player.transform.position.y + 5, player.transform.position.z - 10);
}

Making the camera following the player is quite straight forward.
Add this script to your main camera.
Drag the reference of the player object to the script and then you are done.
You can change the values in the Vector 3 depending on how far you want the camera to be from the player.
using UnityEngine;
public class Follow_player : MonoBehaviour {
public Transform player;
// Update is called once per frame
void Update () {
transform.position = player.transform.position + new Vector3(0, 1, -5);
}
}

Follows player in the back constantly when the player rotates, no parenting needed, with smoothing.
Piece of Knowledges:
Apparently, Quaternion * Vector3 is going to rotate the point of the Vector3 around the origin of the Vector3 by the angle of the Quaternion
The Lerp method in Vector3 and Quaternion stand for linear interpolation, where the first parameter gets closer to the second parameter by the amount of third parameter each frame.
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
public Transform target;
public float smoothSpeed = 0.125f;
public Vector3 locationOffset;
public Vector3 rotationOffset;
void FixedUpdate()
{
Vector3 desiredPosition = target.position + target.rotation * locationOffset;
Vector3 smoothedPosition = Vector3.Lerp(transform.position, desiredPosition, smoothSpeed);
transform.position = smoothedPosition;
Quaternion desiredrotation = target.rotation * Quaternion.Euler(rotationOffset);
Quaternion smoothedrotation = Quaternion.Lerp(transform.rotation, desiredrotation, smoothSpeed);
transform.rotation = smoothedrotation;
}
}

This will always follow the player from the same direction, and if the player rotates it will still stay the same. This may be good for top-down or side-scrolling view, but the camera setup seems to be more fitting for 3rd person, in which case you'd want to rotate the camera when the player turns.
The easiest way to do this is actually not with code alone, simply make the camera a child of the player object, that way its position relative to the player will always stay the same!
If you do want to do it through code, you can change the code to be like this:
void Update()
{
Vector3 back = -player.transform.forward;
back.y = 0.5f; // this determines how high. Increase for higher view angle.
transform.position = player.transform.position - back * distance;
transform.forward = player.transform.position - transform.position;
}
You get the direction of the back of the player (opposite of transform's forward). Then you increase the height a little so the angle will be a bit from above like in your example. Last you set the camera's position to be the player's position and add the back direction multiplied by the distance. That will place the camera behind the player.
You also need to rotate the camera so it points at the player, and that's the last line - setting the camera's forward direction to point at the player.

Here is just another option. I always find it easier to have the variables which are populated in the inspector so you can adjust it and fine tune it as needed.
public GameObject player;
[SerializeField]
private float xAxis, yAxis, zAxis;
private void Update()
{
transform.position = new Vector3(player.transform.position.x + xAxis, player.transform.position.y + yAxis, player.transform.position.z + zAxis);
}

Related

Unity - Virtual Joystick - Camera rotation

I have a virtual movement joystick that I'm using to control the movement of a player object which works fine, the code for this is below.
The problem I have is when I rotate the camera within game mode (or device) the direction is not adjusted according to the cameras rotation, exactly like is shown in this post here that I looked through to try and understand the problem.
I realise I need to rotate my movement around the forward direction the camera is facing which I tried to do with the bottom snippet of code however this yields really strange behavior when the player object moves incredibly fast and eventually unity becomes unresponsive, so something is being incorrectly multiplied I guess.
Could anybody point out where I'm going wrong please? ta !
Edit - Modified to potential answer
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using EasyJoystick;
public class NewJoystick : MonoBehaviour
{
[SerializeField] private float speed;
[SerializeField] private Joystick1 joystick;
[SerializeField] Camera MainCam;
private Rigidbody RB;
private Transform cameraTransform;
// Start is called before the first frame update
void Start()
{
cameraTransform = MainCam.transform;
}
void Awake()
{
RB = gameObject.GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
float xMovement = joystick.Horizontal();
float zMovement = joystick.Vertical();
Vector3 inputDirection = new Vector3(xMovement, 0, zMovement);
//Get the camera horizontal rotation
Vector3 faceDirection = new Vector3(cameraTransform.forward.x, 0, cameraTransform.forward.z);
//Get the angle between world forward and camera
float cameraAngle = Vector3.SignedAngle(Vector3.forward, faceDirection, Vector3.up);
//Finally rotate the input direction horizontally by the cameraAngle
Vector3 moveDirection = Quaternion.Euler(0, cameraAngle, 0) * inputDirection;
RB.velocity = moveDirection * speed;
}
}
I tried this in the update loop -
var Direction = transform.position += new Vector3(xMovement, 0f,zMovement); //* speed * Time.deltaTime;
Vector3 newDir = MainCam.transform.TransformDirection(Direction);
transform.position += new Vector3(newDir.x, 0f,newDir.z) * speed * Time.deltaTime;
Well, here is a simple idea for how to solve it. At least this is how I did it, and it seems to work ever since.
First, you need to get the joystick input, like you did. Both axis input value should be between -1 and 1. This actually determines the direction itself, since the horizontal axis gives you the X coordinate of a vector and the vertical gives you the Y coordinate of that vector. You can visualize it easily:
Mind, that I just put up some random values there, but you get the idea.
Now, your problem is, that this angle you get from your raw input is
static in direction, meaning that it doesn't rely on the camera's face
direction. You can solve this problem by "locking it to the camera",
or in other words, rotate the input direction based on the camera
rotation. Here's a quick example:
//Get the input direction
float inputX = joystick.Horizontal();
float inputY = joystick.Vertical();
Vector3 inputDirection = new Vector3(inputX, 0, inputY);
//Get the camera horizontal rotation
Vector3 faceDirection = new Vector3(cameraTransform.forward.x, 0, cameraTransform.forward.z);
//Get the angle between world forward and camera
float cameraAngle = Vector3.SignedAngle(Vector3.forward, faceDirection, Vector3.up);
//Finally rotate the input direction horizontally by the cameraAngle
Vector3 moveDirection = Quaternion.Euler(0, cameraAngle, 0) * inputDirection;
IMPORTANT: The code above should be called in the Update cycle, since that is where you get the input information.
After this, you can work with moveDirection to move your player. (I suggest using physics for moving, instead of modifying its position)
Simple moving example:
public RigidBody rigidbody;
public Vector3 moveDirection;
public float moveSpeed = 5f;
void FixedUpdate()
{
rigidbody.velocity = moveDirection * moveSpeed;
}

How can I lock the rotation of a player in Unity?

I'm currently making a 2D game as a beginner and I made a spinning platform. But when it's rotating the player's rotation (z-axis) also changes because it's a child of the platform. I need this when I use moving platforms. Now I want to lock the z-axis of the rotation of the player. I already tried it in 3 different ways, but none of them seems to be working. Does anybody know how to do this?
These are the three ways I tried:
// 1
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0);
// 2
PlayerTrans.transform.Rotate(
PlayerTrans.transform.rotation.x,
PlayerTrans.transform.rotation.y,
0,
Space.Self);
// 3
PlayerTrans.transform.localRotation = Quaternion.Euler(new Vector3(
PlayerTrans.transform.localEulerAngles.x,
PlayerTrans.transform.localEulerAngles.y,
0f));
and this is, what my code looks like for staying on the moving platforms. I used raycasting for this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Raycasting : MonoBehaviour
{
// Start is called before the first frame update
Transform PlayerTrans;
public float RayCastRange = 3;
void Start()
{
PlayerTrans = transform.parent;
}
// Update is called once per frame
void Update()
{
RaycastHit2D PlattformCheck = Physics2D.Raycast(transform.position, -Vector2.up, RayCastRange);
if (PlattformCheck.collider != null)
{
if (PlattformCheck.collider.gameObject.tag == "Platform")
{
PlayerTrans.transform.SetParent(PlattformCheck.collider.gameObject.transform);
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
else
{
PlayerTrans.transform.SetParent(null);
}
}
}
There are 2 ways that might help you:
Just freeze the rotation from the inspector:
you can use some LookAt function (there is one for 3D but you can look and find ones for 2D) and just look at the camera.
(if you cant find it let me know and I will add it)
You should raycast directly down and then apply velocities to both objects (un-child the player from the platforms). You could do something like this for the player:
public LayerMask mask; //set ‘mask’ to the mask of the
//platform in the Unity Editor.
public Vector3 velocity;
void Update()
{
RaycastHit hit;
if (Physics.Raycast(transform.position, -Vector3.up, out hit, 0.1f, mask))
//0.1f is the distance to the platform to be able to be moved by the platform.
{
velocity = hit.collider.gameObject.GetComponent<Platform>().velocity;
}
float h = Input.GetAxis(“Horizontal”);
//this one is for CharacterController:
cc.Move(velocity);
//this one is for rigidbody:
rb.velocity = velocity;
velocity = 0;
}
It takes the velocity from the ‘Platform’ script and moves the player based on it. Now we should add the platform script. Call it ‘Platform’.
public Vector3 velocity;
public Vector3 a; //a and b are the two points you want the platform to go between.
public Vector3 b;
public float period = 2f; //the amount of seconds per cycle.
float cycles;
void Update()
{
cycles = Time.time / period;
float amplitude = Mathf.Sin(Mathf.PI * 2f * cycles);
Vector3 location = Vector3.Lerp(a, b, amplitude);
velocity = transform.position - location;
transform.position = velocity;
}
This script interpolates between the point a and b, then it finds the velocity and applies it. The player takes this velocity and it moves the player. Comment if you found an error.

Clamping an object axis in Vuforia AR camera

screenshot hereI want to clamp Y-axis on a cube. I can do it in Unity camera. But, it does not react correctly when I am using it in Vuforia camera.
My problem was that the cube follows the camera. I would like the cube to stay in its position and ignore the AR camera position. I sense it has something to do with WorldtoViewpoint but I cannot figure it out. Can you teach me how to do this please? thankyou
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClampMovementController : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
Vector3 pos = transform.localPosition;
pos.y = Mathf.Clamp(transform.position.y, 0f, 0f);
transform.localPosition = pos;
}
}
This is my solution:
Actually its very simple. The INcorrect concept was my object attached to the AR camera, hence, object position is always moving related to camera position. Now. In order to make the object stays in its place. I need to get its localPosition. First. Store the localposition in Vector3 pos. And then do modification on Vector3 pos. At last, reassign the new value to the object localposition.
public class ClampMovementController : MonoBehaviour
{
public float currentPos;
public GameObject capsule;
void Update()
{
//store the value of object localPosition
Vector3 pos = capsule.transform.localPosition;
//modification on the value
pos.y = Mathf.Clamp(pos.y, currentPos, currentPos);
//rerassign the new value to the object localPosition
capsule.transform.localPosition = pos;
}
}
First of all your cube is moving with the camera because your image target is child of your ARCamera. Therefore, when you move the camera image target moves, then your cube moves as well. Make sure your ImageTarget has no parent.
I did not understand why you have to lock any movement in Y axis. I guess you are doing something wrong with lean touch when you move object. I have not used lean touch but i have achieved this with keyboard inputs. You can convert it to lean touch by modifying following script. Just add these line to your ImageTarget's DefaultTrackableEventHandler script:
//Variables for getting capsule and checking if ImageTarget is tracked
private bool isTracked = false;
private GameObject capsule;
Then create an Update method for getting input from user like this.
void Update()
{
if(isTracked)
{
if(Input.GetKey(KeyCode.W))
{
//using forward for moving object in z axis only.
//Also using local position since you need movement to be relative to image target
//Global forward can be very different depending on your World Center Mode
capsule.transform.localPosition += Vector3.forward * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.S))
{
capsule.transform.localPosition -= Vector3.forward * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A))
{
//Using Vector3.left and right to be make sure movement is in X axis.
capsule.transform.localPosition += Vector3.left * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.D))
{
capsule.transform.localPosition += Vector3.right * Time.deltaTime;
}
}
}
As you can see there is no movement in Y axis because i used forward, left and right vectors to make sure movement in in only X and Y axis.
Last you have to make sure isTracked is updated. In order to do that you have to add isTracked = false; in OnTrackingLost method and isTracked = true; in OnTrackingFound method. Good luck!

Unity2D - Companion

When reading this, keep in mind I'm new to both programming and Unity, so I might be missing some terms or tools Unity offer. Please elaborate your answers in an ELI5 manner. Thanks in advance!
I am currently working on some game-physics for a small personal project. Currently I've created a platform, a character and what should be, a following companion.
However, since I'm still not on a level, where I can create perfect code on own hand, I found an "enemy" script and tried to modify it a bit.
It Works to an extend, but it needs some tweaks which I hope I can help aquire with you guys.
This is how it looks now (the orange square is the companion)
It follows the player, and I can tweak the speed to fit as a companion, and not a player. However, as the Picture presents, the companion runs for the center of the player. What I want to create is a companion which follows the player, but still keeps a small gap from the player.
My first thoughts was to create some kind of permanent offset, but I fail to figure out how to do this without messing up the follow function.
I hope you can help me, it will be much appreciated!
Here's the code for reference.
Code attached to Player:
using UnityEngine;
using System.Collections;
public class PlayerCompanion : MonoBehaviour
{
//In the editor, add your wayPoint gameobject to the script.
public GameObject wayPoint;
//This is how often your waypoint's position will update to the player's position
private float timer = 0.5f;
void Update ()
{
if (timer > 0) {
timer -= Time.deltaTime;
}
if (timer <= 0) {
//The position of the waypoint will update to the player's position
UpdatePosition ();
timer = 0.5f;
}
}
void UpdatePosition ()
{
//The wayPoint's position will now be the player's current position.
wayPoint.transform.position = transform.position;
}
}
Code attached to companion:
using UnityEngine;
using System.Collections;
public class FollowerOffset : MonoBehaviour {
//You may consider adding a rigid body to the zombie for accurate physics simulation
private GameObject wayPoint;
private Vector3 wayPointPos;
//This will be the zombie's speed. Adjust as necessary.
private float speed = 10.0f;
void Start ()
{
//At the start of the game, the zombies will find the gameobject called wayPoint.
wayPoint = GameObject.Find("wayPoint");
}
void Update ()
{
wayPointPos = new Vector3(wayPoint.transform.position.x, transform.position.y, wayPoint.transform.position.z);
//Here, the zombie's will follow the waypoint.
transform.position = Vector3.MoveTowards(transform.position, wayPointPos, speed * Time.deltaTime);
}
}
bump, I guess ? :)
You can use smooth follow script. I have created a sample class for you. This class has features to follow any given gameobject with some delay and offset. You will have to tweak some values according to your need.
using UnityEngine;
using System.Collections;
public class PlayerCompanion : MonoBehaviour
{
[SerializeField]
private GameObject wayPoint;
[SerializeField]
public Vector3 offset;
public Vector3 targetPos;//Edit: I forgot to declare this on firt time
public float interpVelocity;
public float cameraLerpTime = .1f;
public float followStrength = 15f;
// Use this for initialization
void Start ()
{
//At the start of the game, the zombies will find the gameobject called wayPoint.
wayPoint = GameObject.Find("wayPoint");
offset = new Vector3 (5,0,0);//input amount of offset you need
}
void FixedUpdate () {
if (wayPoint) {
Vector3 posNoZ = transform.position;
Vector3 targetDirection = (wayPoint.transform.position - posNoZ);
interpVelocity = targetDirection.magnitude * followStrength;
targetPos = transform.position + (targetDirection.normalized * interpVelocity * Time.deltaTime);
transform.position = Vector3.Lerp (transform.position, targetPos + offset, cameraLerpTime);
}
}
}
Attach this class to your player companion, play with different values.
To preserve object orientation your companion schould not be anyways child of your main character.
Your wayPoint doesn't needs to be a GameObject but a Transform instead and your code will looks like better.
If your game is a 2D platform your and your companion needs to be backwards your player it probabli applys to just one axis (X?) so you can decrement your waiPoint in a more directly way by calculating it on your UpdatePosition function like this:
wayPoint.position = transform.position * (Vector3.left * distance);
where your "distance" could be a public float to easily setup.
so on your companion script Update just do:
transform.position = Vector3.MoveTowards(transform.position, wayPoint.position, speed * Time.deltaTime);
I can't test it right now so you could have problems with Vector3 multiply operations, just comment and I'll try to fix as possible ;)

Unity: Rotate towards mouse in 3D topdown view

So I am trying to create a kind of turrent like a tank. The upper section needs to look at my mouse. I have tried
GetComponent().ScreenToWorldPoint(Argument);
many times togheter with
Input.mousePosistion();
But I couldn't figure this out really. I am programing this in C# if any one could help or provide a simple script that works in a 3D setting that would be great!
My code so far:
using UnityEngine;
using System.Collections;
public class Laser : MonoBehaviour {
public float Speed;
public AudioClip LaserSFX;
private Transform Player;
public Vector3 mousePos;
public Camera Cam;
// Use this for initialization
void Start () {
GameObject player = GameObject.FindWithTag("Player");
Player = player.transform;
if(!GetComponent<AudioSource>().isPlaying)
GetComponent<AudioSource> ().PlayOneShot (LaserSFX);
}
// Update is called once per frame
void Update () {
//Code to look at mouse or rotate
//Code to move towards it
float dist = Vector3.Distance(Player.position, transform.position);
if (dist >= 500)
{
Destroy(gameObject);
}
}
}
With kind regards,
Misterk99
You have to convert the mouse position to the view position, this means the ScreenToWorldPoint should be provided to you by the camera you are using at that time, and since you already have the camera as cam:
Vector3 pos = Input.mousePosition;
pos = Cam.ScreenToWorldPoint(pos);
with that now you have to face the position, and since you are using topdown 3D i supose the camera is facing the -y position. if so, don't forget to set the y you want:
pos.y = (your value here, depending to the position you are giving to your objects);
Vectgor3 dir = this.position - pos;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(angle, Vector3.up);
I figured out a solution while trying to find one for myself. The answer #Spike gave led me on the right track. However, I used the mouse's viewpoint position and converted the objects position to the viewport position. Here is the code in Javascript (what I am using) which should be easy enough to convert to C#.
My camera is facing the -Y direction, FYI.
#pragma strict
var cam: Camera;
function Start () {
}
function Update () {
var mousePos: Vector3 = Input.mousePosition;
var playerPos: Vector3 = cam.WorldToScreenPoint(transform.position);
var dir: Vector3 = mousePos - playerPos;
var angle: float = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.AngleAxis(-angle, Vector3.up);
}

Categories