Change perspective script to orthographic unity 2d - c#

I am trying to change this script that I found online https://pressstart.vip/tutorials/2018/09/25/58/spawning-obstacles.html to work with a orthographic camera because that is what my game uses. At the moment it only works with perspective cameras and I don't really know how this works cause I have not really touched the camera matrix. Here is the code for the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class deployAsteroids : MonoBehaviour {
public GameObject asteroidPrefab;
public float respawnTime = 1.0f;
private Vector2 screenBounds;
// Use this for initialization
void Start () {
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
StartCoroutine(asteroidWave());
}
private void spawnEnemy(){
GameObject a = Instantiate(asteroidPrefab) as GameObject;
a.transform.position = new Vector2(screenBounds.x * -2, Random.Range(-screenBounds.y, screenBounds.y));
}
IEnumerator asteroidWave(){
while(true){
yield return new WaitForSeconds(respawnTime);
spawnEnemy();
}
}
}
My goal is to change the script to make it work correctly with a orthographic camera. (The indentation is messed up and that is not the problem).

For some reason the code is using Camera.main.transform.position.z for the camera depth component. This value will be negative in a typical camera setup in a 2d game.
So it's finding the left side of the screen by following the right edge of the frustum behind the camera. Very odd. You can't follow the right side of the frustum to find where the left side of the screen if it's orthographic so it is no surprise that it doesn't work.
Instead, just use the left side of the frustum and make the depth positive by negating that component:
screenBounds = Camera.main.ViewportToWorldPoint(
new Vector3(0f, 0f, -Camera.main.transform.position.z));

Related

How to give the camera's edge collision in Unity

I am making a 2D game in Unity, and in this game, the camera will not need to move. As such, I would like to constrain the player's movement within the camera border, preferably with collision instead of just based on the player's transform. Honestly, I have no idea where to start doing something like this, but I assume it would involve some scripting. I am pretty comfortable with scripting at this point, but if your answer includes scripting, I would appreciate it if it would include thorough explanations of everything that is going on. By the by, I am using C#.
If the camera is in orthographic mode, you can use EdgeCollider2D to do this, finding the world positions of the corners of the screen using ScreenToWorldPoint to then determine the shape of the EdgeCollider2D.
The Unity Community UnityLibrary Github has an example (copied below):
// adds EdgeCollider2D colliders to screen edges
// only works with orthographic camera
using UnityEngine;
using System.Collections;
namespace UnityLibrary
{
public class ScreenEdgeColliders : MonoBehaviour
{
void Awake ()
{
AddCollider();
}
void AddCollider ()
{
if (Camera.main==null) {Debug.LogError("Camera.main not found, failed to create edge colliders"); return;}
var cam = Camera.main;
if (!cam.orthographic) {Debug.LogError("Camera.main is not Orthographic, failed to create edge colliders"); return;}
var bottomLeft = (Vector2)cam.ScreenToWorldPoint(new Vector3(0, 0, cam.nearClipPlane));
var topLeft = (Vector2)cam.ScreenToWorldPoint(new Vector3(0, cam.pixelHeight, cam.nearClipPlane));
var topRight = (Vector2)cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth, cam.pixelHeight, cam.nearClipPlane));
var bottomRight = (Vector2)cam.ScreenToWorldPoint(new Vector3(cam.pixelWidth, 0, cam.nearClipPlane));
// add or use existing EdgeCollider2D
var edge = GetComponent<EdgeCollider2D>()==null?gameObject.AddComponent<EdgeCollider2D>():GetComponent<EdgeCollider2D>();
var edgePoints = new [] {bottomLeft,topLeft,topRight,bottomRight, bottomLeft};
edge.points = edgePoints;
}
}
}

How can a make the camera follow a rolling ball from behind?

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.

How do i fix this? (Simple "Rotation" Script)

So i have this script that rotates a point around my "character", it worked until i added a minimap using the canvas ui element, now only works on the bottom left side of the screen.
Here you can see more clearly what im talking about.
this is my script:
using UnityEngine;
public class PlayerAim : MonoBehaviour
{
private void LateUpdate()
{
AimMouse();
}
void AimMouse()
{
Vector3 mousePos = Input.mousePosition;
mousePos = Camera.main.ScreenToWorldPoint(mousePos);
Vector2 direction = new Vector2(
mousePos.x - transform.position.x,
mousePos.y - transform.position.y
);
transform.up = direction;
}
}
I'd be willing to bet your minimap uses a second camera, correct? Do both cameras have the MainCamera tag? If so, then your code that calls Camera.main would have undefined behaviour as to which camera it actually uses. Most likely, it's using the minimap camera for the ScreenToWorldPoint call, which is giving you the unexpected behaviour.
What you need to do is either (a) remove the MainCamera tag from the minimap camera object, or (b) add a Camera reference to your script, and reference it directly in the code.

How to attach the camera to a player object instantiated by HLAPI Network Manager?

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.

Camera which sits behind player

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);

Categories

Resources