How to display Text during Unity game? - c#

I inherited by my ex collegue a Unity game. I need to display a label in my scene. The label should be contains the text "what is your level of fear?"
The user should be throught Logitech steering wheel, using the rotation button select a number from 0 to 9.
Now I m new user of unity and I want to start this task step by step. My Unity project have a Init scene that can start other scenes.
In my Init scene I create this static component (FearTest):
This component have a RedDot (a simple red dot) and textAnsia2 that contains the text that I need to display.
This is my class FreatTest:
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace DrivingTest
{
public class FearTest : MonoBehaviour
{
//public GameObject redDot;
public TextMeshPro textAnsia2;
public TextMesh textAnsia3;
public int shouldEvaluateTest = 0; // 0 - false, 1 - true
public int secondsInterval;
public int secondsToDisaply;
public int radiusR1;
public int radiusR2;
public int reactionTestDuration;
public int maxDots;
public float dotRadius = 1;
private float endTime;
private float dotDisaplyAtTime;
private List<float> dotDisplayReactTime = new List<float>();
private int missedSignals;
private int currentDotsCount;
private bool isReactionAlreadyGiven;
public bool ShouldEvaluateTest
{
get
{
return shouldEvaluateTest != 0;
}
}
void OnEnable()
{
GameManager.TestSceneLoaded += OnSceneLoaded;
}
private void OnDisable()
{
GameManager.TestSceneLoaded -= OnSceneLoaded;
}
#region Scene Loaded
private void OnSceneLoaded(eTESTS test)
{
if (SceneManager.GetActiveScene().name != test.ToString())
return;
Reset();
GetApiParams();
}
#endregion
private void GetApiParams()
{
#if UNITY_EDITOR
if (!GameManager.Instance)
{
Init();
return;
}
#endif
Debug.Log("called rt");
NextTestOutput nextTestOutput = GameManager.Instance.currentTest;
if (nextTestOutput.content != null && nextTestOutput.content.Count > 0)
{
foreach (var item in nextTestOutput.content[0].listInputParameter)
{
switch ((ePARAMETERS)item.id)
{
case ePARAMETERS.RT_ENABLE:
shouldEvaluateTest = System.Convert.ToInt32(item.Value);
break;
case ePARAMETERS.RT_DURATION:
reactionTestDuration = System.Convert.ToInt32(item.Value);
break;
case ePARAMETERS.RED_DOT_FREQ:
secondsInterval = System.Convert.ToInt32(item.Value);
break;
case ePARAMETERS.RED_DOT_MAX_COUNT:
maxDots = System.Convert.ToInt32(item.Value);
break;
case ePARAMETERS.RED_DOT_RADIUS_R1:
radiusR1 = System.Convert.ToInt32(item.Value);
break;
case ePARAMETERS.RED_DOT_RADIUS_R2:
radiusR2 = System.Convert.ToInt32(item.Value);
break;
case ePARAMETERS.RED_DOT_SIZE:
dotRadius = float.Parse(item.Value)/10f;
break;
case ePARAMETERS.RED_DOT_TIME:
secondsToDisaply = System.Convert.ToInt32(item.Value);
break;
}
}
Debug.Log("called rt "+ shouldEvaluateTest);
/*if (ShouldEvaluateTest)
{
Init();
}*/
Init();//dopo bisogna sistemare il shoudl evaluatetest
}
}
Coroutine displayCoroutine;
public void Init()
{
endTime = Time.time + reactionTestDuration + 10;
SetRedDotSize();
displayCoroutine = StartCoroutine(RedDotDisplay());
}
private IEnumerator RedDotDisplay()
{
yield return new WaitForSeconds(2);
while (true)
{
SetRandomDotPosition();
RedDot(true);
isReactionAlreadyGiven = false;
dotDisaplyAtTime = Time.time;
currentDotsCount++;
yield return new WaitForSeconds(secondsToDisaply);
if(!isReactionAlreadyGiven)
{
missedSignals++;
}
RedDot(false);
if ((reactionTestDuration > 0 && endTime <= Time.time) || (maxDots > 0 && currentDotsCount >= maxDots))
break;
float waitTime = secondsInterval - secondsToDisaply;
yield return new WaitForSeconds(waitTime);
}
}
private void Update()
{
if (!ShouldEvaluateTest)
return;
if (!isReactionAlreadyGiven && /*redDot.activeSelf &&*/ (LogitechGSDK.LogiIsConnected(0) && LogitechGSDK.LogiButtonIsPressed(0, 23)))
{
isReactionAlreadyGiven = true;
float reactionTime = Time.time - dotDisaplyAtTime;
Debug.Log("Reaction Time RT : " + reactionTime);
RedDot(false);
dotDisplayReactTime.Add(reactionTime);
}
}
public double GetReactionTimeAvg()
{
double avg = 0;
foreach (var item in dotDisplayReactTime)
{
avg += item;
}
//avg / currentDotsCount
return avg / (float)dotDisplayReactTime.Count;
}
public double GetMissedSignals()
{
return ((float) missedSignals / (float) currentDotsCount) * 100;
}
private void RedDot(bool state)
{
//redDot.SetActive(state);
textAnsia2.SetText("Pippo 2");
}
private void SetRedDotSize()
{
//redDot.transform.localScale *= dotRadius;
textAnsia2.transform.localScale *= dotRadius;
textAnsia3.transform.localScale *= dotRadius;
}
private void SetRandomDotPosition()
{
//redDot.GetComponent<RectTransform>().anchoredPosition = GetRandomPointBetweenTwoCircles(radiusR1, radiusR2)*scale;
float scale = ((Screen.height*0.9f) / radiusR2) * 0.9f;
Vector3 pos = GetRandomPointBetweenTwoCircles(radiusR1, radiusR2) * scale;
Debug.Log("RT temp pos : " + pos);
pos = new Vector3(500, 500, 0);
Debug.Log("RT pos : " + pos);
// redDot.transform.position = pos;
Vector3 pos2 = new Vector3(20, 20, 0);
Debug.Log("text ansia 2 : " + pos2);
textAnsia2.transform.position = pos2;
textAnsia3.transform.position = pos;
}
#region Getting Red Dot b/w 2 cricles
/*
Code from : https://gist.github.com/Ashwinning/89fa09b3aa3de4fd72c946a874b77658
*/
/// <summary>
/// Returns a random point in the space between two concentric circles.
/// </summary>
/// <param name="minRadius"></param>
/// <param name="maxRadius"></param>
/// <returns></returns>
Vector3 GetRandomPointBetweenTwoCircles(float minRadius, float maxRadius)
{
//Get a point on a unit circle (radius = 1) by normalizing a random point inside unit circle.
Vector3 randomUnitPoint = Random.insideUnitCircle.normalized;
//Now get a random point between the corresponding points on both the circles
return GetRandomVector3Between(randomUnitPoint * minRadius, randomUnitPoint * maxRadius);
}
/// <summary>
/// Returns a random vector3 between min and max. (Inclusive)
/// </summary>
/// <returns>The <see cref="UnityEngine.Vector3"/>.</returns>
/// <param name="min">Minimum.</param>
/// <param name="max">Max.</param>
Vector3 GetRandomVector3Between(Vector3 min, Vector3 max)
{
return min + Random.Range(0, 1) * (max - min);
}
#endregion
#region Reset
private void Reset()
{
if (displayCoroutine != null)
StopCoroutine(displayCoroutine);
RedDot(false);
shouldEvaluateTest = 0;
reactionTestDuration = 0;
secondsInterval = 0;
missedSignals = 0;
maxDots = 0;
radiusR1 = 0;
radiusR2 = 0;
dotRadius = 1;
secondsToDisaply = 0;
endTime = 0;
dotDisaplyAtTime = 0;
dotDisplayReactTime.Clear();
//redDot.transform.localScale = Vector3.one;
textAnsia2.transform.localScale = Vector3.one;
textAnsia3.transform.localScale = Vector3.one;
currentDotsCount = 0;
isReactionAlreadyGiven = true;
}
#endregion
}
}
When "SetRandomDotPosition" method is called, in my scene I can display in a random position of the screen the RedDot (that is a simple image with a red dot), and I need to display also my text.
The red dot is displayed, but I m not able to display the text.
How can I fixed it ?

Related

Doom-like face system using unity UI

As you can see in the code below , i have a OnGUI method that "draws" texture depending on the number i give to this method . is there a way to do this by using unity's UI system instead of GUI ? I've tried to do it myself , but was not able to make a method that would change the image on the screen depending on the given number .
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class FaceSystem : MonoBehaviour
{
// HP = HitPoints, SHT = While Shooting, DMG = While taking damage
// FW = Forward, L = Left, R = Right
// Numbers are the HP ranges for the different faces
public Texture2D HP80100FW;
public Texture2D HP80100L;
public Texture2D HP80100R;
public Texture2D HP6079FW;
public Texture2D HP6079L;
public Texture2D HP60790R;
public Texture2D HP4059FW;
public Texture2D HP4059L;
public Texture2D HP4059R;
public Texture2D HP2039FW;
public Texture2D HP2039L;
public Texture2D HP2039R;
public Texture2D HP119FW;
public Texture2D HP119L;
public Texture2D HP119R;
public Texture2D HP0;
public Texture2D SHT80100;
public Texture2D SHT6079;
public Texture2D SHT4059;
public Texture2D SHT2039;
public Texture2D SHT119;
public Texture2D DMG80100;
public Texture2D DMG6079;
public Texture2D DMG4059;
public Texture2D DMG2039;
public Texture2D DMG119;
int pick;
Texture2D[] imgs;
int i;
float timer;
public PlayerHealth PlayerHealth;
public Image healthIndicator;
public Sprite madddead;
void Start()
{
// have every image in an array for easy access
imgs = new Texture2D[26];
imgs[0] = HP80100FW;
imgs[1] = HP80100L;
imgs[2] = HP80100R;
imgs[3] = HP6079FW;
imgs[4] = HP6079L;
imgs[5] = HP60790R;
imgs[6] = HP4059FW;
imgs[7] = HP4059L;
imgs[8] = HP4059R;
imgs[9] = HP2039FW;
imgs[10] = HP2039L;
imgs[11] = HP2039R;
imgs[12] = HP119FW;
imgs[13] = HP119L;
imgs[14] = HP119R;
imgs[15] = HP0;
imgs[16] = SHT80100;
imgs[17] = SHT6079;
imgs[18] = SHT4059;
imgs[19] = SHT2039;
imgs[20] = SHT119;
imgs[21] = DMG80100;
imgs[22] = DMG6079;
imgs[23] = DMG4059;
imgs[24] = DMG2039;
imgs[25] = DMG119;
}
void Update()
{
Faces();
}
public void Faces()
{
timer -= Time.deltaTime;
// modify the timers to your liking
if (PlayerHealth.health >= 80 & PlayerHealth.health <= 100 || PlayerHealth.health >100)
{
if (Input.GetMouseButton(0))
{
timer = 1f;
pick = 16;
}
if (PlayerHealth.isDamaged == true) // add a bool for when damaged in your health script!
{
timer = 0.5f;
pick = 21;
}
if (timer < 0 & !Input.GetMouseButton(0))
{
timer = 1.5f;
// get a random number not equal to current
i = pick;
while (i == pick)
{
pick = Random.Range(0, 3);
}
}
}
if (PlayerHealth.health >= 60 & PlayerHealth.health <= 79)
{
if (Input.GetMouseButton(0))
{
timer = 1f;
pick = 17;
}
if (PlayerHealth.isDamaged == true)
{
timer = 0.5f;
pick = 22;
}
if (timer < 0 & !Input.GetMouseButton(0))
{
timer = 1.5f;
// get a random number not equal to current
i = pick;
while (i == pick)
{
pick = Random.Range(3, 6);
}
}
}
if (PlayerHealth.health >= 40 & PlayerHealth.health <= 59)
{
if (Input.GetMouseButton(0))
{
timer = 1f;
pick = 18;
}
if (PlayerHealth.isDamaged == true)
{
timer = 0.5f;
pick = 23;
}
if (timer < 0 & !Input.GetMouseButton(0))
{
timer = 1.5f;
// get a random number not equal to current
i = pick;
while (i == pick)
{
pick = Random.Range(6, 9);
}
}
}
if (PlayerHealth.health >= 20 & PlayerHealth.health <= 39)
{
if (Input.GetMouseButton(0))
{
timer = 1f;
pick = 19;
}
if (PlayerHealth.isDamaged == true)
{
timer = 0.5f;
pick = 24;
}
if (timer < 0 & !Input.GetMouseButton(0))
{
timer = 1.5f;
// get a random number not equal to current
i = pick;
while (i == pick)
{
pick = Random.Range(9, 12);
}
}
}
if (PlayerHealth.health >= 1 & PlayerHealth.health <= 19)
{
if (Input.GetMouseButton(0))
{
timer = 1f;
pick = 20;
}
if (PlayerHealth.isDamaged == true)
{
timer = 0.5f;
pick = 25;
}
if (timer < 0 & !Input.GetMouseButton(0))
{
timer = 1.5f;
// get a random number not equal to current
i = pick;
while (i == pick)
{
pick = Random.Range(12, 15);
}
}
}
if (PlayerHealth.health <= 0)
{
pick = 15;
}
}
private void OnGUI()
{
if(PlayerHealth.health >0)
{
GUI.DrawTexture(new Rect(695,830, 515, 315), imgs[pick]);
}
else
{
healthIndicator.sprite= madddead;
}
}
}
Pseudo-algorithm:
create your interface with UI, add either Image or RawImage, depending your input
sprite for Image, texture for RawImage
add in your behavior a property, i.e. Image or RawImage and assign it in the inspector
your behavior now knows which UI control to assign an image to
do your logic and set that UI control image accordingly
https://docs.unity3d.com/Packages/com.unity.ugui#1.0/manual/script-Image.html
https://docs.unity3d.com/Packages/com.unity.ugui#1.0/manual/script-RawImage.html

Unity Error building Player because scripts had compiler errors

I know this is a well-known question. But I don't know what to do.
(Open the image in a new tab for better clarity)
That script FastIKFabric.cs is working perfectly (moreover it's from asset store) and as you can see in the inspector it does not have any using UnityEditor;. The line 250 is the last one from that script and the } is closed properly. As I said, the script does not have any errors.
What can I do? Thanks in advance for any answer! :)
Here is the script:
#if UNITY_EDITOR
#endif
using UnityEngine;
namespace DitzelGames.FastIK
{
/// <summary>
/// Fabrik IK Solver
/// </summary>
public class FastIKFabric : MonoBehaviour
{
/// <summary>
/// Chain length of bones
/// </summary>
public int ChainLength = 2;
/// <summary>
/// Target the chain should bent to
/// </summary>
public Transform Target;
public Transform Pole;
/// <summary>
/// Solver iterations per update
/// </summary>
[Header("Solver Parameters")]
public int Iterations = 10;
/// <summary>
/// Distance when the solver stops
/// </summary>
public float Delta = 0.001f;
/// <summary>
/// Strength of going back to the start position.
/// </summary>
[Range(0, 1)]
public float SnapBackStrength = 1f;
protected float[] BonesLength; //Target to Origin
protected float CompleteLength;
protected Transform[] Bones;
protected Vector3[] Positions;
protected Vector3[] StartDirectionSucc;
protected Quaternion[] StartRotationBone;
protected Quaternion StartRotationTarget;
protected Transform Root;
// Start is called before the first frame update
void Awake()
{
Init();
}
void Init()
{
//initial array
Bones = new Transform[ChainLength + 1];
Positions = new Vector3[ChainLength + 1];
BonesLength = new float[ChainLength];
StartDirectionSucc = new Vector3[ChainLength + 1];
StartRotationBone = new Quaternion[ChainLength + 1];
//find root
Root = transform;
for (var i = 0; i <= ChainLength; i++)
{
if (Root == null)
throw new UnityException("The chain value is longer than the ancestor chain!");
Root = Root.parent;
}
//init target
if (Target == null)
{
Target = new GameObject(gameObject.name + " Target").transform;
SetPositionRootSpace(Target, GetPositionRootSpace(transform));
}
StartRotationTarget = GetRotationRootSpace(Target);
//init data
var current = transform;
CompleteLength = 0;
for (var i = Bones.Length - 1; i >= 0; i--)
{
Bones[i] = current;
StartRotationBone[i] = GetRotationRootSpace(current);
if (i == Bones.Length - 1)
{
//leaf
StartDirectionSucc[i] = GetPositionRootSpace(Target) - GetPositionRootSpace(current);
}
else
{
//mid bone
StartDirectionSucc[i] = GetPositionRootSpace(Bones[i + 1]) - GetPositionRootSpace(current);
BonesLength[i] = StartDirectionSucc[i].magnitude;
CompleteLength += BonesLength[i];
}
current = current.parent;
}
}
// Update is called once per frame
void LateUpdate()
{
ResolveIK();
}
private void ResolveIK()
{
if (Target == null)
return;
if (BonesLength.Length != ChainLength)
Init();
//Fabric
// root
// (bone0) (bonelen 0) (bone1) (bonelen 1) (bone2)...
// x--------------------x--------------------x---...
//get position
for (int i = 0; i < Bones.Length; i++)
Positions[i] = GetPositionRootSpace(Bones[i]);
var targetPosition = GetPositionRootSpace(Target);
var targetRotation = GetRotationRootSpace(Target);
//1st is possible to reach?
if ((targetPosition - GetPositionRootSpace(Bones[0])).sqrMagnitude >= CompleteLength * CompleteLength)
{
//just strech it
var direction = (targetPosition - Positions[0]).normalized;
//set everything after root
for (int i = 1; i < Positions.Length; i++)
Positions[i] = Positions[i - 1] + direction * BonesLength[i - 1];
}
else
{
for (int i = 0; i < Positions.Length - 1; i++)
Positions[i + 1] = Vector3.Lerp(Positions[i + 1], Positions[i] + StartDirectionSucc[i], SnapBackStrength);
for (int iteration = 0; iteration < Iterations; iteration++)
{
//https://www.youtube.com/watch?v=UNoX65PRehA
//back
for (int i = Positions.Length - 1; i > 0; i--)
{
if (i == Positions.Length - 1)
Positions[i] = targetPosition; //set it to target
else
Positions[i] = Positions[i + 1] + (Positions[i] - Positions[i + 1]).normalized * BonesLength[i]; //set in line on distance
}
//forward
for (int i = 1; i < Positions.Length; i++)
Positions[i] = Positions[i - 1] + (Positions[i] - Positions[i - 1]).normalized * BonesLength[i - 1];
//close enough?
if ((Positions[Positions.Length - 1] - targetPosition).sqrMagnitude < Delta * Delta)
break;
}
}
//move towards pole
if (Pole != null)
{
var polePosition = GetPositionRootSpace(Pole);
for (int i = 1; i < Positions.Length - 1; i++)
{
var plane = new Plane(Positions[i + 1] - Positions[i - 1], Positions[i - 1]);
var projectedPole = plane.ClosestPointOnPlane(polePosition);
var projectedBone = plane.ClosestPointOnPlane(Positions[i]);
var angle = Vector3.SignedAngle(projectedBone - Positions[i - 1], projectedPole - Positions[i - 1], plane.normal);
Positions[i] = Quaternion.AngleAxis(angle, plane.normal) * (Positions[i] - Positions[i - 1]) + Positions[i - 1];
}
}
//set position & rotation
for (int i = 0; i < Positions.Length; i++)
{
if (i == Positions.Length - 1)
SetRotationRootSpace(Bones[i], Quaternion.Inverse(targetRotation) * StartRotationTarget * Quaternion.Inverse(StartRotationBone[i]));
else
SetRotationRootSpace(Bones[i], Quaternion.FromToRotation(StartDirectionSucc[i], Positions[i + 1] - Positions[i]) * Quaternion.Inverse(StartRotationBone[i]));
SetPositionRootSpace(Bones[i], Positions[i]);
}
}
private Vector3 GetPositionRootSpace(Transform current)
{
if (Root == null)
return current.position;
else
return Quaternion.Inverse(Root.rotation) * (current.position - Root.position);
}
private void SetPositionRootSpace(Transform current, Vector3 position)
{
if (Root == null)
current.position = position;
else
current.position = Root.rotation * position + Root.position;
}
private Quaternion GetRotationRootSpace(Transform current)
{
//inverse(after) * before => rot: before -> after
if (Root == null)
return current.rotation;
else
return Quaternion.Inverse(current.rotation) * Root.rotation;
}
private void SetRotationRootSpace(Transform current, Quaternion rotation)
{
if (Root == null)
current.rotation = rotation;
else
current.rotation = Root.rotation * rotation;
}
void OnDrawGizmos()
{
#if UNITY_EDITOR
var current = this.transform;
for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
{
var scale = Vector3.Distance(current.position, current.parent.position) * 0.1f;
//Handles.matrix = Matrix4x4.TRS(current.position, Quaternion.FromToRotation(Vector3.up, current.parent.position - current.position), new Vector3(scale, Vector3.Distance(current.parent.position, current.position), scale));
//Handles.color = Color.green;
//Handles.DrawWireCube(Vector3.up * 0.5f, Vector3.one);
current = current.parent;
}
}
#endif
}
}
I don't believe you, the compiler doesn't lie. Perhaps you closed it properly, but did you save the script in visual studio before rebuilding??
Just 2 cents. A long answer just to illustrate the problem and make it easier for others to see.
Take a minute and think about the preprocessor directive (#if UNITY_EDITOR), so, if we are inside/using the UnityEditor the code inside the directives (#if...#endif) will be active.
So since we have:
// previous code ...
void OnDrawGizmos()
{
#if UNITY_EDITOR
var current = this.transform;
for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
{
// ...code...
}
}
#endif
// rest of the code ...
private void LikeAnotherMethod()
{
....
}
While we are in UNITY_EDITOR will be equal to;
// previous code ...
void OnDrawGizmos()
{
var current = this.transform;
for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
{
// ...code...
}
}
// rest of the code ...
private void LikeAnotherMethod()
{
....
}
But, if we are not on UnityEditor's world (like on an Android, iOS, or MacOSX game) everything inside those preprocessor directives will be gone.
So, in our case;
// previous code ...
void OnDrawGizmos()
{
#if UNITY_EDITOR
// nope var current = this.transform;
// nope for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
// nope {
// nope // ...code...
// nope }
// nope }
#endif
// rest of the code ...
private void LikeAnotherMethod()
{
....
}
which is the same as;
// previous code ...
void OnDrawGizmos()
{
// rest of the code ...
private void LikeAnotherMethod()
{
....
}
So in the last block of code is easier to see that before the //rest of the code a { is missing. This is the cause of the problem.
VisualStudio (or other IDEs will not complain in the meanwhile because inside UnityEditor world everything is ok, but once you are building the app it will fail.)
A possible fix will be to move the #endif preprocessor directive one line up:
// previous code ...
void OnDrawGizmos()
{
#if UNITY_EDITOR
var current = this.transform;
for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
{
// ...code...
}
#endif
}
// rest of the code ...
private void LikeAnotherMethod()
{
....
}

Array inaccessible only at certain times

I am currently building a parallax background effect in Unity and starting with some starter code that I'm trying to work though. The code works for the most part, with some small issues I'm slowly getting through.
I have been testing out various stats of public vs. private, etc. but can't seem to work out exactly why and where the issue I'm facing is occurring.
When I run the same script and it calls Update() every frame, I would expect to have the same size "poolObjects" length. However, when I call it with a starting pool size of 10, I get 10, then 2, then 0, then 10, 2, 0, etc.
I am truncating it but posting what I think to be relevant here. Hope you can help me see what is likely obvious!
I do see "In GetPool Object" but because the length is never > 0, I never see within the For Loop, which is essential. I can't figure out why the poolObjects length would be showing up as 0.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Parallaxer : MonoBehaviour {
class PoolObject {
public Transform transform;
public bool inUse;
public PoolObject(Transform t) { transform = t; }
public void Use() { inUse = true; }
public void Dispose() { inUse = false; }
}
...
public int poolSize;
public float shiftSpeed;
public float spawnRate;
...
float spawnTimer;
PoolObject[] poolObjects;
float targetAspect;
GameManager game;
void Awake() {
Configure();
}
void Start() {
game = GameManager.Instance;
}
...
void Update() {
Debug.Log(poolObjects.Length + "Len here of pool objects");
if (game.GameOver) return;
Shift();
spawnTimer += Time.deltaTime;
if (spawnTimer > spawnRate) {
Spawn();
spawnTimer = 0;
}
}
void Configure() {
//spawning pool objects
targetAspect = targetAspectRatio.x / targetAspectRatio.y;
// targetAspect = Camera.main.aspect;
// Debug.Log(targetAspectRatio.x +" " + targetAspectRatio.y);
poolObjects = new PoolObject[poolSize];
for (int i = 0; i < poolObjects.Length; i++) {
GameObject go = Instantiate(Prefab) as GameObject;
Transform t = go.transform;
t.SetParent(transform);
t.position = Vector3.one * 1000;
poolObjects[i] = new PoolObject(t);
}
if (spawnImmediate) {
SpawnImmediate();
}
}
void Spawn() {
//moving pool objects into place
Transform t = GetPoolObject();
Debug.Log("In to Spawn" + t);
if (t == null) return;
Vector3 pos = Vector3.zero;
pos.y = Random.Range(ySpawnRange.minY, ySpawnRange.maxY);
pos.x = (defaultSpawnPos.x * Camera.main.aspect) / targetAspect;
// Debug.Log("Spwaning");
// Debug.Log(Camera.main.aspect);
// Debug.Log(immediateSpawnPos.x + " " + immediateSpawnPos.y + " " + targetAspect);
t.position = pos;
// Debug.Log(pos);
}
void SpawnImmediate() {
Transform t = GetPoolObject();
if (t==null) return;
Vector3 pos = Vector3.zero;
pos.y = Random.Range(ySpawnRange.minY, ySpawnRange.maxY);
pos.x = (immediateSpawnPos.x * Camera.main.aspect) / targetAspect;
t.position = pos;
Spawn();
}
void Shift() {
//loop through pool objects
//moving them
//discarding them as they go off screen
Debug.Log(poolObjects.Length + "Finding Length");
for (int i = 0; i < poolObjects.Length; i++) {
poolObjects[i].transform.position += -Vector3.right * shiftSpeed * Time.deltaTime;
Debug.Log(poolObjects[i].transform.position);
CheckDisposeObject(poolObjects[i]);
}
}
void CheckDisposeObject(PoolObject poolObject) {
//place objects off screen
if (poolObject.transform.position.x < (-defaultSpawnPos.x * Camera.main.aspect) / targetAspect) {
poolObject.Dispose();
poolObject.transform.position = Vector3.one * 1000;
}
}
Transform GetPoolObject() {
//retrieving first available pool object
Debug.Log("In GetPool Object" + poolObjects.Length);
for (int i = 0; i < poolObjects.Length; i++) {
Debug.Log("This is not showing up "+ poolObjects[i].inUse);
if (!poolObjects[i].inUse) {
poolObjects[i].Use();
return poolObjects[i].transform;
}
}
return null;
}
}

Issue with invokerepeating function in unity

OK I have two scripts the first one is using invokerepeating to spawn obstacles at a given rate. The second script increases the speed of the obstacles every 20 seconds. My issue is that once the speed increases the gap between the obstacles increases which leads to very big gaps between each one. Any ideas on how to fix this?
using UnityEngine;
using System.Collections;
public class Generate : MonoBehaviour
{
public Vector3 startPosition;
public GameObject object1;
public GameObject object2;
public GameObject object3;
public int random;
int score = 0;
public int count = 0;
private float timeLeft = 20.0f;
private int num1 =3;
private int num2 =3;
// Use this for initialization
void Start()
{
startPosition = new Vector3(5, 0, 0);
random = Random.Range(1, 4);
InvokeRepeating("CreateObstacle", num1, num2);
}
// Update is called once per frame
/*void OnGUI ()
{
GUI.color = Color.black;
GUILayout.Label(" Score: " + score.ToString());
}*/
void Update(){
fast ();
}
void CreateObstacle()
{
if (random == 1) {
GameObject go = Instantiate(object1, startPosition, Quaternion.identity) as GameObject;
go.transform.parent = GameObject.Find("4 - Obstacles").transform;
random = Random.Range(1, 4);
//Destroy(gameObject, 10);
}
else if (random == 2) {
GameObject go = Instantiate(object2, startPosition, Quaternion.identity) as GameObject;
go.transform.parent = GameObject.Find("4 - Obstacles").transform;
random = Random.Range(1, 4);
//Destroy(gameObject, 10);
}
else if(random == 3) {
GameObject go = Instantiate(object3, startPosition, Quaternion.identity) as GameObject;
go.transform.parent = GameObject.Find("4 - Obstacles").transform;
random = Random.Range(1, 4);
//Destroy(gameObject, 10);
}
}
void fast(){
//Timer
timeLeft -= Time .deltaTime;
if (timeLeft <= 0.0f) {
count ++;
timeLeft += 20.0f;
num1 += 1;
num2 += 1;
}
if (count == 1) {
num1 += 1;
num2 += 1;
count ++;
}
else if (count == 3) {
num1 += 1;
num2 += 1;
count ++;
}
}
void OnGUI () {
// Make a background box
GUI.Box (new Rect (10, 10, 100, 90), "Number" + num1);
}
}
second script
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
/// <summary>
/// Parallax scrolling script that should be assigned to a layer
/// </summary>
public class Scrolling : MonoBehaviour
{
public int count = 0;
private float timeLeft = 20.0f;
/// <summary>
/// Scrolling speed
/// </summary>
private Vector2 speed = new Vector2(2, 2);
/// <summary>
/// Moving direction
/// </summary>
public Vector2 direction = new Vector2(-1, 0);
/// <summary>
/// Movement should be applied to camera
/// </summary>
public bool isLinkedToCamera = false;
/// <summary>
/// 1 - Background is infinite
/// </summary>
public bool isLooping = false;
/// <summary>
/// 2 - List of children with a renderer.
/// </summary>
private List<Transform> backgroundPart;
// 3 - Get all the children
void Start()
{
// For infinite background only
if (isLooping)
{
// Get all the children of the layer with a renderer
backgroundPart = new List<Transform>();
for (int i = 0; i < transform.childCount; i++)
{
Transform child = transform.GetChild(i);
// Add only the visible children
if (child.renderer != null)
{
backgroundPart.Add(child);
}
}
// Sort by position.
// Note: Get the children from left to right.
// We would need to add a few conditions to handle
// all the possible scrolling directions.
backgroundPart = backgroundPart.OrderBy(
t => t.position.x
).ToList();
}
}
void Update()
{
//InvokeRepeating("fast", 1, 1);
fast();
// Movement
Vector3 movement = new Vector3(
speed.x * direction.x,
speed.y * direction.y,
0);
movement *= Time.deltaTime;
transform.Translate(movement);
// Move the camera
if (isLinkedToCamera)
{
Camera.main.transform.Translate(movement);
}
// 4 - Loop
if (isLooping)
{
// Get the first object.
// The list is ordered from left (x position) to right.
Transform firstChild = backgroundPart.FirstOrDefault();
if (firstChild != null)
{
// Check if the child is already (partly) before the camera.
// We test the position first because the IsVisibleFrom
// method is a bit heavier to execute.
if (firstChild.position.x < Camera.main.transform.position.x)
{
// If the child is already on the left of the camera,
// we test if it's completely outside and needs to be
// recycled.
if (firstChild.renderer.IsVisibleFrom(Camera.main) == false)
{
// Get the last child position.
Transform lastChild = backgroundPart.LastOrDefault();
Vector3 lastPosition = lastChild.transform.position;
Vector3 lastSize = (lastChild.renderer.bounds.max - lastChild.renderer.bounds.min);
// Set the position of the recyled one to be AFTER
// the last child.
// Note: Only work for horizontal scrolling currently.
firstChild.position = new Vector3(lastPosition.x + lastSize.x, firstChild.position.y, firstChild.position.z);
// Set the recycled child to the last position
// of the backgroundPart list.
backgroundPart.Remove(firstChild);
backgroundPart.Add(firstChild);
}
}
}
}
}
void fast(){
//Timer
timeLeft -= Time .deltaTime;
if (timeLeft <= 0.0f) {
count ++;
timeLeft += 20.0f;
speed.x += 0.4f;
speed.y += 0.4f;
}
if (count == 1) {
speed.x += 0.4f;
speed.y += 0.4f;
count ++;
}
else if (count == 3) {
speed.x += 0.4f;
speed.y += 0.4f;
count ++;
}
/* else if (count == 5) {
speed.x ++;
speed.y ++;
count ++;
}*/
else if (count == 5) {
speed.x += 5;
speed.y += 5;
count ++;
}
}
void OnGUI ()
{
GUI.color = Color.black;
GUILayout.Label(" Speed: " + speed.ToString() + " Count: " + count.ToString ());
GUILayout.Label(" Time: " + timeLeft.ToString());
}
}
You will also have to reduce the time with which the obstacles are generating (which you are trying in your fast() method but it will not work). You are updating your num1 and num2 values but these values are never assigned to the InvokeRepeating.
After updating your num1 and num2 also cancel the previous invoke and create a new invoke (I believe this time you will only need num2). Add these two lines at the end of your fast() method.
CancelInvoke("CreateObstacle");
InvokeRepeating("CreateObstacle", num2, num2);
First time value in InvokeRepeating defines how long to wait before calling the method for the first. Second time value defines the duration after which method calls will be repeated. (In short first value is used only for first time and second value is used for repeated method calls).

Kinect causing framerate limitation in Unity3D

I'm currently developing a Unity3D project which uses both Oculus Rift and Kinect. However, Kinect is limiting the framerate to 30 fps and the Rift needs 60 fps to achieve a fluent experience. I'm using the official It's definitely not a performance issue.
I'm using this wrapper with the official Kinect SDK.
I've narrowed the cause down to this piece of code bellow. I'm suspecting that the getSkeleton() function is blocking the main thread until it has recieved data from the Kinect. Since the Kinect only runs at 30 fps the rest of the application cannot run faster than that.
public bool pollSkeleton () {
if (!updatedSkeleton)
{
updatedSkeleton = true;
if (kinect.pollSkeleton())
{
newSkeleton = true;
System.Int64 cur = kinect.getSkeleton().liTimeStamp;
System.Int64 diff = cur - ticks;
ticks = cur;
deltaTime = diff / (float)1000;
processSkeleton();
}
}
return newSkeleton;
}
Perhaps I could run a seperate thread, but since I have no experience with multithreaded programming I was wondering if anyone had a more simple solution?
My guess is that a lot of Oculus Rift developers will be using the Kinect+Unity3D combo and thus run into the same limitation as me. Any help will be greatly appreciated!
EDIT:
I created a seperate thread for polling the skeleton Info from the kinect: Here's the complete code for the modified SkeletonWrapper.cs. Hope it will help some of you guys struggling with the same issue.
using UnityEngine;
using System.Collections;
using Kinect;
using System.Threading;
public class SkeletonWrapper : MonoBehaviour {
public DeviceOrEmulator devOrEmu;
private Kinect.KinectInterface kinect;
private bool updatedSkeleton = false;
private bool newSkeleton = false;
[HideInInspector]
public Kinect.NuiSkeletonTrackingState[] players;
[HideInInspector]
public int[] trackedPlayers;
[HideInInspector]
public Vector3[,] bonePos;
[HideInInspector]
public Vector3[,] rawBonePos;
[HideInInspector]
public Vector3[,] boneVel;
[HideInInspector]
public Quaternion[,] boneLocalOrientation;
[HideInInspector]
public Quaternion[,] boneAbsoluteOrientation;
public Kinect.NuiSkeletonPositionTrackingState[,] boneState;
private System.Int64 ticks;
private float deltaTime;
private Matrix4x4 kinectToWorld;
public Matrix4x4 flipMatrix;
private Thread thread = null;
private bool isThreadRunning = false;
// Use this for initialization
void Start () {
kinect = devOrEmu.getKinect();
players = new Kinect.NuiSkeletonTrackingState[Kinect.Constants.NuiSkeletonCount];
trackedPlayers = new int[Kinect.Constants.NuiSkeletonMaxTracked];
trackedPlayers[0] = -1;
trackedPlayers[1] = -1;
bonePos = new Vector3[2,(int)Kinect.NuiSkeletonPositionIndex.Count];
rawBonePos = new Vector3[2,(int)Kinect.NuiSkeletonPositionIndex.Count];
boneVel = new Vector3[2,(int)Kinect.NuiSkeletonPositionIndex.Count];
boneState = new Kinect.NuiSkeletonPositionTrackingState[2,(int)Kinect.NuiSkeletonPositionIndex.Count];
boneLocalOrientation = new Quaternion[2, (int)Kinect.NuiSkeletonPositionIndex.Count];
boneAbsoluteOrientation = new Quaternion[2, (int)Kinect.NuiSkeletonPositionIndex.Count];
//create the transform matrix that converts from kinect-space to world-space
Matrix4x4 trans = new Matrix4x4();
trans.SetTRS( new Vector3(-kinect.getKinectCenter().x,
kinect.getSensorHeight()-kinect.getKinectCenter().y,
-kinect.getKinectCenter().z),
Quaternion.identity, Vector3.one );
Matrix4x4 rot = new Matrix4x4();
Quaternion quat = new Quaternion();
double theta = Mathf.Atan((kinect.getLookAt().y+kinect.getKinectCenter().y-kinect.getSensorHeight()) / (kinect.getLookAt().z + kinect.getKinectCenter().z));
float kinectAngle = (float)(theta * (180 / Mathf.PI));
quat.eulerAngles = new Vector3(-kinectAngle, 0, 0);
rot.SetTRS( Vector3.zero, quat, Vector3.one);
//final transform matrix offsets the rotation of the kinect, then translates to a new center
kinectToWorld = flipMatrix*trans*rot;
thread = new Thread(ThreadUpdate);
thread.Start();
}
void OnDestroy()
{
if (isThreadRunning)
{
isThreadRunning = false;
thread.Abort();
thread = null;
}
}
// Update is called once per frame
void Update () {
}
void LateUpdate () {
updatedSkeleton = false;
newSkeleton = false;
}
private void ThreadUpdate()
{
isThreadRunning = true;
while (isThreadRunning)
{
// This function is capping the FPS to 30.
if (kinect.pollSkeleton())
{
System.Int64 cur = kinect.getSkeleton().liTimeStamp;
System.Int64 diff = cur - ticks;
ticks = cur;
deltaTime = diff / (float)1000;
processSkeleton();
newSkeleton = true;
}
}
}
/// <summary>
/// First call per frame checks if there is a new skeleton frame and updates,
/// returns true if there is new data
/// Subsequent calls do nothing have the same return as the first call.
/// </summary>
/// <returns>
/// A <see cref="System.Boolean"/>
/// </returns>
public bool pollSkeleton () {
//if (!updatedSkeleton)
//{
// updatedSkeleton = true;
// //this function is capping the FPS to 30.
// //It might be blocking the main thread because it waits for the kinects skeleton input which only runs 30 fps
// //possible solution: run function in seperate thread
// if (kinect.pollSkeleton())
// {
// newSkeleton = true;
// System.Int64 cur = kinect.getSkeleton().liTimeStamp;
// System.Int64 diff = cur - ticks;
// ticks = cur;
// deltaTime = diff / (float)1000;
// processSkeleton();
// }
//}
return newSkeleton;
}
private void processSkeleton () {
int[] tracked = new int[Kinect.Constants.NuiSkeletonMaxTracked];
tracked[0] = -1;
tracked[1] = -1;
int trackedCount = 0;
//update players
for (int ii = 0; ii < Kinect.Constants.NuiSkeletonCount; ii++)
{
players[ii] = kinect.getSkeleton().SkeletonData[ii].eTrackingState;
if (players[ii] == Kinect.NuiSkeletonTrackingState.SkeletonTracked)
{
tracked[trackedCount] = ii;
trackedCount++;
}
}
//this should really use trackingID instead of index, but for now this is fine
switch (trackedCount)
{
case 0:
trackedPlayers[0] = -1;
trackedPlayers[1] = -1;
break;
case 1:
//last frame there were no players: assign new player to p1
if (trackedPlayers[0] < 0 && trackedPlayers[1] < 0)
trackedPlayers[0] = tracked[0];
//last frame there was one player, keep that player in the same spot
else if (trackedPlayers[0] < 0)
trackedPlayers[1] = tracked[0];
else if (trackedPlayers[1] < 0)
trackedPlayers[0] = tracked[0];
//there were two players, keep the one with the same index (if possible)
else
{
if (tracked[0] == trackedPlayers[0])
trackedPlayers[1] = -1;
else if (tracked[0] == trackedPlayers[1])
trackedPlayers[0] = -1;
else
{
trackedPlayers[0] = tracked[0];
trackedPlayers[1] = -1;
}
}
break;
case 2:
//last frame there were no players: assign new players to p1 and p2
if (trackedPlayers[0] < 0 && trackedPlayers[1] < 0)
{
trackedPlayers[0] = tracked[0];
trackedPlayers[1] = tracked[1];
}
//last frame there was one player, keep that player in the same spot
else if (trackedPlayers[0] < 0)
{
if (trackedPlayers[1] == tracked[0])
trackedPlayers[0] = tracked[1];
else{
trackedPlayers[0] = tracked[0];
trackedPlayers[1] = tracked[1];
}
}
else if (trackedPlayers[1] < 0)
{
if (trackedPlayers[0] == tracked[1])
trackedPlayers[1] = tracked[0];
else{
trackedPlayers[0] = tracked[0];
trackedPlayers[1] = tracked[1];
}
}
//there were two players, keep the one with the same index (if possible)
else
{
if (trackedPlayers[0] == tracked[1] || trackedPlayers[1] == tracked[0])
{
trackedPlayers[0] = tracked[1];
trackedPlayers[1] = tracked[0];
}
else
{
trackedPlayers[0] = tracked[0];
trackedPlayers[1] = tracked[1];
}
}
break;
}
//update the bone positions, velocities, and tracking states)
for (int player = 0; player < 2; player++)
{
//print(player + ", " +trackedPlayers[player]);
if (trackedPlayers[player] >= 0)
{
for (int bone = 0; bone < (int)Kinect.NuiSkeletonPositionIndex.Count; bone++)
{
Vector3 oldpos = bonePos[player,bone];
bonePos[player,bone] = kinectToWorld.MultiplyPoint3x4(kinect.getSkeleton().SkeletonData[trackedPlayers[player]].SkeletonPositions[bone]);
//bonePos[player,bone] = kinectToWorld.MultiplyPoint3x4(bonePos[player, bone]);
rawBonePos[player, bone] = kinect.getSkeleton().SkeletonData[trackedPlayers[player]].SkeletonPositions[bone];
Kinect.NuiSkeletonBoneOrientation[] or = kinect.getBoneOrientations(kinect.getSkeleton().SkeletonData[trackedPlayers[player]]);
boneLocalOrientation[player,bone] = or[bone].hierarchicalRotation.rotationQuaternion.GetQuaternion();
boneAbsoluteOrientation[player,bone] = or[bone].absoluteRotation.rotationQuaternion.GetQuaternion();
//print("index " + bone + ", start" + (int)or[bone].startJoint + ", end" + (int)or[bone].endJoint);
boneVel[player,bone] = (bonePos[player,bone] - oldpos) / deltaTime;
boneState[player,bone] = kinect.getSkeleton().SkeletonData[trackedPlayers[player]].eSkeletonPositionTrackingState[bone];
//print(kinect.getSkeleton().SkeletonData[player].Position.z);
}
}
}
}
}
I don't know much about how the Kinect SDK works. It's possible that it's already managing a background thread that is doing the skeletal tracking, and the pollSkeleton method simply blocks until the next frame is available.
This seems like a reasonable assumption, since the SDK supports both polling and event based notifications, implying that if you don't poll, something else will trigger the fetch of the next frame and send you the event.
If this is the case, then you can solve your problem by simply scanning the timestamp on the skeleton data that's available from the thread...
System.Int64 lastSkeletonTime = 0;
public bool pollSkeleton ()
{
if (kinect.getSkeleton().liTimeStamp > lastSkeletonTime) {
updatedSkeleton = true;
newSkeleton = true;
System.Int64 cur = kinect.getSkeleton().liTimeStamp;
System.Int64 diff = cur - lastSkeletonTime;
deltaTime = diff / (float)1000;
lastSkeletonTime = cur;
processSkeleton();
}
return newSkeleton;
}
If this doesn't work, then most likely you will need to launch a background thread, or switch to handling the events.

Categories