Floating origin and visual effect graph in Unity - unity3d

I am sure that everybody knows about this script, http://wiki.unity3d.com/index.php/Floating_Origin, that fixes problems with floating origin easily.
The problem is that the script is outdated and does not move the particle effects created by visual effect graph.
I was trying to rewrite it but I cant seem to make an array to store all the particles, like with the previous one, thus I can't continue from there.
Here is my code:
// Based on the Unity Wiki FloatingOrigin script by Peter Stirling
// URL: http://wiki.unity3d.com/index.php/Floating_Origin
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.VFX;
using UnityEngine.Experimental.VFX;
public class FloatingOrigin : MonoBehaviour
{
[Tooltip("Point of reference from which to check the distance to origin.")]
public Transform ReferenceObject = null;
[Tooltip("Distance from the origin the reference object must be in order to trigger an origin shift.")]
public float Threshold = 5000f;
[Header("Options")]
[Tooltip("When true, origin shifts are considered only from the horizontal distance to orign.")]
public bool Use2DDistance = false;
[Tooltip("When true, updates ALL open scenes. When false, updates only the active scene.")]
public bool UpdateAllScenes = true;
[Tooltip("Should ParticleSystems be moved with an origin shift.")]
public bool UpdateParticles = true;
[Tooltip("Should TrailRenderers be moved with an origin shift.")]
public bool UpdateTrailRenderers = true;
[Tooltip("Should LineRenderers be moved with an origin shift.")]
public bool UpdateLineRenderers = true;
private ParticleSystem.Particle[] parts = null;
VisualEffect[] visualEffect = null;
void LateUpdate()
{
if (ReferenceObject == null)
return;
Vector3 referencePosition = ReferenceObject.position;
if (Use2DDistance)
referencePosition.y = 0f;
if (referencePosition.magnitude > Threshold)
{
MoveRootTransforms(referencePosition);
if (UpdateParticles)
MoveParticles(referencePosition);
if (UpdateTrailRenderers)
MoveTrailRenderers(referencePosition);
if (UpdateLineRenderers)
MoveLineRenderers(referencePosition);
}
}
private void MoveRootTransforms(Vector3 offset)
{
if (UpdateAllScenes)
{
for (int z = 0; z < SceneManager.sceneCount; z++)
{
foreach (GameObject g in SceneManager.GetSceneAt(z).GetRootGameObjects())
g.transform.position -= offset;
}
}
else
{
foreach (GameObject g in SceneManager.GetActiveScene().GetRootGameObjects())
g.transform.position -= offset;
}
}
private void MoveTrailRenderers(Vector3 offset)
{
var trails = FindObjectsOfType<TrailRenderer>() as TrailRenderer[];
foreach (var trail in trails)
{
Vector3[] positions = new Vector3[trail.positionCount];
int positionCount = trail.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
trail.SetPositions(positions);
}
}
private void MoveLineRenderers(Vector3 offset)
{
var lines = FindObjectsOfType<LineRenderer>() as LineRenderer[];
foreach (var line in lines)
{
Vector3[] positions = new Vector3[line.positionCount];
int positionCount = line.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
line.SetPositions(positions);
}
}
private void MoveParticles(Vector3 offset)
{
var particles = FindObjectsOfType<ParticleSystem>() as ParticleSystem[];
foreach (ParticleSystem system in particles)
{
if (system.main.simulationSpace != ParticleSystemSimulationSpace.World)
continue;
int particlesNeeded = system.main.maxParticles;
if (particlesNeeded <= 0)
continue;
bool wasPaused = system.isPaused;
bool wasPlaying = system.isPlaying;
if (!wasPaused)
system.Pause();
// ensure a sufficiently large array in which to store the particles
if (parts == null || parts.Length < particlesNeeded)
{
parts = new ParticleSystem.Particle[particlesNeeded];
}
// now get the particles
int num = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
if (wasPlaying)
system.Play();
}
var particles2 = FindObjectsOfType<VisualEffect>() as VisualEffect[];
foreach (VisualEffect system in particles2)
{
int particlesNeeded = system.aliveParticleCount;
if (particlesNeeded <= 0)
continue;
bool wasPaused = !system.isActiveAndEnabled;
bool wasPlaying = system.isActiveAndEnabled;
if (!wasPaused)
system.Stop();
// ensure a sufficiently large array in which to store the particles
if (visualEffect == null || visualEffect.Length < particlesNeeded)
{
visualEffect = new VisualEffect().visualEffectAsset[particlesNeeded];
}
// now get the particles
int num = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
if (wasPlaying)
system.Play();
}
}
}
On the line(this is a wrong line and everything below it too)
visualEffect = new VisualEffect().visualEffectAsset[particlesNeeded];
, I need to create a similar array to the line (correct one, but for the old particle system)
parts = new ParticleSystem.Particle[particlesNeeded];
that creates array full of particles (but with VisualEffect class).
If I can fix this one, there should not be any problem with the rest.
I think that solving this problem will help literally thousands of people now and in the future, since limitation for floating origin in unity are horrible and majority of people working in unity will need floating origin for their game worlds, with VFX graph particles.
Thanks for the help.

My question has been answered here:
https://forum.unity.com/threads/floating-origin-and-visual-effect-graph.962646/#post-6270837

Related

How to enlarge a ragdoll in game - Unity

I have a ragdoll. I want to increase the scale of this ragdoll in game mode. But when I increase the scale ragdoll' bones mingle and drool. How can i prevent this from happening? Related pictures below.
Normal Scale
3x Scale
Welcome to StackOverflow. After a quick search on Google and I've found an answer for you:
http://answers.unity.com/answers/1556521/view.html
TL;DR: joints calculate anchor only on start, but are never updated later. To make them update later, just reassign them
Transform[] children;
private Vector3[] _connectedAnchor;
private Vector3[] _anchor;
void Start()
{
children = transform.GetComponentsInChildren<Transform>();
_connectedAnchor = new Vector3[children.Length];
_anchor = new Vector3[children.Length];
for (int i = 0; i < children.Length; i++)
{
if (children[i].GetComponent<Joint>() != null)
{
_connectedAnchor[i] = children[i].GetComponent<Joint>().connectedAnchor;
_anchor[i] = children[i].GetComponent<Joint>().anchor;
}
}
}
private void Update()
{
for (int i = 0; i < children.Length; i++)
{
if (children[i].GetComponent<Joint>() != null)
{
children[i].GetComponent<Joint>().connectedAnchor = _connectedAnchor[i];
children[i].GetComponent<Joint>().anchor = _anchor[i];
}
}
}
Just make sure you do this reassign only when needed as it will hurt your performance...

Microphone, gain value and spectrum values do not sync using Unity

I am making a simple voice visualization program. My goals are:
Playback microphone input
Visualize voice spectrum and gain in real time
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VisualizeVoice : MonoBehaviour
{
private const int NUM_SPECTRUM_SAMPLES = 256;
private const int NUM_SPECTRUM_BARS = 32;
private const int NUM_PCM_SAMPLES = 16000;
private const float BAR_DROP_SPEED = 1e-3f;
private const int NUM_SAMPLES_TO_AVERAGE = 8;
private string _deviceName;
private float[] _spectrumData = new float[NUM_SPECTRUM_SAMPLES];
private float[] _fPCMData = new float[NUM_PCM_SAMPLES];
private float _gain = 0;
private AudioClip _audio; // Audio from microphone
private AudioSource _playback; // To play the audio from microphone
// For visualization
private GameObject[] _spectrumBars = new GameObject[NUM_SPECTRUM_BARS];
private GameObject _gainBar;
// Start is called before the first frame update
void Start()
{
if (Microphone.devices.Length == 0) {
Debug.LogError("No Microphone");
return;
}
_deviceName = Microphone.devices[0];
Debug.Log("Current microphone is " + _deviceName);
if ((_playback = this.GetComponent<AudioSource>()) == null) {
_playback = this.gameObject.AddComponent<AudioSource>();
}
_playback.loop = true;
_playback.bypassEffects = true;
_playback.bypassListenerEffects = true;
_playback.bypassReverbZones = true;
_playback.priority = 0;
_playback.pitch = 1;
_playback.clip = _audio = Microphone.Start(_deviceName, true, 1, AudioSettings.outputSampleRate);
// Sync microphone and playback, but it always fails
float waitTime = 0;
while (!(Microphone.GetPosition(_deviceName) > 0) && waitTime <= 2)
waitTime += Time.deltaTime;
if (waitTime > 2) {
Debug.LogError("time out waiting for microphone");
}
_playback.Play();
InitVisualization();
}
// Update is called once per frame
void Update()
{
// Get PCM data and calculate gain
var audioPosition = Microphone.GetPosition(_deviceName);
_audio.GetData(_fPCMData, audioPosition);
UpdateGain();
// Get spectrum data
_playback.GetSpectrumData(_spectrumData, 0, FFTWindow.BlackmanHarris);
// Update visualization
UpdateVisualization();
}
private void InitVisualization()
{
// Initialize spectrum bars
for (int ibar = 0; ibar < NUM_SPECTRUM_BARS; ibar++) {
_spectrumBars[ibar] = GameObject.CreatePrimitive(PrimitiveType.Cube);
_spectrumBars[ibar].transform.parent = this.transform;
_spectrumBars[ibar].transform.localPosition = new Vector3(ibar, 0, 0);
_spectrumBars[ibar].transform.localScale = new Vector3(1, 0, 1);
}
// Initialize gain bar
_gainBar = GameObject.CreatePrimitive(PrimitiveType.Cube);
_gainBar.transform.parent = this.transform;
_gainBar.transform.localPosition = new Vector3(-5, 0, 0);
_gainBar.transform.localScale = new Vector3(4, 0, 1);
// Overall dimension
this.transform.localScale = new Vector3(0.2f, 10.0f, 0.2f);
}
private void UpdateVisualization()
{
// Update spectrum bars
int nSamplesPerBar = NUM_SPECTRUM_SAMPLES / NUM_SPECTRUM_BARS;
for (int ibar = 0; ibar < NUM_SPECTRUM_BARS; ibar++) {
// Calculate value of each bar
float value = 0;
for (int isample = 0; isample < nSamplesPerBar; isample++) {
value += _spectrumData[ibar * nSamplesPerBar + isample];
}
value /= nSamplesPerBar;
// Use current value if increasing, or slowly drop previous value if decreasing
float prevValue = _spectrumBars[ibar].transform.localScale.y;
if (value < prevValue)
value = prevValue - BAR_DROP_SPEED;
// Y scale is set to value
_spectrumBars[ibar].transform.localScale = new Vector3(1, value, 1);
}
// Update gain bar
_gainBar.transform.localScale = new Vector3(4, _gain, 1);
}
private void UpdateGain()
{
_gain = 0;
for(int i = 0; i < NUM_SAMPLES_TO_AVERAGE; i++) {
_gain += Mathf.Abs(_fPCMData[NUM_PCM_SAMPLES - i - 1]);
}
_gain /= NUM_SAMPLES_TO_AVERAGE;
}
}
Here are my questions:
I can't use while (!Microphone.GetPosition(_deviceName) > 0)); to avoid latency from microphone to speaker. If I use it, my application just freezes. If I add code to allow time-out, it has time-out every time.
The gain bar seems irrelevant with my voice. I don't know if my calculation is right.
I'm not sure if I need to average over multiple samples calculating gains, and how many samples I need to average over. I need this gain value later to detect silent moments and cut audio data.
To 1.
You can. Unity allows to define Start as a Coroutine
private IEnumerator Start()
{
...
}
On this way you can use a non blocking
while (!Microphone.GetPosition(_deviceName) > 0))
{
yield return null;
}

how to stop tiles from spawning after a certain number in unity3d

I have a script that spawns endless tiles (3D) and i want it to stop at after a certain number (e.g. 100) and at the end of the last tile (the 100th) i want to spawn an other prefab like a portal.
I have no clue how to do that.
Any answer i have found on google couldnt help.
Any help is much appreciated.
void Start()
{
nextTileLocation = startPoint;
nextTileRotation = Quaternion.identity;
for (int i = 0; i < initSpawnNum; ++i)
{
SpawnNextTile (i >= initNoObstacles);
}
}
public void SpawnNextTile(bool spawnObstacles = true)
{
var newTile = Instantiate (tile, nextTileLocation, nextTileRotation);
var nextTile = newTile.Find ("Next Spawn Point");
nextTileLocation = nextTile.position;
nextTileRotation = nextTile.rotation;
if (!spawnObstacles)
return;
var obstacleSpawnPoints = new List<GameObject> ();
foreach (Transform child in newTile) {
if (child.CompareTag ("ObstacleSpawn")) {
obstacleSpawnPoints.Add (child.gameObject);
}
}
if (obstacleSpawnPoints.Count > 0) {
var spawnPoint = obstacleSpawnPoints [Random.Range (0, obstacleSpawnPoints.Count)];
var spawnPos = spawnPoint.transform.position;
var newObstacle = Instantiate (obstacle, spawnPos, Quaternion.identity);
newObstacle.SetParent (spawnPoint.transform);
}
}
You could do something like pass in a bool to tell the function to spawn a portal.
void Start()
{
nextTileLocation = startPoint;
nextTileRotation = Quaternion.identity;
for (int i = 0; i < initSpawnNum; ++i)
{
// Pass in true for the last tile
SpawnNextTile (i >= initNoObstacles, i == initSpawnNum - 1);
}
}
public void SpawnNextTile(bool spawnObstacles = true, bool shouldSpawnPortal = false)
{
//
}
Edit to show adding the tiles to a list:
class YourScript : MonoBehaviour
{
private List<GameObject> tiles = new List<GameObject>();
private void SpawnNextTile(bool spawnObstacles = true, bool shouldSpawnPortal = false)
{
var newTile = Instantiate (tile, nextTileLocation, nextTileRotation);
tiles.Add(newTile);
// The rest of your code
}
}

scaling issue on click event

I am developing a 2D game in Unity. I've created a character panel in that to let player select different character. In panel, there are thumbnails for different character. By tapping on a particular character thumbnail, the player can view that character. The original scale of thumbnail is 1, and when player taps on thumbnail, the scale get doubles. All is fine till this. but issue is that whenever player taps on thumbnail its scale gets double. But i want to limit it to once only. I've used flag to stop scaling, But still issue is there. After flag it stops scaling, but now player can click on multiple character simultaneously. I am copying snippet here.
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class ViewCharacter : MonoBehaviour {
[SerializeField]
private GameObject TempCharacterHolder ,TempCharacter, TempCharacterText, TempCharacterPrice;
// Use this for initialization
void Start () {
for (int i = 0; i < ShoppingManager.instance.ShoppingList.Count; i++) {
if (i == TheGameController.instance.GetSelectedCharacter ()) {
PlayerPrefs.SetInt ("CharacterScaled" + i, 1);
} else {
PlayerPrefs.SetInt ("CharacterScaled" + i, 0);
}
}
}
public void ViewCharacterFunc()
{
int ClickedCharacter = int.Parse (TempCharacterText.GetComponent<Text> ().text);
foreach (var characters in ShoppingManager.instance.ShoppingList) {
if (string.Equals (characters.CharacterName, TempCharacterText.GetComponent<Text> ().text)) {
if (PlayerPrefs.GetInt("CharacterScaled"+characters.CharacterName)==0) {
ShoppingManager.instance.IncreaseScale (TempCharacter, TempCharacterHolder);
for (int i = 0; i < ShoppingManager.instance.ShoppingList.Count; i++) {
if (i == ClickedCharacter) {
PlayerPrefs.SetInt ("CharacterScaled" + i, 1);
} else {
PlayerPrefs.SetInt ("CharacterScaled" + i, 0);
}
}
}
} else {
Color clr = characters.Character_Holder.GetComponent<Image> ().color;
clr.a = 1;
characters.Character_Holder.GetComponent<Image> ().color = clr;
Vector3 TempVector = characters.CharaacterObject.GetComponent<RectTransform> ().localScale;
TempVector.x = 1f;
TempVector.y = 1f;
characters.CharaacterObject.GetComponent<RectTransform> ().localScale = TempVector;
}
}
}
}
If I understand your question correctly, your characters scale numerous times when you click on them instead of scaling once.
If that's the case, I'd suggest controlling that with a bool:
bool hasTouched = false;
void OnMouseDown()
{
ShoppingManager.instance.Message.SetActive (false);
foreach (var characters in ShoppingManager.instance.ShoppingList) {
Color clr = characters.Character_Holder.GetComponent<Image> ().color;
clr.a = 1;
characters.Character_Holder.GetComponent<Image> ().color = clr;
if (!hasTouched) //if we havent touched
{
Vector3 TempVector = characters.CharaacterObject.GetComponent<RectTransform> ().localScale*Time.deltaTime;
TempVector.x = 1.0f;
TempVector.y = 1.0f;
characters.CharaacterObject.GetComponent<RectTransform> ().localScale = TempVector;
hasTouched = true; //then we scale it, and we have touched it
}
}

Lifting platforms is not working as it should

I would like to make some lifting platforms in my game, so if the platform went down, the characters can't go over it. I have written a script for it, but for some reason the "lifting up" is not working as intended. It won't go back to its starting place, but it will go a bit below. And for some reason it won't go smoothly to the place where it should, just "teleport" there and done. I thougt multiplying Time.deltaTime with a const will help, but it is the same.
Here is my code, any help would be appreciated:
public class LiftingPlatform : MonoBehaviour {
private Transform lift;
private bool isCanBeLifted;
private float timeToLift;
public float timeNeededToLift = 5f;
private Vector3 startPos;
private Vector3 downPos;
private Vector3 shouldPos;
private bool isDown;
public GameObject[] collidingWalls;
// Use this for initialization
void Start () {
lift = transform;
isCanBeLifted = true;
timeToLift = 0f;
isDown = false;
startPos = transform.position;
downPos = new Vector3(startPos.x, startPos.y - 5f, startPos.z);
}
// Update is called once per frame
void Update () {
timeToLift += Time.deltaTime;
if (timeToLift >= timeNeededToLift) {
if (isCanBeLifted) {
if (isDown) {
shouldPos = Vector3.Lerp(startPos, downPos, Time.deltaTime * 10);
lift.position = new Vector3(shouldPos.x, shouldPos.y, shouldPos.z);
isDown = true;
}
else if (!isDown) {
shouldPos = Vector3.Lerp(downPos, new Vector3(startPos.x, startPos.y, startPos.z), Time.deltaTime * 10);
lift.position = new Vector3(shouldPos.x, shouldPos.y, shouldPos.z);
isDown = false;
}
}
timeToLift = 0;
}
if (!isDown) {
for (int i = 0; i < collidingWalls.Length; i++) {
collidingWalls[i].SetActive(true);
}
}
else if (isDown) {
for (int i = 0; i < collidingWalls.Length; i++) {
collidingWalls[i].SetActive(false);
}
}
}
void OnTriggerEnter(Collider collider) {
if (collider.tag == "Player" || collider.tag == "Enemy") {
isCanBeLifted = false;
}
}
void OnTriggerExit(Collider collider) {
if (collider.tag == "Player" || collider.tag == "Enemy") {
isCanBeLifted = true;
}
}
}
These lifting platforms are a child of another Platforms object.
It doesn't look like you are updating the object's position every frame. You are only checking if the total time passed is greater than the time needed to lift, and then updating the position to a value that is dependent on the delta time (using the Vector3.Lerp function).
What I would do is in the update step, if timeToLift is greater then timeNeededToLift, subtract the latter from the former and invert the value of isDown. Then, in your Vector3.Lerp, make the third argument (timeToLift / timeNeededToLift) instead of (Time.deltaTime * 10). Can you try that and see if it works?
The third argument for Vector3.Lerp is the "blending factor" between the two vectors, 0 is the first vector, 1 is the second, and 0.5 is in between. If the total time is greater than the time needed to lift, but the delta time is not greater than 1, it will get the position of the platform using a blending factor of less than 1, resulting in a platform that didn't move fully.