Infinite Parallax Background in Unity - unity3d

I have been trying to get infinite parallaxing working with Unity 2d. I have gotten the parallaxing to work but I start to run into issues when trying to make the background continue infinitely.
I should mention that the camera backgrounds are restricted movement on the X axis only. The Player can jump and move up and down but the background and camera Y position stays constant.
The main problem is that out of my 11 backgrounds used for the parallax effect, only the first one ever gets cloned and none of them get destroyed when off screen(Although this is more of a secondary concern at this point).
I've tried a few different ways to detect that the player is in front of the background. I've used GameObjects attached to each background object and compared them to the Player's position. That didn't work very well so in my current version, I'm using cameras to detect the Player's position.
My process for creating the infinite background is as follows:
Loop: Through all the background images and do the following checks:
If: Player position is outside the bounds of the current background on the left.
Then: Create a copy of the current background and place it to the left the current background.
If: Player position is outside the bounds of the current background on the right.
Then: Create a copy of the current background and place it to the right the current background.
To clean up the backgrounds, I just check if the Player is in front of one of the backgrounds and if not then delete it.
Below is the working parallax code along with the attempted infinite background code at the bottom:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ParallaxBackground : MonoBehaviour {
public GameObject[] backgrounds;
public float smooting = 1f;
public int offset = -1;
public Transform cam;
public Camera Lcam;
public Camera Rcam;
//private Transform cam;
private Vector3 previousCamPos;
private float[] parallaxScales;
private GameObject[] backgroundClones;
// Use this for initialization
void Start () {
previousCamPos = cam.position;
parallaxScales = new float[backgrounds.Length];
for (int i = 0; i < backgrounds.Length; i++) {
parallaxScales[i] = backgrounds[i].transform.position.z * offset;
}
}
// Update is called once per frame
void FixedUpdate () {
// Handle paralaxing
for (int i = 0; i < backgrounds.Length; i++) {
float parallax = (previousCamPos.x - cam.position.x) * parallaxScales[i];
float backgroundTargetPosX = backgrounds[i].transform.position.x + parallax;
Vector3 backgroundTargetPos = new Vector3(backgroundTargetPosX, backgrounds[i].transform.position.y, backgrounds[i].transform.position.z);
backgrounds[i].transform.position = Vector3.Lerp(backgrounds[i].transform.position, backgroundTargetPos, smooting * Time.deltaTime);
}
/* Handle continuous backgrounds*/
for (int i = 0; i < backgrounds.Length; i++)
{
// Left Camera
float pointL = Lcam.WorldToViewportPoint(backgrounds[i].transform.position).x;
// Right Camera
float pointR = Rcam.WorldToViewportPoint(backgrounds[i].transform.position).x;
// Check if the object is within the Left camera
if (pointL < 1)
{
Destroy(backgroundClones[i]);
var clone = Instantiate(backgrounds[i].gameObject);
clone.transform.position = Rcam.transform.position;
backgroundClones[i] = clone;
}
else if (pointR > 0)
{
Destroy(backgroundClones[i]);
var clone = Instantiate(backgrounds[i].gameObject);
clone.transform.position = Lcam.transform.position;
backgroundClones[i] = clone;
}
}
/* Handle removing backgrounds*/
for (int i = 0; i < backgrounds.Length; i++)
{
// Main Camera
Vector3 point = Camera.main.WorldToScreenPoint(backgrounds[i].transform.position);
// Left Camera
float pointL = Lcam.WorldToViewportPoint(backgrounds[i].transform.position).x;
// Right Camera
float pointR = Rcam.WorldToViewportPoint(backgrounds[i].transform.position).x;
// Check if the object is within the main camera
if (point.x > 0 || point.x < 1)
{
}
else {
Destroy(backgrounds[i]);
}
}
previousCamPos = cam.position;
}
}

Related

Unity renders object before updating Rigidbody2D's properties

I am trying to implement a way for the player to switch between a square and a circle. For this to work my player object has two colliders, one circle and one box. When switching between them I simply disable one collider and enable the other, and switch the current sprite. The issue arises when I switch from a circle to a square.
I want the square to be able to glide across the floor, whereas the circle is supposed to roll. In order to make the switch seamless I have to reorient the square to be aligned with the current velocity, and remove the angular velocity. This does seem to work, however there is a slight period of frames (or frame) where the square has the same rotation the circle had before switching. This seems odd to me since the new rotation and sprite is changed in the same part of the code. This is a video showcasing the issue.
If this is an issue resulting from the way the objects are rendered I can solve this another way. I would just like to understand why it happens.
Code snippet of the part that changes the properties from circle to square when switching:
else if (Input.GetKeyDown("2"))
{
// Update rotation of box to velocity:
float newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
float newAngleDegrees = newAngleRadians * 180 / Mathf.PI;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
playerShape = Shape.SQUARE;
spriteRenderer.sprite = spriteArray[1];
circleCollider.enabled = false;
boxCollider.enabled = true;
updateShape = true;
}
Logging the angle of the rigidbody directly after setting it to newAngleDegrees shows that the rotation has been set correct, yet the issue persists.
And just in case it is needed, full code of the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class scr_StateMachine : MonoBehaviour
{
// Types of shapes:
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Variables:
public Rigidbody2D rb;
public SpriteRenderer spriteRenderer;
public Sprite[] spriteArray;
public Shape playerShape;
public CircleCollider2D circleCollider;
public BoxCollider2D boxCollider;
private bool updateShape;
void Start()
{
playerShape = Shape.CIRCLE;
updateShape = true;
}
void Update()
{
// Get input for shape change:
if(Input.GetKeyDown("1"))
{
playerShape = Shape.CIRCLE;
spriteRenderer.sprite = spriteArray[0];
circleCollider.enabled = true;
boxCollider.enabled = false;
updateShape = true;
}
else if (Input.GetKeyDown("2"))
{
// Update rotation of box to velocity:
float newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
float newAngleDegrees = newAngleRadians * 180 / Mathf.PI;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
playerShape = Shape.SQUARE;
spriteRenderer.sprite = spriteArray[1];
circleCollider.enabled = false;
boxCollider.enabled = true;
updateShape = true;
}
// Update movement script's shape:
if (updateShape)
{
GetComponent<scr_Movement>().shape = playerShape;
updateShape = false;
}
}
}
I think the issue is Rigidbody/Rigidbody2D physics are applied in fixed time steps (see FixedUpdate). Therefore yes, on a strong device it can definitely happen that you render some frames before the next FixedUpdate call kicks in and changes the Rigidbody/Rigidbody2D behavior.
I think what you could do is actually wait with the change for the next FixedUpdate call e.g. using a Coroutine and WaitForFixedUpdate like e.g.
public class scr_StateMachine : MonoBehaviour
{
// Types of shapes:
public enum Shape { SQUARE, CIRCLE, TRIANGLE }
// Variables:
public Rigidbody2D rb;
public SpriteRenderer spriteRenderer;
public Sprite[] spriteArray;
public Shape playerShape;
public CircleCollider2D circleCollider;
public BoxCollider2D boxCollider;
[SerializeField] private scr_Movement _scrMovement;
void Start()
{
if(!_scrMovement) _scrMovement = GetComponent<scr_Movement>();
ChangeShape(Shape.CIRCLE);
}
// Still get User Input in Update
void Update()
{
// Get input for shape change:
if(Input.GetKeyDown("1"))
{
ChangeShape(Shape.CIRCLE);
}
else if (Input.GetKeyDown("2"))
{
ChangeShape(Shape.SQUARE);
}
}
private void ChangeShape(Shape newShape)
{
// if the same shape comes in we already have -> nothing to do
if(newShape == playerShape) return;
// Stop any already running coroutine since we only want to handle the last input before the FixUpdate call
// https://docs.unity3d.com/ScriptReference/MonoBehaviour.StopAllCoroutines.html
StopAllCoroutines();
// Start a new coroutine for the new shape
// see https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html
StartCoroutine(ChangeShapeInNextFixedUpdate(newShape));
}
private IEnumerator ChangeShapeInNextFixedUpdate(Shape newShape)
{
// just in case again, if the same shape comes in we already have -> nothing to do
if(newShape == playerShape) yield break;
// Wait until the next FixedUpdate call
// see https://docs.unity3d.com/ScriptReference/WaitForFixedUpdate.html
yield return new WaitForFixedUpdate();
// Now do your required changes depending on the new shape
circleCollider.enabled = newShape == Shape.CIRCLE;
boxCollider.enabled = newShape == Shape.SQUARE;
switch(newShape)
{
case Shape.CIRCLE:
spriteRenderer.sprite = spriteArray[0];
break;
case Shape.SQUARE:
// Update rotation of box to velocity:
var newAngleRadians = Mathf.Atan2(rb.velocity.y, rb.velocity.x);
// see https://docs.unity3d.com/ScriptReference/Mathf.Rad2Deg.html
var newAngleDegrees = newAngleRadians * Mathf.Rad2Deg;
rb.rotation = newAngleDegrees;
rb.angularVelocity = 0;
Debug.Log(rb.rotation);
spriteRenderer.sprite = spriteArray[1];
break;
}
playerShape = newShape;
_scrMovement.shape = playerShape;
}
}

How to resize all particles from a particle system?

I'm trying to dynamically resize particles using a slider, as well as change their colour.
Particles are used to display datapoints in a 3D scatterplot. I'm using this code: https://github.com/PrinzEugn/Scatterplot_Standalone
private ParticleSystem.Particle[] particlePoints;
void Update () {
pointScale = sizeSlider.value;
for (int i = 0; i < pointList.Count; i++) {
Quaternion quaternion = Camera.current.transform.rotation;
Vector3 angles = quaternion.eulerAngles;
// Set point color
particlePoints[i].startColor = new Color(angles.x, angles.y, angles.z, 1.0f);
particlePoints[i].transform.localScale = new Vector3(pointScale, pointScale, pointScale);
}
}
The issue is that there's no transform method for Particles, and changing the "startColour" doesn't change anything.
The API states that "The current size of the particle is calculated procedurally based on this value and the active size modules."
What does that mean, and how can I change the size of the particles ?
Thanks to previous answers I managed to get this working:
In the PlacePrefabPoints method I add every instantiated prefab to a List, and I add a listener to the slider, which looks like this:
void changedPointSize(){
pointScale = sizeSlider.value;
for (int i = 0; i < objects.Count; i++) {
objects[i].transform.localScale = new Vector3(pointScale, pointScale, pointScale);
}
}
Thanks all !
I just had a look at PointRenderer.cs -> CreateParticles and PlacePrefabPoints give a good hint what has to be changed.
So I guess you would simply change the scale values
foreach (var point in particlePoints)
{
Quaternion quaternion = Camera.current.transform.rotation;
Vector3 angles = quaternion.eulerAngles;
// Set point color
point.startColor = new Color(angles.x, angles.y, angles.z, 1.0f);
point.startSize = sizeSlider.value;
}
and than re-call
GetComponent<ParticleSystem>().SetParticles(particlePoints, particlePoints.Length);
it is questionable though if you really would do this in Update. I would rather do it in sizeSlider.onValueChanged to only do it when neccesarry (you could even make a certain treshold that has to be changed before updating the view) but well for the color there might be no other option than doing it in Update but atleast there I would use a Threshold:
privtae ParticleSystem ps;
// I assume you have that referenced in the inspector
public Slider sizeSlider;
// flag to control whether system should be updated
private bool updateSystem;
privtae void Awake()
{
ps = GetComponent<ParticleSystem>();
}
private void OnEnable()
{
// add a listener to onValueChanged
// it is secure to remove it first (even if not there yet)
// this makes sure it is not added twice
sizeSlider.onValueChanged.RemoveListener(OnsliderChanged());
sizeSlider.onValueChanged.AddListener(OnsliderChanged());
}
private void OnDisable()
{
// cleanup listener
sizeSlider.onValueChanged.RemoveListener(OnsliderChanged());
}
private void OnSliderChanged()
{
foreach (var point in particlePoints)
{
point.startSize = sizeSlider.value;
}
// do the same also for the instantiated prefabs
foreach(Transform child in PointHolder.transform)
{
child.localScale = Vecto3.one * sizeSlider.value;
}
updateSystem = true;
}
private Quaternion lastCameraRot;
public float CameraUpdateThreshold;
private void Update()
{
if(Quaternion.Angle(Camera.current.transform.rotation, lastCameraRot) > CameraUpdateThreshold)
{
foreach (var point in particlePoints)
{
Quaternion quaternion = Camera.current.transform.rotation;
Vector3 angles = quaternion.eulerAngles;
// Set point color
point.startColor = new Color(angles.x, angles.y, angles.z, 1.0f);
}
lastCameraRot = Camera.current.transform.rotation;
updateSystem = true;
}
if(!updateSystem) return;
updateSystem = false;
ps.SetParticles(particlePoints, particlePoints.Length);
}

Unity Vuforia: Camera position is wrong when trying to draw a line with LineRenderer

Hello im new at AR development, i've tried to make a simple script that takes the camera position and the position of some object in the world and then draw a simple line between them using LineRenderer.
The object is tied to an imagetarget and im running with the FIRST_TARGET setting (so the world should have its origin (0,0,0) on the imagetarget)
However the camera position seems to be wrong for me and i dont really understand why. What i want is a line from the center of the mobile (Camera) screen to some object in the world viewed using an imagetarget. I would love some help with my issue. The code for my script is here:
public class POILine : MonoBehaviour
{
//Camera
private GameObject camera;
//Gameobject of interest to point the user towards
public GameObject to;
private GameObject toParent;
private LineRenderer line;
public float lineWidthMultiplier = 0.5f;
private float distance;
public float distanceMin = 50f;
void Start ()
{
camera = GameObject.FindGameObjectWithTag("MainCamera");
line = this.gameObject.AddComponent<LineRenderer>();
line.positionCount = 2;
//Thickness of the line
line.widthMultiplier = lineWidthMultiplier;
}
// Update is called once per frame
void Update ()
{
TrackableBehaviour.Status toStatus = to.transform.parent.GetComponent<TrackableBehaviour>().CurrentStatus;
if (toStatus == TrackableBehaviour.Status.TRACKED || toStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
{
distance = Vector3.Distance(camera.transform.position, to.transform.position);
if (distance > distanceMin)
{
line.enabled = true;
if (to != null)
{
//I think the error is here
line.SetPosition(0, camera.transform.position);
line.SetPosition(1, to.transform.position);
}
}
else
{
line.enabled = false;
}
}
}
Managed to get it working, what i did was that i placed an empty gameobject as a child to the Imagetarget i was currently tracking, then i made it follow the ARCamera transform position.
Then the code works by rendering a Line from that empty gameobject to the object of interest.

Unity - Infinite sprite spawner stops spawning at a high speed

i wrote a script for my 2D car game for an infinite track. So i got a "killer" behind my car, that destroys all ground objects coming out the screen on the left and on the right i have a spawner that spawns all my blocky sprites in it and it works pretty good.
Here is my update function:
void Update()
{
if(Mathf.Round(this.transform.position.x) == limit)
{
//Debug.Log("Limit reached");
limit += 10;
Spawn();
}
}
I attached the script to my camera and i have a start limit set to 160 (because i already got 15 10x10 sprites as start). Everytime my spawner passes the x-axis-limit it spawns a new sprite at this position and sets the next limit 10 higher. This works good if I don't drive too fast. Because then it stops spawning and the world is cut off. When I drive back to get my spawner back into the already spawned area and drive slowly again to it, it works again. I believe the method is just to inefficient to spawn fast enough so I maybe need another style of doing it.
For the understanding here the rest of the script:
using UnityEngine;
using System.Collections;
public class Spawner : MonoBehaviour
{
public GameObject[] obj;
private int limit = 160;
public int yAxisValue = -1;
public bool isOnlyDirt;
private ArrayList rotationValues = new ArrayList();
void Start()
{
//Spawn ();
int value = 0;
for(int i = 0; i < 4; i++)
{
rotationValues.Add(value);
//Debug.Log(rotationValues[i]);
value += 90;
}
}
void Spawn()
{
Vector3 pos = new Vector3 (Mathf.Round(transform.position.x), yAxisValue, transform.position.z);
Quaternion rotation = new Quaternion (0, 0, 0, 0);
if(isOnlyDirt)
{
int zRot = (int)rotationValues[Random.Range(0, rotationValues.Count - 1)];
//Debug.Log(zRot);
rotation = new Quaternion(0, 0, zRot, 0);
}
var SpawnedGround = Instantiate(obj[Random.Range(0, obj.GetLength(0))], pos, rotation);
(SpawnedGround as GameObject).gameObject.tag = "Gro
I also have a one-liner to move my spawner in front of my car so it can spawn things:
public float yCoord;
void Start ()
{
this.transform.position = new Vector3 (transform.position.x + 160, -yCoord, transform.position.z);
}
I parented it so i just have to write it in the start function.
Any ideas to improve this one?
Thanks
Sorry can't post as comments. You should try
if(Mathf.Round(this.transform.position.x) >= limit)
instead of
if(Mathf.Round(this.transform.position.x) == limit)
I think the floating point precision is skipping the checking.

Make the Camera fit the background image in Unity

Okay so I have a long image I'm using for a scene, it will be the entire level 1 background.
The height is 1080. I set the render settings to the same as my background image, but the camera has the Default unity background showing at the bottom of my floor (bottom of sprite image background).
If I move the camera it doesn't do anything about the black background.
I'm also using a script on the camera to follow the player, could that be an issue?
Sorry if I wasn't that clear here is screen cap:
http://s30.postimg.org/4aq7hd4a9/EXAMPLE.jpg
and here is what I'd like it to look like:
http://s17.postimg.org/r2pgy8pnz/example_2.jpg
Here is the camera script:
using UnityEngine;
using System.Collections;
public class GameCamera : MonoBehaviour {
private Transform target;
private float trackSpeed = 10;
// Set target
public void SetTarget(Transform t) {
target = t;
}
// Track target
void LateUpdate() {
if (target) {
float x = IncrementTowards(transform.position.x, target.position.x, trackSpeed);
float y = IncrementTowards(transform.position.y, target.position.y, trackSpeed);
transform.position = new Vector3(x,y, transform.position.z);
}
}
// Increase n towards target by speed
private float IncrementTowards(float n, float target, float a) {
if (n == target) {
return n;
}
else {
float dir = Mathf.Sign(target - n); // must n be increased or decreased to get closer to target
n += a * Time.deltaTime * dir;
return (dir == Mathf.Sign(target-n))? n: target; // if n has now passed target then return target, otherwise return n
}
}
}