I have 2 scenes in my Unity Project. The first one is a loading scene which consist of a simple text and a slide bar. And the second scene is a random generator of 'terrain'(3 differents cubes of size 1x1x1).
The time it gets to load the second scene is about 15 seconds, but when I use the method progress from AsyncOperation, I only get the values 0 or 0.9.
This is my script for the loading bar:
IEnumerator LoadingScreen(int level)
{
button.gameObject.SetActive(false);
loadingScreenObj.SetActive(true);
AsyncOperation async = SceneManager.LoadSceneAsync(level);
async.allowSceneActivation = false;
Debug.Log(async.progress);
while(!async.isDone){
slider.value = async.progress;
Debug.Log(slider.value);
if (async.progress >= 0.9f){
slider.value = 1f;
async.allowSceneActivation = true;
}
yield return null;
}
}
And the script for the terrain generator is:
public class SpawnInitialFloor : MonoBehaviour {
public GameObject [] prefabs;
private GameObject floor;
List<Vector2> list = new List<Vector2>();
private float y = 0;
private float yWater = -0.1f;
public int maxIterations = 50;
private int max = 1;
private int min = -1;
// Use this for initialization
void Start (){
setSpawn();
}
private void setSpawn()
{
int r;
for (int i = 0; i < maxIterations; ++i){
for (int xIt = min; xIt <= max; ++xIt){
for (int zIt = min; zIt <= max; ++zIt){
if (!list.Contains(new Vector2(xIt, zIt))){
r = Random.Range(0, 3);
if (r == 1)
floor = Instantiate(prefabs[r], new Vector3(xIt, yWater, zIt), Quaternion.identity) as GameObject;
else
floor = Instantiate(prefabs[r], new Vector3(xIt, y, zIt), Quaternion.identity) as GameObject;
list.Add(new Vector2(xIt, zIt));
}
}
}
max += 1;
min -= 1;
}
}
}
The loading bar always looks like this for about the 15 seconds of the other scene loading: Loading Bar
And before and after the complete load of the second scene:
Before - After
I wanted to know if I have to change something in the SpawnInitialFloor script or use other thing instead of the progress method of AsyncOperation.
Related
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movements : MonoBehaviour
{
public List<Transform> objectsToMove = new List<Transform>();
public List<Vector3> positions = new List<Vector3>();
public int amountOfPositions = 30;
public int minRandRange, maxRandRange;
public bool randomPositions = false;
public bool generateNewPositions = false;
public float duration = 5f;
public bool pingPong = false;
private void Start()
{
if (generateNewPositions || (positions.Count == 0 && amountOfPositions > 0))
GeneratePositions();
StartCoroutine(MoveBetweenPositions(duration));
}
private void GeneratePositions()
{
for(int i = 0; i < amountOfPositions; i++)
{
if (randomPositions)
{
var randPosX = UnityEngine.Random.Range(minRandRange, maxRandRange);
var randPosY = UnityEngine.Random.Range(minRandRange, maxRandRange);
var randPosZ = UnityEngine.Random.Range(minRandRange, maxRandRange);
positions.Add(new Vector3(randPosX, randPosY, randPosZ));
}
else
{
positions.Add(new Vector3(i, i, i));
}
}
}
IEnumerator MoveBetweenPositions(float duration)
{
for(int i = 0; i < positions.Count; i++)
{
float time = 0;
Vector3 startPosition = objectsToMove[0].position;
while(time < duration)
{
transform.position = Vector3.Lerp(startPosition, positions[i], time / duration);
time += Time.deltaTime;
yield return null;
}
objectsToMove[0].position = positions[i];
}
}
}
Now I have one object to move in the editor a cube. but if I have for example 20 cubes and I want that the first cube will move to the first position(waypoint) then after duration of 5 or any duration the next cube will move to the first position then the first cube will move to the second position and son all the cubes will move to the next position/s with speed and duration.
So each 5 seconds another cube start to move between the positions and each cube will move smooth with speed value between the positions.
For example the duration is 5 and also the speed is 5.
Later I want to use enum or something like that to be able to choose modes for example ping pong or backward or stop(each cube will stop in the last waypoint) or continue so the cubes will continue move between the waypoints nonstop.
Seems like this:
while(time < duration)
{
transform.position = Vector3.Lerp(startPosition, positions[i], time/duration);
time += Time.deltaTime;
yield return null;
}
should be this:
while(time < duration)
{
objectsToMove[i].position = Vector3.Lerp(startPosition, positions[i], time / duration);
time += Time.deltaTime;
yield return null;
}
if i understood your problem right.
The script is attached to empty gameobject :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwitchText : MonoBehaviour
{
public GameObject[] objectsTexts;
private bool isDisplaying = false;
private Vector3[] lastFwd;
private float curAngleX = 0;
private GameObject[] objectsWithText;
public void Init()
{
objectsWithText = GameObject.FindGameObjectsWithTag("ObjectToAddText");
lastFwd = new Vector3[objectsWithText.Length];
for(int i = 0; i < objectsWithText.Length; i++)
{
lastFwd[i] = objectsWithText[i].transform.forward;
}
}
private void Update()
{
if (isDisplaying == false)
{
StartCoroutine(UpdateDisplayPhrase(objectsWithText));//objectsTexts[i].name, objectsWithText[i].GetComponent<TextMesh>()));
}
}
private bool myApproximation(float a, float b, float tolerance)
{
return (Mathf.Abs(a - b) < tolerance);
}
private IEnumerator UpdateDisplayPhrase(GameObject[] objects)//string text, TextMesh t)
{
// block multiple calls
//if (isDisplaying) yield break;
isDisplaying = true;
for (int i = 0; i < objectsWithText.Length; i++)
{
var curFwd = objectsWithText[i].transform.forward;
// measure the angle rotated since last frame:
var ang = Vector3.Angle(curFwd, lastFwd[i]);
if (myApproximation(ang, 179f, 1f) == true)
{
var t = objectsWithText[i].GetComponent<TextMesh>();
var text = objectsTexts[i].name;
// you can simply yield IEnumerators so they are executed and at the same time
// wait until finished
yield return StartCoroutine(FadeTextTo(0, 0.6f, t));//FadeTextToZeroAlpha(1, t);
t.text = text;
// NOTE: you pass in 0
// -> DIVIDING BY 0 ?!
yield return StartCoroutine(FadeTextTo(1, 0.6f, t));//FadeTextToFullAlpha(0, t);
}
// when done reset the blocking flag
//isDisplaying = false;
}
}
public IEnumerator FadeTextTo(float targetAlpha, float maxDuration, TextMesh textMesh)
{
// more efficient to get both colors beforehand
var fromColor = textMesh.color;
var toColor = new Color(fromColor.r, fromColor.g, fromColor.b, targetAlpha);
// this is optional ofcourse but I like to do this in order to
// always have the same fading speed even if it is already slightly faded into one direction
var actualDuration = maxDuration * Mathf.Abs(fromColor.a - toColor.a);
var passedTime = 0f;
while (passedTime < actualDuration)
{
var lerpFactor = passedTime / actualDuration;
// now the huge advantage is that you can add ease-in and -out if you like e.g.
//lerpFactor = Mathf.SmoothStep(0, 1, lerpFactor);
textMesh.color = Color.Lerp(fromColor, toColor, lerpFactor);
// avoid overshooting
passedTime += Mathf.Min(Time.deltaTime, actualDuration - passedTime);
yield return null;
}
// just to be sure in the end always set it once
textMesh.color = toColor;
}
}
I'm calling the Init method in another script in the Start after adding text first time to the gameobjects.
Using a break point in the SwitchText script on the line :
StartCoroutine(UpdateDisplayPhrase(objectsWithText));
objectsWithText contain 3 objects also objectsTexts contain 3 objects.
The problem is that the objectsWithText not rotating yet bit in the Update it's starting the Coroutine already.
The main goal is to switch the text on the TextMesh objects to the names of the objects in objectsTexts.
This script rotate the objects :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public GameObject[] objectsToRotate;
public float duration = 5f;
private void OnMouseDown()
{
StartCoroutine(StartRotationOfObjects());
}
private IEnumerator StartRotationOfObjects()
{
for (int i = 0; i < objectsToRotate.Length; i++)
{
// Random wait period before rotation starts
if (i == 0)
{
yield return new WaitForSeconds(0);
}
else
{
yield return new WaitForSeconds(Random.Range(0, 2f));
}
StartCoroutine(Rotates(objectsToRotate[i].transform, duration));
}
}
private IEnumerator Rotates(Transform objectToRotate, float duration)
{
Quaternion startRot = objectToRotate.rotation;
float t = 0.0f;
while (t < duration)
{
t += Time.deltaTime;
objectToRotate.rotation = startRot * Quaternion.AngleAxis(t / duration * 360f, Vector3.up);
yield return null;
}
objectToRotate.rotation = startRot;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
public GameObject stairsPrefab;
public int delay = 3;
public int stairsNumber = 5;
public int stairsHeight = 0;
public Vector3 stairsPosition;
public Vector2 stairsSize;
// Use this for initialization
void Start ()
{
StartCoroutine(BuildStairs());
}
// Update is called once per frame
void Update ()
{
}
private IEnumerator BuildStairs()
{
for (float i = 0; i <= stairsSize.x; i++)
{
for (float k = 0; k <= stairsSize.y; k++)
{
stairsPosition = new Vector3(i, stairsHeight, k);
GameObject stairs = Instantiate(stairsPrefab, stairsPosition, Quaternion.identity);
stairs.transform.localScale = new Vector3(stairsSize.x, 1 , stairsSize.y);
stairsHeight += 1;
yield return new WaitForSeconds(delay);
}
}
}
private void CalculateNextStair()
{
}
}
I messed it up. For example I want to build 5 stairs but the loops are over the stairs size and not number of stairs.
Second it's creating 10 sets of stairs not 5 stairs:
Another problem is how can I make that each stair will be build slowly ? Now it's just Instantiate slowly with delay but how can I generate each stair with delay?
Screenshot of the script inspector:
My current code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GenerateStairs : MonoBehaviour
{
public GameObject stairsPrefab;
public float delay = 0.3f;
public int stairsNumber = 5;
public int stairsPositions = 0;
public int stairsStartPositionHeight = 0;
public float stairsScalingHaight = 1;
public Vector2 stairsPosition;
public Vector2 stairsSize;
// Use this for initialization
void Start()
{
StartCoroutine(BuildStairs());
}
// Update is called once per frame
void Update()
{
}
private IEnumerator BuildStairs()
{
for (float i = 0; i <= stairsNumber; i++)
{
// x=0f, y=z=stairsHeight
stairsPosition = new Vector3(0f, stairsPositions, stairsPositions);
GameObject stairs = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stairs.transform.localScale = new Vector3(
stairsSize.x,
stairsScalingHaight,
stairsSize.y);
stairsStartPositionHeight += 1;
yield return new WaitForSeconds(delay);
}
}
private void CalculateNextStair()
{
}
}
There's no reason to loop over the size of the stairs at all; you want to loop over stairsNumber, which is yet unused in your code.
Also, you don't need to change the x component of your stairs' positions. Keep it at 0f (or whatever you need).
The y and z components of your stairs positions (relative to the starting point) should both be factors of stairHeight. In this particular case, you want them to be equal to stairHeight, so that you get "square" step shapes.
private IEnumerator BuildStairs()
{
for (int i = 0; i <= stairsNumber ; i++) {
// x=0f, y=z=stairsHeight
stairsPosition = new Vector3(0f, stairsHeight, stairsHeight);
GameObject stairs = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stairs.transform.localScale = new Vector3(
stairsSize.x,
1f ,
stairsSize.y);
stairsHeight += 1f;
yield return new WaitForSeconds(delay);
}
}
If you change stairSize to be a Vector3, then you can just use stairSize directly as the localScale, and increment stairsHeight by stairsSize.y instead of just 1f.
If you want to offset the starting position of your stairs, you need to include an offset. I recommend keeping it separate from the height counter until you need to add them.
Also, if you want to have rectangular sized steps, keep a widthFactor to multiply by the height to find how far each step moves horizontally.
Combining these changes might look like this:
Vector3 stairSize;
float stepWidthFactor=1f;
Vector3 stairsStartPosition;
private IEnumerator BuildStairs() {
for (int i = 0; i <= stairsNumber ; i++) {
stairsPosition = new Vector3(
stairsStartPosition.x,
stairsStartPosition.y + stairsHeight,
stairsStartPosition.z + stairsHeight*stepWidthFactor);
GameObject stairs = Instantiate(
stairsPrefab,
stairsPosition,
Quaternion.identity);
stairsHeight += stairsSize.y;
stairs.transform.localScale = stairSize;
yield return new WaitForSeconds(delay);
}
}
The code below works Except for the Instancated objects moving on their own. I want my Instancated objects to move back and fourth between pointA and pointB at a speed 0.5f.
Note: Im not trying to use the commented code in Start() and Update() because this file is attached to the camera.
With current code: My objectList objects are moving as expected just not their instantiated objects. I would like the Instantiated objects to move like ping-pong with their off-set
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectsSpawner : MonoBehaviour {
public GameObject[] objectList;
public GameObject[] objectSpawns;
int val;
public float speed = 0.5f;
Vector3 pointA;
Vector3 pointB;
// Use this for initialization
void Start () {
val = PlayerPrefs.GetInt("CannonPowerVal");
addToList();
for (int i = 1; i < objectSpawns.Length; i++){
pointA = new Vector3(-3.8f, objectSpawns[i].transform.localPosition.y, 0);
pointB = new Vector3(3.8f, objectSpawns[i].transform.localPosition.y, 0);
}
//pointA = new Vector3(-3.8f, transform.localPosition.y, 0);
//pointB = new Vector3(3.8f, transform.localPosition.y, 0);
}
// Update is called once per frame
void Update()
{
//PingPong between 0 and 1
float time = Mathf.PingPong(Time.time * speed, 1);
//transform.position = Vector3.Lerp(pointA, pointB, time);
for (int i = 1; i < objectSpawns.Length; i++)
{
objectSpawns[i].transform.position = Vector3.Lerp(pointA, pointB, time);
}
}
public void addToList(){
objectSpawns = new GameObject[val];
int max = objectList.Length;
int counter = 8; // set first object out of screen sight
// Adds Scene Objects from objectList to objectSpawns
// Size of SceneObjects determined by CannonPowerVal
for (int i = 0; i < PlayerPrefs.GetInt("CannonPowerVal"); i++){
objectSpawns.SetValue(objectList[Random.Range(0, max)], i);
// Random x spawn(-2.8f, 2.8f)
Instantiate(objectSpawns[i], new Vector2(transform.localPosition.x + Random.Range(-2.8f,2.8f), transform.localPosition.y + counter), Quaternion.identity);
counter = counter + 5;
}
}
}
after instantiating the object, you forgot to add the reference to the list of objectSpawns.
In addToList() method do:
GameObject object = Instantiate(objectSpawns[i],...);
objectSpawns.Add(object)
Hi everyone I have been making and experimenting on an 3d endless runner game and came with an issue. Here is what I meant to achieve. I have two list of gameobjects called activeTiles and deactivatedTiles. According to my idea I want to first add all the prefab tiles to the deactivatedtTiles list. Next I have a float amtTileOnScreen variable which controls the amount of tiles put in front of the player to run. Then I take a random Tile from the list of deactivated tiles to activated tiles by considering the amount of tiles o screen and put in-front of the player. Used tiles are put back to deactivated tile list and the whole cycle begins.
The question is how do I achieve this? Help would be appreciated.
Here's what I have tried.
public class TileManager : MonoBehaviour
{
public GameObject[] tilePrefabs;
private Transform playerTransform;
private float spawnZ = -12f;
private float tileLength = 24.0f;
private int amtOfTilesOnScreen = 5;
private float safeZone = 56.0f;
private GameObject spawnedTile;
public static List<GameObject> activeTiles;
public static List<GameObject> deactivatedTiles;
private int lastPrefabIndex = 0;
private Vector3 transformTiles;
// Use this for initialization
void Start ()
{
activeTiles = new List<GameObject>();
deactivatedTiles = new List<GameObject>();
playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
for (int i = 0; i < amtOfTilesOnScreen; i++)
{
if (i < 1)
{
activeTiles.Add(SpawnTileAtFront(0));
}
else
{
activeTiles.Add(SpawnTileAtFront());
}
}
}
void Update ()
{
if (playerTransform.position.z - safeZone > (spawnZ - amtOfTilesOnScreen * tileLength))
{
for (int i = 0; i < tilePrefabs.Length; i++)
{
spawnedTile = SpawnTileAtFront();
deactivatedTiles.Add(spawnedTile);
Debug.Log(deactivatedTiles.Count);
}
if (activeTiles.Count < (amtOfTilesOnScreen + 1))
{
activeTiles.Add(GetRandomDeactivatedTile());
MoveTileToTheFront(GetRandomDeactivatedTile());
}
else
{
var disposeTile = activeTiles[0];
deactivatedTiles.Add(disposeTile);
DisposeActiveTiles(0);
}
}
}
private void MoveTileToTheFront(GameObject tile)
{
tile.transform.position = Vector3.forward * spawnZ;
spawnZ += tileLength;
}
private GameObject SpawnTileAtFront(int prefabIndex = -1)
{
GameObject go;
if (prefabIndex == -1)
{
go = Instantiate(tilePrefabs[RandomPrefabIndex()]) as GameObject;
}
else
{
go = Instantiate(tilePrefabs[prefabIndex]) as GameObject;
}
go.transform.SetParent(transform);
MoveTileToTheFront(go);
return go;
}
private void DisposeActiveTiles(int index)
{
GameObject unusedTile = activeTiles[index];
activeTiles.RemoveAt(index);
deactivatedTiles.Add(unusedTile);
}
private GameObject GetRandomDeactivatedTile()
{
if (deactivatedTiles.Count == 0)
return null;
int randomIndex = Random.Range(0, deactivatedTiles.Count);
GameObject unusedTile = deactivatedTiles[randomIndex];
deactivatedTiles.RemoveAt(randomIndex);
return unusedTile;
}
private int RandomPrefabIndex()
{
if (tilePrefabs.Length <= 0)
{
return 0;
}
int randomIndex = lastPrefabIndex;
while (randomIndex == lastPrefabIndex)
{
randomIndex = Random.Range(0, tilePrefabs.Length);
}
lastPrefabIndex = randomIndex;
return lastPrefabIndex;
}
}
void Update ()
{
while (playerTransform.position.z - safeZone > (spawnZ - amtOfTilesOnScreen * tileLength))
{
// we need to add a new tile in front of the player
GameObject t;
if (deactivatedTiles.Count == 0) {
// no deactivated tiles so we need to instantiate a new tile
t = SpawnTileAtFront ();
} else {
// otherwise take deactivated tile into use
t = GetRandomDeactivatedTile ();
MoveTileToTheFront (t);
}
// new tile is now active tile
activeTiles.Add (t);
// take oldest active tile and move it to deactivated list
DisposeActiveTiles(0);
}
}