Jump to content


Photo

[unity3d] The handy script snippets thread

unity unity3d c# script

  • Please log in to reply
1 reply to this topic

#1 duke_Qa

duke_Qa

    I've had this avatar since... 2003?

  • Network Staff
  • 3,837 posts
  • Location:Norway
  • Division:Revora
  • Job:Artist

Posted 08 July 2012 - 10:46 PM

The yield clock is basically a class that allows you to run heavy processing operations without inflicting hurt upon your FPS. It uses Deltatime and the time the program has been running to tell whatever method is calling it if its time to yield.

it also is based upon using StartCoroutine and yield functions. There's also code showing how to stop started coroutines and the likes in there.
save as a .cs file and apply the guiDebug to a gameobject of sorts. it also creates a spinning cube for reference, but whatever you want to test it out with should work.

using UnityEngine;
using System.Collections;

public class GuiDebug : MonoBehaviour {


float startTime =0;
FrameClock clock;
bool isInit =false;


void OnGUI ()
{

GUI.Box(new Rect(10,10,200,90), "Loader Menu");


if(GUI.Button(new Rect(20,40,150,20), "test withoutClock")) {
if(!isInit) init();
clock.isOn = false;
TestFunc();
}


if(GUI.Button(new Rect(20,70,150,20), "WithClock")) {
if(!isInit) init();
clock.isOn = true;
TestFunc();
}
}
void Awake()
{
GameObject testCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
testCube.renderer.material.color= Color.red;
testCube.AddComponent<RotateObj>();
}


void init()
{
GameObject go = transform.gameObject;
clock = go.AddComponent<FrameClock>();
isInit = true;
}


void TestFunc()
{

	 print("Starting " + Time.time);
startTime = (float)Time.time;
	
if (isShortLoopRunning == true) StopCoroutine("shortLoop");
if (isLongLoopRunning == true) StopCoroutine("isLongLoopRunning");
StartCoroutine("LongLoop",30);
StartCoroutine("shortLoop",300);	
}


bool isLongLoopRunning =false; //my way of figuring out if a coroutine is running, in case I want to reset it

IEnumerator LongLoop(int iterations)
{
isLongLoopRunning=true;
int mainI=0;
float sumFloat=0;

while (mainI<iterations) {

startTime = (float)Time.realtimeSinceStartup;

int i=0;
while (i < 1000000){

sumFloat += Mathf.PerlinNoise(i,0);
if (clock.outOfTime) yield return 0;

i++;
}
if(clock.isOn == false) yield return 0; //remove this and the loop will just stop the game until its done if you have turned off the clock
else if (clock.outOfTime) yield return 0;

float endTime = (float)Time.realtimeSinceStartup;
float timeElapsed = (endTime-startTime);
print("____perlinNoiseLong: "+(sumFloat/1000000)+"time taken: "+timeElapsed+" #"+mainI);
her
mainI++;
}

isLongLoopRunning=false;
}



bool isShortLoopRunning = false;

IEnumerator shortLoop(int iterations)
{
print("start of shortLoop\n");
isShortLoopRunning = true;
//int mainI = 0;
float sumFloat = 0;
int totalRepetitions = 0;

for(int mainI=0; mainI < iterations; mainI ++)
{

int i = 0;
while(i<10000){

sumFloat += Mathf.PerlinNoise(i,0);
totalRepetitions++;
i++;
}
if(clock.isOn == false) yield return 0;
else if ( clock.outOfTime)yield return 0;


//if(clock.isOn == false) yield return 0;

mainI++;
}
print("_____________perlinNoiseShort: "+(sumFloat/totalRepetitions));
isShortLoopRunning=false;

}

}









public class RotateObj : MonoBehaviour
{

void Update () {
transform.Rotate(new Vector3(0,180*Time.deltaTime,1*Time.deltaTime));
}
}




public class FrameClock : MonoBehaviour
{

//this class is an attempt to make a system that tells you if you got time to do another batch in a loop,
//or if you should do a yield and let the other functions within the system keep a good frame-rate

// graphics in heavier games takes about 30% of each frame, so for now I'm starting with 80% of previous delta


private float currentTime;
private float timeOutTime;
private float _percentage = 0.8f;
private float previousDelta;
private float _minFPS = 0.040f; //in case the previous deltatime was horrible long. set to zero to ignore(not recommended here, long deltatime will domino)
private float _maxFPS = 0.015f; //in case the previous deltatime was horrible short. set to zero to ignore
private float currentDelta;
private bool _outOfTime=true;
public bool isOn=false;

private void Update()
{
reset();
}


public int SetPercentage
{
get{return (int)_percentage * 100;}
set{_percentage = (float)value * 0.01f;}

}

public int minFPS
{
get{return (int)(_minFPS*100);}
set{_minFPS = (float)(1/value);}
}
public int maxFPS
{
get{return (int)(_maxFPS*100);}
set{_maxFPS = (float)(1/value);}
}



public bool outOfTime
{
get{
CheckTime();
return _outOfTime;

}
set{
_outOfTime=value;
}
}

public void reset() //use this function from some monobehaviour Updatefunction
{ currentTime =Time.realtimeSinceStartup;
previousDelta = Time.deltaTime * _percentage;
if (previousDelta > _minFPS) previousDelta = _minFPS;
if (previousDelta < _maxFPS) previousDelta = _maxFPS;
timeOutTime = currentTime + previousDelta;
}




void CheckTime()
{
currentTime =Time.realtimeSinceStartup;
if(currentTime < timeOutTime) _outOfTime = false;
else _outOfTime = true;
if(isOn==false) outOfTime=false;
}

}


Hope someone else can get some use out of this. By the way, you have to be a bit careful about how you write coroutine functions: since they are working on things out-of-sync, if your next line of code assumes that the job is done before its done, things will get pear-shaped.

Edited by duke_Qa, 20 July 2012 - 08:06 AM.

"I give you private information on corporations for free and I'm a villain. Mark Zuckerberg gives your private information to corporations for money and he's 'Man of the Year.'" - Assange


#2 duke_Qa

duke_Qa

    I've had this avatar since... 2003?

  • Network Staff
  • 3,837 posts
  • Location:Norway
  • Division:Revora
  • Job:Artist

Posted 20 July 2012 - 08:08 AM

Figured this might work better as a summary thread for different handy scripts.

Just made a static class that lets me easily calculate the time a function spends before it finishes.
just type:
TimeTakenClass.StartTime("nameOfYourChoice");
//long loop/function in here
TimeTakenClass.TakeTime("nameOfYourChoice");
and it should work anywhere. Dunno how useful it will be for you if you are not making very long loops, but eh, nice to have imo. Also shows how to use a dictionary from system generics, which is a very handy data-storage system.


using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/*
* Class used to calculate the time gone between different points in a function
*
* start a call by typing [TimeTakenClass.StartTime("nameOfYourChoice");] (its a static function,so you don't need to create a class to call it from anywhere. just save it in your project and type the code)
* Then check how long that one has been running by calling
*
* TimeTakenClass.TakeTime("nameOfYourChoice");
*
* or if you don't want to check every time it goes through a loop(a smart thing to do if you have tens of thousands of iterations since debug is sort of slow)
* - call this one instead
* TimeTakenClass.TakeTimeSkip("nameOfYourChoice",128);
*
* */
public static class TimeTakenClass {

static private Dictionary<string,float> timeDictStart = new Dictionary<string, float>();
static private Dictionary<string,int> timeDictI = new Dictionary<string, int>();

public static void StartTime(string name)
{
if(timeDictStart.ContainsKey(name)) timeDictStart.Remove(name);
float tempF=(float)Time.realtimeSinceStartup;
timeDictStart.Add(name, tempF);

	 //Debug.Log("\ntimeStart for "+name+"created: "+tempF);


}
public static void TakeTime(string name)
{
if(!timeDictStart.ContainsKey(name)) {
Debug.LogError("\nerror, "+name+" doesn't exist, adding it because you didn't >__<");
StartTime(name);
}
else
{
float startTime;
timeDictStart.TryGetValue(name,out startTime);
float endTime = (float)Time.realtimeSinceStartup;
		 float timeElapsed = (endTime-startTime);
Debug.Log ("\ntime elapsed for "+name+": "+timeElapsed);
}
StartTime(name);
}

public static void TakeTimeSkip(string name, int counter)
{
int i;
if(!timeDictStart.ContainsKey(name)) StartTime(name);
else
{
timeDictI.TryGetValue(name, out i);

if (i > counter) {

TakeTime(name);
timeDictI.Remove(name);
timeDictI.Add(name,0);

}else StartTime(name);
timeDictI.Remove(name);
timeDictI.Add(name,i++);

}


}
}

Edited by duke_Qa, 20 July 2012 - 08:10 AM.

"I give you private information on corporations for free and I'm a villain. Mark Zuckerberg gives your private information to corporations for money and he's 'Man of the Year.'" - Assange





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users