I have been working on getting a camera to follow my player when he moves with 3rd person controller.
At the moment the camera does follow him but the view remains looking forward, so if I was to move left and right the camera sits still instead of rotating to face the same direction as my character.
The code I currently have is:
using UnityEngine;
using System.Collections;
public class CameraController : MonoBehaviour
{
public GameObject player;
private Vector3 offset;
void Start ()
{
offset = transform.position - player.transform.position;
}
void LateUpdate ()
{
transform.position = player.transform.position + offset;
}
}
Anyone know a solution to make my camera rotate with the charater?
You have three option for getting this done.
Make the camera as a child of your 3rd person in game object hierarchy.
Using scripts align its forward vector to the person's forward vector.
transform.forward = player.transform.forward;
Using scripts make the camera to LookAt the 3rd person.
transform.LookAt(player);
Related
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.
I am currently programming a game where the player must tilt their phone to rotate the world so they can navigate through a maze. This is proving difficult as when I rotate the phone the sprite flies off screen.
I am assuming this is to do with the forces between the character's and the world's colliders which ends up launching the character.
However, I want the character to have gravity follow the players relative down direction so that when the character rotates it falls the direction of its feet.
Therefore, how should I rotate the direction of gravity to be relative to the sprite's direction and prevent the player from flying off when rotating?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GyroController : MonoBehaviour {
private Gyroscope Gyro ;
private float rotation;
private Vector3 startEulerAngles;
private Vector3 startGyroAttitudeToEuler;
public GameObject Player = null;
private void Awake () {
if (SystemInfo.supportsGyroscope) {
Gyro = Input.gyro;
Gyro.enabled = false;
startEulerAngles = transform.eulerAngles;
startGyroAttitudeToEuler = Input.gyro.attitude.eulerAngles;
Debug.Log("Gyro Enabled");
}
else {
Debug.Log("No Gyro Detected");
}
}
private void Update()
{
Vector3 deltaEulerAngles = Input.gyro.attitude.eulerAngles - startGyroAttitudeToEuler;
deltaEulerAngles.x = 0.0f;
deltaEulerAngles.y = 0.0f;
Player.transform.eulerAngles = startEulerAngles - deltaEulerAngles;
}
}
So far I have only tried one method of changing the direction of gravity which involves moving the center of gravity which only made the character fall through other colliders. Hence, my gravity code is not included in this snippet.
I am not asking for the code to be made for me, just a direction for me to look in as i've hit a dead end using rigidbody2d
Thankyou.
I am in the middle of working on a game, and I just started. I added in the map as a png and have been adding in colliders around the areas that I want to be impassable (it is a 2D platformer). I have an enemy already designed and added a 2DRigidBody component to it as it moves around, and started to use 2DBoxColliders as the colliders for the level, and my script that I have written:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sexapus : MonoBehaviour {
public static int Velocity = 42;
public Rigidbody2D rb;
public Vector2 dir;
public Animator anim;
void Start () {
rb = GetComponent<Rigidbody2D>();
dir = new Vector2(1, 0);
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
rb.velocity = dir * Velocity;
anim.SetFloat ("Direction", dir.x);
}
void OnCollisionEnter2D (Collision2D col) {
dir = dir * -1;
}
//CHECK TASKS
}
Meant that the enemy would hit the side of a wall and then rotate and start going the other way. I realised with the size of my map that using multiple 2DBoxColliders (and when I say multiple I mean I would probably have to use over a hundred) was a very bad way of doing it. I have now started to use a 2DpolygonCollider for the map as well, but now the enemy doesn't collide with the sides of the wall and turn around, it just stays facing the same direction but doesn't move. Anyone know why?
You are using the same collider for the floor and the walls... So when you collide with the wall, and are already touching the floor, the OnCollisionEnter will not happen.
So, you do get the collision, hence the object cant move past the wall, BUT it's not a new collision!
Solution: Use a collider to the floor, and a different one to the walls, Edge colliders are good for this.
camera transform
I am trying to move my camera based on the players' movements on Y axis in Unity.
However, it does not work...
What did I do wrong? I have attached image of my script (C#) here.
and, Yes, I did attach this script with Main Camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour {
GameObject player;
// Use this for initialization
void Start () {
this.player = GameObject.Find("cat");
}
// Update is called once per frame
void Update () {
Vector3 playerPos = this.player.transform.position;
transform.position = new Vector3(
transform.position.x, playerPos.y, transform.position.z);
}
}
Make the player GameObject public and just drag and drop your player in the inspector in unity see if that works? Are you getting any exceptions? Also add Debug.Log (player.transform.position.ToString ()) to see if it is showing the right values. Are you sure you player object name is cat and not Cat, it is case sensitive. Check on those things and let me know if you figured it out!
In short, I have a very simple multiplayer game. It's the Roll A Ball game (Unity3D tutorial). So right now I have the players etc spawning perfectly and everyone is able to control their own balls perfectly fine.
But here's the problem: I've got a default Main Camera. Since it's only the local player itself that needs to see it, I figured there's no point in trying to spawn a seperate camera for each player on the server.
However, to make the camera follow the player, I need to attach it the player gameobject. Obviously I can't attach it to the player prefab as it's a clone the camera needs to follow. But since the player is being spawned by the Network Manager component, I have no idea on how to refer to this clone.
What I've tried myself:
public class CameraController : NetworkManager
{
public GameObject playerPrefab;
public Transform target;
private Vector3 offset;
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
GameObject player = (GameObject)Instantiate(playerPrefab, new Vector3(0, 0.5f, 0), Quaternion.identity);
target = player.transform;
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
void Start()
{
offset = transform.position - target.position;
}
void LateUpdate()
{
transform.position = transform.position + offset;
}
}
But this resulted in:
Which I find extremely odd since as you can clearly see, there's no NetworkIdentity component on the NetworkManager object. I've been trying A LOT of things for the past 4 hours now and I just can't do it. So now I'm hoping you guys can help me out.
Edit: This is how the Network Manager normally spawns a player. As you can see, there's no code for it:
I had the same issue and figured out the followig solution. Seems like you already got a solution, but maybe it is interesting to share some possible ways for other people in the same situation.
This is a way to do it without a camera attached to the prefabs.
I'm using a NetworkManager to instantiate Player-prefabs. (Same as you)
I solved the problem of finding references to the clone objects by letting the clones tell the camera, who they are (or which transform belongs to them).
The Player has the following script:
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class PlayerController : NetworkBehaviour {
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
Camera.main.GetComponent<CameraFollow>().target=transform; //Fix camera on "me"
}
void Update ()
{
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis ("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate (0, x, 0);
transform.Translate (0,0,z);
}
}
On my default main Camera (there is no camera attached to the player prefab, just the default camera) I put the following script on. It takes a target which I initialised with the prefab using the inspector.
using UnityEngine;
using System.Collections;
public class CameraFollow : MonoBehaviour {
public Transform target; //what to follow
public float smoothing = 5f; //camera speed
Vector3 offset;
void Start()
{
offset = transform.position - target.position;
}
void FixedUpdate()
{
Vector3 targetCamPos = target.position + offset;
transform.position = Vector3.Lerp (transform.position, targetCamPos,smoothing * Time.deltaTime);
}
}
After starting the game, each clone tells the camera who he is, so the target changes to the individual clients clone with this line from the Player's Script:
Camera.main.GetComponent<CameraFollow>().target=transform; //Fix camera on "me"
This way you don't need to create one camera per instance of player-prefabs (I'm not sure if this makes big differences in performance) and you don't have to deactivate all cameras which don't belong to your client.
If you host the game in the editor you can see that there is just 1 camera instead of one camera per connected client (like when you attach it to the prefab).
I think this is a good use of this method, you can use it to put things in it, which should be applied to the Local Player only.
public override void OnStartLocalPlayer()
{
}
I tried by starting the game in the editor and in a build and it seems to work well.
I would add a camera to the prefab and then write a player script like this:
using UnityEngine.Networking;
public class Player : NetworkBehaviour
{
public Camera camera;
void Awake()
{
if(!isLocalPlayer)
{
camera.enabled = false;
}
}
}
I've not really worked with networking but what if you do this after you spawn the local player
Camera.main.transfor.SetParent(the transform of the local player here);
As I understand the problem each separate instance of the game has a main camera.
Thanks to Rafiwui's point into the right direction, I've finally managed to get it working. All I had to do was adept his code a bit. The end result was:
public Camera camera;
void Awake()
{
camera.enabled = false;
}
public override void OnStartLocalPlayer()
{
camera.enabled = true;
}
Thanks A LOT to you all for helping me out! This has been quite a day for me.