I would like to create a timer interval between the execution of a state in an FSM.
What I have at the moment is pretty basic as I'm still quite new to programming. It'd be great if you could keep any possible solutions to around a basic level.
public override void Execute()
{
//Logic for Idle state
if (dirRight)
oFSM.transform.Translate(Vector2.right * speed * Time.deltaTime);
else
oFSM.transform.Translate(-Vector2.right * speed * Time.deltaTime);
if (oFSM.transform.position.x >= 2.0f)
dirRight = false;
else if (oFSM.transform.position.x <= -2.0f)
dirRight = true;
//play animation
//Transition out of Idle state
//SUBJECT TO CHANGE
float timer = 0f;
timer += Time.time;
if (timer >= 3f)
{
int rng = Random.Range(0, 5);
if (rng >= 0 && rng <= 1)
{
timer = 0;
oFSM.ChangeStateTo(FSM.States.AtkPatt1);
}
else if (rng >= 2 && rng <= 3)
{
timer = 0;
oFSM.ChangeStateTo(FSM.States.AtkPatt2);
}
else if (rng >= 4 && rng <= 5)
{
timer = 0;
oFSM.ChangeStateTo(FSM.States.AtkPatt3);
}
}
}
You need to use Coroutines, and use the method WaitForSeconds.
Then you can do something like this:
private float timeToWait = 3f;
private bool keepExecuting = false;
private Coroutine executeCR;
public void CallerMethod()
{
// If the Coroutine is != null, we will stop it.
if(executeCR != null)
{
StopCoroutine(executeCR);
}
// Start Coroutine execution:
executeCR = StartCoroutine( ExecuteCR() );
}
public void StoperMethod()
{
keepExecuting = false;
}
private IEnumerator ExecuteCR()
{
keepExecuting = true;
while (keepExecuting)
{
// do something
yield return new WaitForSeconds(timeToWait);
int rng = UnityEngine.Random.Range(0, 5);
if (rng >= 0 && rng <= 1)
{
oFSM.ChangeStateTo(FSM.States.AtkPatt1);
}
else if (rng >= 2 && rng <= 3)
{
oFSM.ChangeStateTo(FSM.States.AtkPatt2);
}
else if (rng >= 4 && rng <= 5)
{
oFSM.ChangeStateTo(FSM.States.AtkPatt3);
}
}
// All Coroutines should "return" (they use "yield") something
yield return null;
}
Related
I've been working on a project for the GMTK 2022 Game Jam recently, and I ran into a very strange problem. I have a dash that starts when you are moving and press space. It moves you in the direction of your velocity, then for a short time lets you move very quickly. It works perfectly fine in all cases, unless the direction you are moving is up and to the left, in which case, the if statement strangely won't trigger. I'm sure this is something idiotic, but I've been troubleshooting it for the last hour and it's been driving me insane.
// Update is called once per frame
void Update()
{
playerInputh = 0;
playerInputv = 0;
if (Input.GetKey("right"))
{
playerInputh = 1;
}
if (Input.GetKey("left"))
{
playerInputh = -1;
}
if (Input.GetKey("right") && Input.GetKey("left"))
{
playerInputh = 0;
}
if (Input.GetKey("up"))
{
playerInputv = 1;
}
if (Input.GetKey("down"))
{
playerInputv = -1;
}
if (Input.GetKey("up") && Input.GetKey("down"))
{
playerInputv = 0;
}
Vector2 screenPosition = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
Vector2 mouseWorldPosition = Camera.main.ScreenToWorldPoint(screenPosition);
//This is the dash that isn't working:
if ((Input.GetKeyDown(/*"right shift"*/"space")) && (playerInputh != 0 || playerInputv != 0))
{
Debug.Log("Dash");
//Vector2 transform2dposition = new Vector2(transform.position.x, transform.position.y);
m_Rigidbody.AddForce((m_Rigidbody.velocity) * 500f);
wJumpTimer = airControlAfterJump;
speed = maxSpeed*3.5f;
StartCoroutine(Roll());
}
}
void FixedUpdate()
{
//no moving while jumping!!!
if (wJumpTimer > 0)
{
wJumpTimer -= 1;
}
else
{
wJumpTimer = 0;
}
//move
if (playerInputh != 0 && playerInputv != 0) //make diagonals no super sayan
{
playerInputh *= moveLimiter;
playerInputv *= moveLimiter;
one_h = playerInputh;//futureproof
one_v = playerInputv;
}
if ((playerInputh != 0 || playerInputv != 0) && speed < maxSpeed) //are we hitting the move buttons??
{
speed += acceleration;//accelerate
one_h = playerInputh;//futureproof
one_v = playerInputv;
}
else
{
if (speed > 0f) //are we getting off the ride
{
speed -= deceleration; //decelerate
}
else
{
speed = 0f; //no funny buisness
}
}
m_Rigidbody.velocity = new Vector2(one_h * speed, one_v * speed); //actually move
}
void SetFace(int diceNumb)
{
rndr.sprite = sprites[diceNumb];
}
IEnumerator Roll()
{
Random diceNumb = new Random();
rndr.sprite = sprites[diceNumb.Next(0,5)];
yield return new WaitForSeconds(0.125f);
rndr.sprite = sprites[diceNumb.Next(0, 5)];
yield return new WaitForSeconds(0.125f);
rndr.sprite = sprites[diceNumb.Next(0, 5)];
yield return new WaitForSeconds(0.125f);
rndr.sprite = sprites[diceNumb.Next(0, 5)];
yield return new WaitForSeconds(0.125f);
var newValue = diceNumb.Next(0, 5);
FaceValue = newValue + 1;
rndr.sprite = sprites[newValue];
}
How are your inputs setup? I am suspecting you have one key bound to multiple actions, like one key is set up as primary for an action and alternate for another action.
Personally I'd also stop using the assignment operators and increment instead. Instead of
playerInputh = 0;
if (Input.GetKey("right"))
{
playerInputh = 1;
}
if (Input.GetKey("left"))
{
playerInputh = -1;
}
if (Input.GetKey("right") && Input.GetKey("left"))
{
playerInputh = 0;
}
you can do
playerInputv = 0;
if (Input.GetKey("right"))
{
playerInputh += 1;
}
if (Input.GetKey("left"))
{
playerInputh += -1;
}
Net result is the same here - if you push both keys the result sums to zero, but the code is easier to read (IMO).
When you check things for key bindings also check alternates for space, because that's another one of the triggers you need to dash.
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class WaypointsFollower : MonoBehaviour
{
public float speed;
public Waypoints waypoints;
public bool go;
public bool goForward;
private int index = 0;
private int counter = 0;
private int c = 0;
private List<GameObject> curvedLinePoints = new List<GameObject>();
public int numofposbetweenpoints;
private bool getonce;
private void Start()
{
waypoints = GameObject.Find("Waypoints").GetComponent<Waypoints>();
curvedLinePoints = GameObject.FindGameObjectsWithTag("Curved Line Point").ToList();
}
private void Update()
{
if (getonce == false)
{
numofposbetweenpoints = curvedLinePoints.Count;
getonce = true;
}
if (go == true && waypoints.lineRendererPositions.Count > 0)
{
Move();
}
}
private void Move()
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
// error exception out of bound on line 55 to check !!!!!
newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == waypoints.lineRendererPositions[index]) // Vector3 comparison is approximate so this is ok
{
// when you hit a waypoint:
if (goForward)
{
bool atLastOne = index >= waypoints.lineRendererPositions.Count - 1;
if (!atLastOne)
{
index++;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index--; goForward = false; }
}
else
{ // going backwards:
bool atFirstOne = index <= 0;
if (!atFirstOne)
{
index--;
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else { index++; goForward = true; }
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
}
Now it's moving from the first index to the last one then when reaching the last index it's moving from the last index to the first one and so on nonstop.
but I want that if goForward is true at the start to go to the first index to the last then from last to the first like it is now but if goForward will be false at the start then start from the last index move in reverse to the first index and then from the first index to the last same as the first state but opposite.
and if I change the goForward at run time then change the transform moving direction to the last/before index it was and keep moving on that direction. and if I change the flag at a run time again change direction again so I can change the direction/s in real time.
How can I change the code that if the goForward state change in runtime or at start move the transform forward or backward?
Consider using the mathematical %(modulo) operator. This operator performs 'clock math'. Think of it like a hand on a clock, when it reaches 12 on the clock the hand 'wraps around' the the beginning and starts as 1. Take the number 4 for example. If we have a loop like
for(int i = 0; i < 8; i++)
{
Console.WriteLine($"{i % 4}");
}
It would produce 0, 1, 2, 3, 0, 1, 2, 3. This in-effect gives you a looping index around the number 4.
If we look at this in the context of an array(or list) we can loop through an array, forwards AND backwards without ever checking to see if we are at the first or last position of the array(or list).
This effect is super helpful for traveling between arbitrary waypoints and avoiding that pesky IndexOutOfBoundsException.
You could implement something like this to achieve the effect you want:
private void Move()
{
Vector3 newPos = transform.position;
float distanceToTravel = speed * Time.deltaTime;
bool stillTraveling = true;
while (stillTraveling)
{
Vector3 oldPos = newPos;
// error exception out of bound on line 55 to check !!!!!
newPos = Vector3.MoveTowards(oldPos, waypoints.lineRendererPositions[index], distanceToTravel);
distanceToTravel -= Vector3.Distance(newPos, oldPos);
if (newPos == waypoints.lineRendererPositions[index]) // Vector3 comparison is approximate so this is ok
{
// determine if we should go forward or backward through the list
int direction = goForward ? 1 : -1;
// loop around the index, this automatically wraps to 0 if we are going forward and get to the end of the list,
// or to the end if we are going backwards and hit the end of the list
index = (index + direction) % waypoints.lineRendererPositions.Count;
// increment the amounnt of points we passed
counter++;
if (counter == numofposbetweenpoints)
{
c++;
counter = 0;
}
// reset C if we reached the end
if (c == curvedLinePoints.Count - 1)
{
c = 0;
}
}
else
{
stillTraveling = false;
}
}
transform.position = newPos;
}
So I made this code in an effort to start making a script that generates bush objects in my scene randomly, however when in runs it only spawns the first bush. Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BushSpawner : MonoBehaviour
{
public GameObject bush;
private float x = 0f;
private float y = -.47f;
private float z = 0f;
private int bushCount = 0;
private Vector3 origPos;
private bool xPlus = false;
private bool xMinus = false;
private bool zPlus = false;
private bool zMinus = false;
// Use this for initialization
void Start()
{
SpawnBushes();
}
// Update is called once per frame
void Update()
{
}
void SpawnBushes()
{
Vector3 startPos = new Vector3(x, y, z);
Instantiate(bush, startPos, Quaternion.identity);
bushCount += 1;
while (bushCount < 100)
{
Vector3 checkPos = new Vector3(x, y, z);
Collider[] intersecting = Physics.OverlapSphere(checkPos, 1f);
if (intersecting.Length == 0)
{
//code to run if nothing is intersecting as the length is 0
Instantiate(bush, checkPos, Quaternion.identity);
bushCount += 1;
}
else
{
//code to run if something is intersecting it
RollPos();
}
}
}
void RollPos()
{
if (xPlus == true
&& xMinus == true
&& zPlus == true
&& zMinus == true)
{
int newRoll = Random.Range(1, 4);
if (newRoll == 1)
{
x += 10f;
}
else if (newRoll == 2)
{
x -= 10f;
}
else if (newRoll == 3)
{
z += 10f;
}
else if (newRoll == 4)
{
z -= 10f;
}
xPlus = false;
xMinus = false;
zPlus = false;
zMinus = false;
}
else
{
int roll = Random.Range(1, 4);
if (roll == 1)
{
if (xPlus == false)
{
x += 2f;
xPlus = true;
}
else
{
RollPos();
}
}
if (roll == 2)
{
if (xMinus == false)
{
x -= 2f;
xMinus = true;
}
else
{
RollPos();
}
}
if (roll == 3)
{
if (zPlus == false)
{
z += 2f;
zPlus = true;
}
else
{
RollPos();
}
}
if (roll == 4)
{
if (zMinus == false)
{
z -= 2f;
zMinus = true;
}
else
{
RollPos();
}
}
}
}
}
I tried putting SpawnBushes in Update to run while a bool is true then make it false when SpawnBushes is done, but that creates the first bush, then 99 other bushes in one random position next to it.
If someone can point me in the right direction or tell me I'm completely off-base I would appreciate it immensely!
Ron Beyer pointed out that I didn't have a large enough range in my Random.Range in RollPos(). Thanks again Ron!
I've written a script that makes the enemy appear behind the player, with a 1 in 5 chance every 3 minutes, I've changed the 1 in 5 chance to a 1 in 1 chance for testing purposes, but I'am unsure if it works.
I know how to place the enemy behind the player but not with a chance of 1 on 5.
I've tried this with a random number between 1 and 5. And that if the random number equals 1 he has to spawn the enemy and else not.
This is the code:
using UnityEngine;
using System.Collections;
public class MainEnemy : MonoBehaviour
{
public GameObject Main;
public GameObject Holder;
public Transform player;
public Transform FPSController;
bool wantPosition;
bool appear;
float timer;
Vector3 temp;
// Use this for initialization
void Start()
{
wantPosition = true;
appear = false;
temp = new Vector3(0, 0, 0);
timer = 20;// 180;
}
// Update is called once per frame
void Update()
{
Appear();
}
Vector3 GetPosition()
{
Debug.Log("Hij doet het getposition");
float px = player.transform.position.x;
float pz = player.transform.position.z;
//
float angle2 = Mathf.Cos(Camera.main.transform.eulerAngles.y) + 180;
//
float distance = 20;
float distancex = Mathf.Cos(angle2 + 180) * distance;
float distancez = Mathf.Sin(angle2 + 180) * distance;
// Tell distanceen bij coordinaten op
temp = new Vector3(distancex, -3, distancez);
return temp;
}
void SetFalse()
{
if (timer < 1)
{
timer = 10;// 180; // na 3 minuten weer kijken of hij hem laat zien
}
Main.SetActive(false);
}
void Position()
{
if (wantPosition)
{
temp = GetPosition();
Holder.transform.position = player.position + temp;
Main.SetActive(true);
if (timer < 0)
{
timer = 10; // kort zichtbaar
}
wantPosition = false;
}
}
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1, 1);
if (rand == 1)
{
appear = true;
}
else
{
appear = false;
}
return appear;
}
void Appear()
{
bool appear = false;
if (timer <= 0)
{
appear = Appeared();
}
else
{
timer -= Time.deltaTime;
if (timer < 10)
{
Debug.Log(timer);
}
}
if (appear == true)
{
Position();
}
else
{
SetFalse();
}
}
}
Firstly be aware that Random.Range returns a number that is greater than or equal to min, but less than (but not equal to) max. If the special case where min == max, then that value will be returned.
Secondly your Appeared function is a bit verbose. Assuming we set it back to a 1 in 5 chance, you'd have this:
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1, 6);
if (rand == 1)
{
appear = true;
}
else
{
appear = false;
}
return appear;
}
Firstly let me point out that saying:
if(x)
y = true
else
y = false
Where x is a Boolean condition, is exactly the same as saying
y = x
So perhaps you'd change it to:
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1, 6);
appear = rand == 1;
return appear;
}
Now look, why bother setting appear to false at the start? That value never gets used. Perhaps this:
bool Appeared()
{
int rand = Random.Range(1, 6);
bool appear = rand == 1;
return appear;
}
Hmm, now we're just assigning a variable and then returning it on the next line. OK, maybe this:
bool Appeared()
{
int rand = Random.Range(1, 6);
return rand == 1;
}
Right, yeah. This looks familiar. Now, again, we're almost just assigning a variable and then returning it on the next line. Do we really need that rand variable now? Probably not. How about this then:
bool Appeared()
{
return Random.Range(1, 6) == 1;
}
Much better.
An easy and performant way to get a 1/5 chance in Unity3D is
if(Random.value < 1f/5f)
//do something
Random.value is returning a float 0 <= value <= 1
**EDIT Updated for UnityEngine
Change your bool Appeared method to:
bool Appeared()
{
bool appear = false;
int rand = Random.Range(1,6)
if (rand == 1)
{
appear = true;
} // else not needed
return appear;
}
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.