Am developing a follow target camera, it's working fine but when the vehicle(Target) is on slope, the camera is not rotating to show the full vehicle.
void LateUpdate()
{
if (car1.controlled && Camera.main != null)
{
float speedFactor = Mathf.Clamp01(target.root.GetComponent<Rigidbody>().velocity.magnitude / 20.0f);
if (speedFactor < 0.01f)
speedFactor = 0.01f;
Camera.main.fieldOfView = Mathf.Lerp(40, 65, speedFactor);
float currentDistance = Mathf.Lerp(13.5f, 8.5f, speedFactor);
currentVelocity = currentVelocity.normalized;
Vector3 newTargetPosition = target.position + Vector3.up * height;
Vector3 newPosition = newTargetPosition - ((currentVelocity * currentDistance));
newPosition.y = newTargetPosition.y;
Vector3 targetDirection = newPosition - newTargetPosition;
if (Physics.Raycast(newTargetPosition, targetDirection, out hit, currentDistance, raycastLayers))
newPosition = hit.point;
Camera.main.transform.position = newPosition;
Camera.main.transform.LookAt(newTargetPosition);
}
LookAt is going to set the camera rotation to be looking straight at the newTargetPosition. It doesn't actually moves the camera up, it simply rotates it to look at the vehicule. You should modify your code so the camera moves up when the vehicule goes down a slope and then make it look at the vehicule.
Before 5.5 particle system variables could be accessed via ParticleSystem and were read/write. Now they're accessed via ParticleSystem.MainModule and thus a lot of code has become obsolete. The API Updater has not been able to fix most of the issues. I've read through the new documentation but I can't figure out how the new variable types are supposed to be used. For example in JetParticleEffect.cs this line causes a warning:
// set the original properties from the particle system
m_OriginalLifetime = m_System.startLifetime;
The warning states: 'ParticleSystem.startLifetime' is obsolete: 'startLifetime property is deprecated. Use main.startLifetime or main.startLifetimeMultiplier instead.'
I've tried the following:
m_OriginalLifetime = m_System.main.startLifetime;
// error: Cannot implicitly convert type 'UnityEngine.ParticleSystem.MinMaxCurve' to 'float'
I believe the answer has something to do with the minMaxCurve constant variables as this compiles:
m_OriginalLifetime = m_System.main.startLifetime.constant;
But there is almost no explaination in the docs. Can anyone shed some light on this?
Also, where do the new multipliers fit in? I assume where previously you could do this:
particle.startSize *= myMultiplier
... you should now do this?
particle.main.startSizeMultiplier = myMultiplier
particle.startLifetime:
First of all, what Unity did in Unity 5.5 was to add new futures to the ParticleSystem. They also exposed some ParticleSystem API that was hidden before.
ParticleSystem.MainModule.startLifetime is now a type of MinMaxCurve instead of float like ParticleSystem.startLifetime.
By doing this, you are now given more options such as modifying the startLifetime as a curve.
Reading or writing to ParticleSystem.MainModule.startLifetime depends on the value of ParticleSystem.MainModule.startLifetime.mode which is set through the Editor or via code.
The default value of ParticleSystem.MainModule.startLifetime.mode is ParticleSystemCurveMode.Constant
So your m_OriginalLifetime = m_System.main.startLifetime.constant; is fine.
If startLifetime is dynamically or randomly changed to another mode during run-time, then you will have to do something like this:
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
ParticleSystem.MinMaxCurve minMaxCurve = main.startLifetime;
if (minMaxCurve.mode == ParticleSystemCurveMode.Constant)
{
m_OriginalLifetime = m_System.main.startLifetime.constant;
}
else if (minMaxCurve.mode == ParticleSystemCurveMode.Curve)
{
AnimationCurve animCurveLifetime = m_System.main.startLifetime.curve;
}
...
particle.startSize:
The-same thing apply to particle.startSize.
The particle.startSize property is now m_System.main.startSize;
Although you can't do m_System.main.startSize.constant *= myMultiplier; because your old code was particle.startSize *= myMultiplier.
You need to get m_System.main.startSize, modify it then assign the modified m_System.main.startSize back to m_System.main.startSize.
particle.startSize *= myMultiplier should be:
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
ParticleSystem.MinMaxCurve minMaxCurve = main.startSize; //Get Size
minMaxCurve.constant *= myMultiplier; //Modify Size
main.startSize = minMaxCurve; //Assign the modified startSize back
Then, what are particle.main.startSizeMultiplier and particle.main.startSize used for?
This two variables can also be used to change startLifetime and startSize. It's main advantage is that it is very efficient. It does not not require that you make a copy of MinMaxCurve like we did above, in order to change startSize or startSizeMultiplier.
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
main.startSizeMultiplier = 5;
and
ParticleSystem m_System = GetComponent<ParticleSystem>();
ParticleSystem.MainModule main = m_System.main;
main.startLifetimeMultiplier = 8;
Use them if your ParticleSystem.MainModule.startLifetime.mode is constant. This will to change the overall lifetime multiplier or the the overall size multiplier efficiently.
Changing Color and Color Modes
Color:
There is an implicit operator that lets you use:
ParticleSystem.MainModule main = trailPartical.main;
main.startColor = Color.red;
but startColor is not actually type of Color. The startColor variable is now a type of ParticleSystem.MinMaxGradient.
This is how you should be changing the particle startColor:
//Create Color
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.Color;
color.color = Color.red;
//Assign the color to your particle
ParticleSystem.MainModule main = trailPartical.main;
main.startColor = color;
Gradient:
public ParticleSystem particleSystem;
void Start()
{
//Create Gradient key
GradientColorKey[] gradientColorKey;
gradientColorKey = new GradientColorKey[3];
gradientColorKey[0].color = Color.red;
gradientColorKey[0].time = 0f;
gradientColorKey[1].color = Color.blue;
gradientColorKey[1].time = 0.5f;
gradientColorKey[2].color = Color.green;
gradientColorKey[2].time = 1f;
//Create Gradient alpha
GradientAlphaKey[] gradientAlphaKey;
gradientAlphaKey = new GradientAlphaKey[3];
gradientAlphaKey[0].alpha = 1.0f;
gradientAlphaKey[0].time = 0.0f;
gradientAlphaKey[1].alpha = 0.5f;
gradientAlphaKey[1].time = 0.5f;
gradientAlphaKey[2].alpha = 1f;
gradientAlphaKey[2].time = 1f;
//Create Gradient
Gradient gradient = new Gradient();
gradient.SetKeys(gradientColorKey, gradientAlphaKey);
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.Gradient;
color.gradient = gradient;
//Assign the color to particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
}
Random Between Two Colors:
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.TwoColors;
color.colorMin = Color.red;
color.colorMax = Color.green;
//Assign the color to the particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
Random Between Two Gradients:
public ParticleSystem particleSystem;
void Start()
{
//Create Gradient key Min
GradientColorKey[] gradientColorKeyMin;
gradientColorKeyMin = new GradientColorKey[3];
gradientColorKeyMin[0].color = Color.red;
gradientColorKeyMin[0].time = 0f;
gradientColorKeyMin[1].color = Color.blue;
gradientColorKeyMin[1].time = 0.5f;
gradientColorKeyMin[2].color = Color.green;
gradientColorKeyMin[2].time = 1f;
//Create Gradient alpha Min
GradientAlphaKey[] gradientAlphaKeyMin;
gradientAlphaKeyMin = new GradientAlphaKey[3];
gradientAlphaKeyMin[0].alpha = 1.0f;
gradientAlphaKeyMin[0].time = 0.0f;
gradientAlphaKeyMin[1].alpha = 0.5f;
gradientAlphaKeyMin[1].time = 0.5f;
gradientAlphaKeyMin[2].alpha = 1f;
gradientAlphaKeyMin[2].time = 1f;
//Create Gradient key Max
GradientColorKey[] gradientColorKeyMax;
gradientColorKeyMax = new GradientColorKey[3];
gradientColorKeyMax[0].color = Color.red;
gradientColorKeyMax[0].time = 0f;
gradientColorKeyMax[1].color = Color.blue;
gradientColorKeyMax[1].time = 0.5f;
gradientColorKeyMax[2].color = Color.green;
gradientColorKeyMax[2].time = 1f;
//Create Gradient alpha Max
GradientAlphaKey[] gradientAlphaKeyMax;
gradientAlphaKeyMax = new GradientAlphaKey[3];
gradientAlphaKeyMax[0].alpha = 1.0f;
gradientAlphaKeyMax[0].time = 0.0f;
gradientAlphaKeyMax[1].alpha = 0.5f;
gradientAlphaKeyMax[1].time = 0.5f;
gradientAlphaKeyMax[2].alpha = 1f;
gradientAlphaKeyMax[2].time = 1f;
//Create Gradient Min
Gradient gradientMin = new Gradient();
gradientMin.SetKeys(gradientColorKeyMin, gradientAlphaKeyMin);
//Create Gradient Max
Gradient gradientMax = new Gradient();
gradientMax.SetKeys(gradientColorKeyMax, gradientAlphaKeyMax);
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.TwoGradients;
color.gradientMin = gradientMin;
color.gradientMax = gradientMax;
//Assign the color to the particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
}
Random Color:
public ParticleSystem particleSystem;
void Start()
{
//Create Gradient key Min
GradientColorKey[] gradientColorKeyMin;
gradientColorKeyMin = new GradientColorKey[3];
gradientColorKeyMin[0].color = Color.red;
gradientColorKeyMin[0].time = 0f;
gradientColorKeyMin[1].color = Color.blue;
gradientColorKeyMin[1].time = 0.5f;
gradientColorKeyMin[2].color = Color.green;
gradientColorKeyMin[2].time = 1f;
//Create Gradient alpha Min
GradientAlphaKey[] gradientAlphaKeyMin;
gradientAlphaKeyMin = new GradientAlphaKey[3];
gradientAlphaKeyMin[0].alpha = 1.0f;
gradientAlphaKeyMin[0].time = 0.0f;
gradientAlphaKeyMin[1].alpha = 0.5f;
gradientAlphaKeyMin[1].time = 0.5f;
gradientAlphaKeyMin[2].alpha = 1f;
gradientAlphaKeyMin[2].time = 1f;
//Create Gradient key Max
GradientColorKey[] gradientColorKeyMax;
gradientColorKeyMax = new GradientColorKey[3];
gradientColorKeyMax[0].color = Color.red;
gradientColorKeyMax[0].time = 0f;
gradientColorKeyMax[1].color = Color.blue;
gradientColorKeyMax[1].time = 0.5f;
gradientColorKeyMax[2].color = Color.green;
gradientColorKeyMax[2].time = 1f;
//Create Gradient alpha Max
GradientAlphaKey[] gradientAlphaKeyMax;
gradientAlphaKeyMax = new GradientAlphaKey[3];
gradientAlphaKeyMax[0].alpha = 1.0f;
gradientAlphaKeyMax[0].time = 0.0f;
gradientAlphaKeyMax[1].alpha = 0.5f;
gradientAlphaKeyMax[1].time = 0.5f;
gradientAlphaKeyMax[2].alpha = 1f;
gradientAlphaKeyMax[2].time = 1f;
//Create Gradient Min
Gradient gradientMin = new Gradient();
gradientMin.SetKeys(gradientColorKeyMin, gradientAlphaKeyMin);
//Create Gradient Max
Gradient gradientMax = new Gradient();
gradientMax.SetKeys(gradientColorKeyMax, gradientAlphaKeyMax);
//Create Color from Gradient
ParticleSystem.MinMaxGradient color = new ParticleSystem.MinMaxGradient();
color.mode = ParticleSystemGradientMode.RandomColor;
color.gradientMin = gradientMin;
color.gradientMax = gradientMax;
//Assign the color to the particle
ParticleSystem.MainModule main = particleSystem.main;
main.startColor = color;
}
I am creating a game which has up to 4 orthographic cameras (for up to 4 players), which take up various amounts of the screen, depending on the amount of players.
I have a script which controls all the cameras, setting their position relative to the players they are watching.
What I want to achieve is a simple overhead-runner style of movement, whereby the camera will follow the player, but not go outside the bounds of the map.
I have managed to get the boundaries working in the top-left camera, when the cameras are 'square' (as in the 4-player layout). However, the other cameras don't track properly at all, and in the rectangular 2-player mode, the top camera still goes too far left-and right. I'm pretty sure I know exactly which line of code is causing the problem... but I don't know what I need to do to fix it...
SpriteRenderer spriteBounds = GameObject.Find("Map").GetComponentInChildren<SpriteRenderer>();
float leftBound =0;
float rightBound =0;
float bottomBound =0;
float topBound = 0;
if((trackPlayer1 == null))
{
camPlayer1.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer1.orthographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer1.transform.position = new Vector3(Mathf.Clamp(trackPlayer1.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer1.transform.position.y, bottomBound, topBound), camPlayer1.transform.position.z);
}
if((trackPlayer2 == null))
{
camPlayer2.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer2.orthographicSize ;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer2.transform.position = new Vector3(Mathf.Clamp(trackPlayer2.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer2.transform.position.y, topBound, bottomBound), camPlayer2.transform.position.z);
}
if((trackPlayer3 == null))
{
camPlayer3.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer3.orthographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer3.transform.position = new Vector3(Mathf.Clamp(trackPlayer3.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer3.transform.position.y, topBound, bottomBound), camPlayer3.transform.position.z);
}
if((trackPlayer4 == null))
{
camPlayer4.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer4.orthographicSize;
float horzExtent = vertExtent * Screen.width / Screen.height; //I guess the problem is here... but how do I fix this??
leftBound = (float)(horzExtent - spriteBounds.sprite.bounds.size.x / 2.0f);
rightBound = (float)(spriteBounds.sprite.bounds.size.x / 2.0f - horzExtent);
bottomBound = (float)(vertExtent - spriteBounds.sprite.bounds.size.y / 2.0f);
topBound = (float)(spriteBounds.sprite.bounds.size.y / 2.0f - vertExtent);
camPlayer4.transform.position = new Vector3(Mathf.Clamp(trackPlayer4.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer4.transform.position.y, topBound, bottomBound), camPlayer4.transform.position.z);
}
So I'm pretty sure that I need to be checking against the cameras size and relative position on the screen, but I am lost as to exactly what I need to be doing.
(edit)
Script explanation:
The script is a global script attached to the main camera object, which is never seen by the player
The four player cams (camPlayer1 - camPlayer4) are public variables and assigned to the script in the designer
trackPlayer1-trackPlayer4 are public gameobjects, which are assigned in the designer - they are assigned to the player objects
Player tracking works on all cams... for example if I change camPlayer2.transform.position = new Vector3(Mathf.Clamp(trackPlayer2.transform.position.x, leftBound, rightBound), Mathf.Clamp(trackPlayer2.transform.position.y, topBound, bottomBound), camPlayer2.transform.position.z); to camPlayer2.transform.position = trackPlayer2.transform.position;, the code has the expected effect, the camera follows the player. It is only the clamping to the bounds of the map that I am having issues with
The camera's orthographic sizes are set to 2
code which positions the cameras on screen at startup:
switch (playerCount)
{
case 1:
camPlayer1.enabled = true;
camPlayer2.enabled = false;
camPlayer3.enabled = false;
camPlayer4.enabled = false;
camPlayer1.rect = new Rect(0, 0, 1, 1);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0, 0, 0, 0);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0, 0, 0, 0);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0, 0, 0, 0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
break;
case 2:
camPlayer1.enabled = true;
camPlayer2.enabled = true;
camPlayer3.enabled = false;
camPlayer4.enabled = false;
camPlayer1.rect = new Rect(0, 0.5f, 0.7f, 0.5f);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0.3f, 0, 0.7f, 0.5f);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0, 0, 0, 0);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0, 0, 0, 0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
Destroy(play3);
Destroy(play4);
break;
case 3:
camPlayer1.enabled = true;
camPlayer2.enabled = true;
camPlayer3.enabled = true;
camPlayer4.enabled = false;
camPlayer1.rect = new Rect(0, 0.5f, 0.5f, 0.5f);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0.5f, 0.5f, 0.5f, 0.5f);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0.25f, 0, 0.5f, 0.5f);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0, 0, 0, 0);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
Destroy(play4);
break;
case 4:
camPlayer1.enabled = true;
camPlayer2.enabled = true;
camPlayer3.enabled = true;
camPlayer4.enabled = true;
camPlayer1.rect = new Rect(0, 0.5f, 0.5f, 0.5f);
camPlayer1.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer2.rect = new Rect(0.5f, 0.5f, 0.5f, 0.5f);
camPlayer2.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer3.rect = new Rect(0, 0, 0.5f, 0.5f);
camPlayer3.orthographicSize = CamManager.CAMERA_SIZE;
camPlayer4.rect = new Rect(0.5f, 0, 0.5f, 0.5f);
camPlayer4.orthographicSize = CamManager.CAMERA_SIZE;
break;
}
}
edit, so I can get the first camera to tract regardless of shape (so in 2-player mode, with a rectangular camera, the player-1 cam will respect the boundaries of the map) with the code below. I'm guessing then that I need to apply some offsets to the leftBound, rightBound, topBound and bottomBound dependent on the rects of the other cams. How to establish and calculate these I have no idea
if((trackPlayer1 == null))
{
camPlayer1.transform.position = this.transform.position;
}
else
{
float vertExtent = camPlayer1.orthographicSize;
float horzExtent = vertExtent * (Screen.width * (camPlayer1.rect.width * 2)) / Screen.height; //I guess the problem is here... but how do I fix this??
There are several issues with your calculations. I guess it's just luck that it works for some situations. While your general idea is correct, you're calculating with the wrong properties. Basically you need to understand the aspect ratio of the cameras, the bounding box of your map and how a camera should behave at the borders.
We need the aspect ratio of the camera to calculate its width or extent.
As you can see in the picture, Screen.width and Screen.height are referring to the game's window or the monitor resolution in case you're running the game fullscreen. You can also see that the cameras may have a different aspect ratio when compared to the game window. The good news is that Unity provides a property to get the camera's aspect ratio.
float camVertExtent = cam.orthograpicSize;
float camHorzExtent = cam.aspect * camVertExtent;
Now that we have the camera's extents, let's take a look at your map and its bounding box.
You tried calculating with bounds.size, but as you can see bounds.size.x is the width of the bounding box. Using the size will only work if your map's bottom-left starts at (0,0) in world space. A better approach is to use bounds.min and bounds.max which already return coordinates in world space.
Your ultimate goal is that the camera should stay within the bounds of the map, i.e., its position is restricted by the following four conditions:
(cam.transform.position.x - camHorzExtent) >= bounds.min.x // left
(cam.transform.position.x + camHorzExtent) <= bounds.max.x // right
(cam.transform.position.y - camVertExtent) >= bounds.min.y // bottom
(cam.transform.position.y + camVertExtent) <= bounds.max.y // top
Now you only need to take the player position and limit the camera to these conditions:
float leftBound = bounds.min.x + camHorzExtent;
float rightBound = bounds.max.x - camHorzExtent;
float bottomBound = bounds.min.y + camVertExtent;
float topBound = bounds.max.y - camVertExtent;
float camX = Mathf.Clamp(player.transform.position.x, leftBound, rightBound);
float camY = Mathf.Clamp(player.transform.position.y, bottomBound, topBound);
cam.transform.position = new Vector3(camX, camY, cam.transform.position.z);
If all cameras have the same size and aspect ratio, you can use the same bounds for all player cameras and only calculate camX and camY for each player.
I'd like to suggest you another approach for your problem.
Is it possible to you to add high colliders at the border of your map, and a collider for the camera? You can then make the camera follow the player (use physics!), and when the player reaches a boundary, the camera won't go over, because of the collider.
Then, you can easily split the screen knowing how many players you have.
One player? --> all screen size
Two players? --> camera 1 ends ad screen height / 2, camera 2 starts at screen heigth /2 +1
and so on
Hi everyone for some people that need the complete code for work into game object with many childrens sprites into Empty Gameobject like:
Background
--mountains1(sprite)
--mountains2(sprite)
--mountains3(sprite)
This Code will be loop into Background object and take the bound of all childrens sprites :D, I make a Frankestein code hahhaa thanks to #Stefan Hoffmann explanation. I hope this will be helpful to others, Sorry for my bad English :(
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraFollow : MonoBehaviour
{
private float rightBound;
private float leftBound;
private float topBound;
private float bottomBound;
private Vector3 pos;
private Transform target;
private Camera cam;
private Bounds bounds;
// Use this for initialization
void Start()
{
target = GameObject.FindWithTag("Player").transform;
foreach (SpriteRenderer spriteBounds in GameObject.Find("Background").GetComponentsInChildren<SpriteRenderer>())
{
bounds.Encapsulate(spriteBounds.bounds);
}
cam = this.gameObject.GetComponent<Camera>();
float camVertExtent = cam.orthographicSize;
float camHorzExtent = cam.aspect * camVertExtent;
Debug.Log(camVertExtent);
Debug.Log(camHorzExtent);
Debug.Log(cam.aspect);
Debug.Log(cam.orthographicSize);
leftBound = bounds.min.x + camHorzExtent;
rightBound = bounds.max.x - camHorzExtent;
bottomBound = bounds.min.y + camVertExtent;
topBound = bounds.max.y - camVertExtent;
Debug.Log("leftBound=" + leftBound);
Debug.Log("rightBound=" + rightBound);
Debug.Log("bottomBound=" + bottomBound);
Debug.Log("topBound=" + topBound);
}
// Update is called once per frame
void Update()
{
float camX = Mathf.Clamp(target.transform.position.x, leftBound, rightBound);
float camY = Mathf.Clamp(target.transform.position.y, bottomBound, topBound);
cam.transform.position = new Vector3(camX, camY, cam.transform.position.z);
}
}
You should use this this simple yet useful unity 2d camera follow script
also available on github.
https://gist.github.com/unity3diy/5aa0b098cb06b3ccbe47
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);
}
}
}
I am trying to create a row out of some square sprites I have. So to get the width of these sprites i am using
tileWidth = (int)tileSet[0].renderer.bounds.size.x;
And then to form the row i am uisng
for(int i = 0; i < tileSet.Length ; i++){
if((i+1)*tileWidth<screenWidth){
tileSet[i].transform.position = new Vector3(i*tileWidth,0,0);
}
}
But the sprites are still overlapping each other and do not form a proper row.
What am i doing wrong here and how can i rectify it?
If you are using Unity 5 you should use this code:
float tileWidth = tileSet[0].GetComponent<SpriteRenderer>().bounds.size.x;
Pay attention to your pixels per unit.
If the sprite's res is 128x128 pixels.
And this sprite's Pixels To Units is 100.
So your tileWidth will be: renderer.bounds.size.x = 128/100 = 1.28
But you use int: (int)renderer.bounds.size.x = (int)1.28 = 1
and this is why your sprites overlapping each other.
float tileWidth = (float)tileSet[0].renderer.bounds.size.x;
SpriteRenderer spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
//size in Units
Vector3 itemSize = spriteRenderer.bounds.size;
float pixelsPerUnit = spriteRenderer.sprite.pixelsPerUnit;
itemSize.y *= pixelsPerUnit;
itemSize.x *= pixelsPerUnit;
As jjxtra noted, Verv's answer is not handling rotation properly (and neither is MBehtemam's, as it's the same answer with a slight syntax update).
The following extension method correctly returns the pixel size of a given texture for different orthographic camera sizes, scales, rotations and textures.
public static Vector2 GetPixelSize(this SpriteRenderer spriteRenderer, Camera camera = null)
{
if (spriteRenderer == null) return Vector2.zero;
if (spriteRenderer.sprite == null) return Vector2.zero;
float pixelsPerUnit = spriteRenderer.sprite.pixelsPerUnit;
// Get top left corner
float offsetRight = spriteRenderer.sprite.rect.size.x / 2f / pixelsPerUnit;
float offsetUp = spriteRenderer.sprite.rect.size.y / 2f / pixelsPerUnit;
Vector2 localRight = Vector2.right * offsetRight;
Vector2 localUp = Vector2.up * offsetUp;
// Go to world
Vector2 worldRight = spriteRenderer.transform.TransformPoint(localRight);
Vector2 worldUp = spriteRenderer.transform.TransformPoint(localUp);
Vector2 worldCenter = spriteRenderer.transform.position;
// Go to pixels
Vector2 coordsRight = GetPixelCoordinates(worldRight, camera);
Vector2 coordsUp = GetPixelCoordinates(worldUp, camera);
Vector2 coordsCenter = GetPixelCoordinates(worldCenter, camera);
// Get sizes
float pixelsRight = Vector2.Distance(coordsCenter, coordsRight);
float pixelsUp = Vector2.Distance(coordsCenter, coordsUp);
Vector2 itemSize = Vector2.right * pixelsRight * 2 + Vector2.up * pixelsUp * 2;
return itemSize;
}
public static Vector2 GetPixelCoordinates(this Transform transform, Camera camera = null)
{
if (transform == null) return Vector2.zero;
return GetPixelCoordinates(transform.position, camera);
}
private static Vector2 GetPixelCoordinates(Vector3 position, Camera camera)
{
if (camera == null)
camera = Camera.main;
if (camera == null) return Vector2.zero;
return camera.WorldToScreenPoint(position);
}
I have an orthographic camera and would like to implement a zoom feature to a specific point. I.e., imagine you have a picture and want to zoom to a specific part of the picture.
I know how to zoom in, the problem is to move the camera to a position that has the desired zone in focus.
How can I do so?
The camera's orthographicSize is the number of world space units in the top half of the viewport. If it's 0.5, then a 1 unit cube will exactly fill the viewport (vertically).
So to zoom in on your target region, center your camera on it (by setting (x,y) to the target's center) and set orthographicSize to half the region's height.
Here is an example to center and zoom to the extents of an object. (Zoom with LMB; 'R' to reset.)
public class OrthographicZoom : MonoBehaviour
{
private Vector3 defaultCenter;
private float defaultHeight; // height of orthographic viewport in world units
private void Start()
{
defaultCenter = camera.transform.position;
defaultHeight = 2f*camera.orthographicSize;
}
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
Collider target = GetTarget();
if(target != null)
OrthoZoom(target.bounds.center, target.bounds.size.y); // Could directly set orthographicSize = bounds.extents.y
}
if (Input.GetKeyDown(KeyCode.R))
OrthoZoom(defaultCenter, defaultHeight);
}
private void OrthoZoom(Vector2 center, float regionHeight)
{
camera.transform.position = new Vector3(center.x, center.y, defaultCenter.z);
camera.orthographicSize = regionHeight/2f;
}
private Collider GetTarget()
{
var hit = new RaycastHit();
Physics.Raycast(camera.ScreenPointToRay(Input.mousePosition), out hit);
return hit.collider;
}
}
hope you find this code example useful, should be a copy / paste.
Note: this script assume it's attached to the camera object, otherwise you should adjust the transform to the camera object reference.
private float lastZoomDistance = float.PositiveInfinity; // remember that this should be reset to infinite on touch end
private float maxZoomOut = 200;
private float maxZoomIn = 50;
private float zoomSpeed = 2;
void Update() {
if (Input.touchCount >= 2) {
Vector2 touch0, touch1;
float distance;
Vector2 pos = new Vector2(transform.position.x, transform.position.y);
touch0 = Input.GetTouch(0).position - pos;
touch1 = Input.GetTouch(1).position - pos;
zoomCenter = (touch0 + touch1) / 2;
distance = Vector2.Distance(touch0, touch1);
if(lastZoomDistance == float.PositiveInfinity) {
lastZoomDistance = distance;
} else {
if(distance > lastZoomDistance && camera.orthographicSize + zoomSpeed <= maxZoomOut) {
this.camera.orthographicSize = this.camera.orthographicSize + zoomSpeed;
// Assuming script is attached to camera - otherwise, change the transform.position to the camera object
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
} else if(distance < lastZoomDistance && camera.orthographicSize - zoomSpeed >= maxZoomIn) {
this.camera.orthographicSize = this.camera.orthographicSize - zoomSpeed;
transform.position = Vector3.Lerp(transform.position, zoomCenter, Time.deltaTime);
}
}
lastZoomDistance = distance;
}
}