I used Coroutine in Unity quite a lot in my projects, they are useful because they allow me to delay functions or do things every X seconds.
Now I know how to use them, but I don't really know what is happening in the background and I am wondering their impact on performances. Are coroutine low/fast ?
For exemple, doing things every few seconds could be done in the Update function, but it can also be done in a coroutine with WaitForSeconds or with yield return null. Are they all as efficient as the others ?
I wrote different ways here, which should do the job in theory. But which ones are the best ? If they are all the same, WaitForSeconds seems easier to read and I might prefer it.
Update way
private float shootInterval = 5f;
private float counterDeltaTime = 0f;
private void Update() {
counterDeltaTime += Time.deltaTime;
if (counterDeltaTime >= shootInterval) {
Shoot();
counterDeltaTime = 0;
}
}
Coroutine way
yield return new WaitForSeconds
private void Start() {
StartCoroutine(ShootEvery(5f));
}
private IEnumerator ShootEvery(float seconds) {
yield return new WaitForSeconds(seconds);
Shoot();
StartCoroutine(ShootEvery(seconds));
}
yield return null
private void Start() {
StartCoroutine(ShootEvery(5f));
}
private IEnumerator ShootEvery(float seconds) {
float dt = 0;
while(dt < seconds) {
yield return null;
dt += Time.deltaTime;
}
Shoot();
StartCoroutine(ShootEvery(5f));
}
Thanks for answers
Related
I have been using TMP objects in several instances in my game, but all of a sudden it decides not to work on a certain object.
public class BeforeRoundTimer : MonoBehaviour
{
public TextMeshProUGUI timer;
private Timer oneSecondTimer;
private int time = 5;
public void StartCountdown()
{
Debug.Log("One second timer");
oneSecondTimer = new Timer(1000);
oneSecondTimer.Elapsed += UpdateTime;
oneSecondTimer.Enabled = true;
oneSecondTimer.AutoReset = true;
oneSecondTimer.Start();
}
private void UpdateTime(object source, ElapsedEventArgs e)
{
if(time == 0)
{
oneSecondTimer.Stop();
return;
}
timer.text = $"{time}";
time--;
}
}
I know the text is updating because I put debug statements (I have since removed them) and they fired when UpdateTime() is called. I also viewed the inspector when the game was playing, and the text value would update in front of my eyes. The text only changes when I make some stylistic change to it (i.e. making it bold, changing the font asset, including changing the text itself). I have looked back to my old code and it basically runs the exact same way, but it actually changes in game.
Ok so after taking a break, I decided to find another way to call my method every second. Instead of using a Timer, I decided to use Unity's InvokeRepeating() function.
public class BeforeRoundTimer : MonoBehaviour
{
public TextMeshProUGUI timer;
private int count = 0;
public void StartCountdown()
{
InvokeRepeating(nameof(UpdateTime), 0, 1f);
}
private void UpdateTime()
{
if(count == 5)
{
CancelInvoke("UpdateTime");
return;
}
Debug.Log("Update Time");
timer.text = $"{5 - count}";
count++;
}
}
One thing I noticed when trying to use the Timer in a different way is that it was only updating the text value every other second. It ran 10 times (I put a Debug.Log() in UpdateTime()) but only changed the value every other time while not actually updating the TMP. You could replace nameof(UpdateTime) with "UpdateTime", but Visual Studio recommended that I use the former so I went with that.
In short: don't use timers, use Unity's InvokeRepeating() function because it works perfectly. It is actually very similar to JavaScript's setInterval() which I found interesting.
I have a loop that pushes back calls of std::async that are used to create objects in the pointed function and emplace them back to another vector. All the calls are pushed to the futures function and the results are ready when i used the VS debugger. However of the 507 calls, only 30 objects are actually created and i cant seem to pin point why.I have tried setting the launch policy to both async and defered but get the same result.
void load_sec_p(vector<Security>* secs, map<string, map<string, vector<daySec>>> *psa_timeline,security sec) {
Security tmp = Security(psa_timeline, &sec.tsymb, &sec.gicsInd);
std::lock_guard<std::mutex> lock(s_SecsMutex);
secs->emplace_back(tmp);
}
Above is the function being executed in the async call
below is the loop that pushes back the futures
for (auto& sec : security_list) {
m_SecFutures.emplace_back(std::async(load_sec_p,&async_secs, &psa_timeline, sec));
}
The following pictures show the watch of both variables after the above loop is completed and the entire future vectors is checked for completion.
I have tried creating the objects by just using a regular for loop and appending them synchronously but it simply just takes too long(2 hours and 11 minutes long). If anyone has any advice on alternatives or how to fix my vector problem it would be greatly appreciated.
The code that checks if all the futures is shown below:
bool done = false;
cout << "Waiting...";
do {
done = futures_ready(m_SecFutures);
} while (!done);
The function is
template<class T>
bool futures_ready(std::vector<std::future<T>>& futures) {
std::chrono::milliseconds span(5);
bool finished = false;
int pends = 0;
while (!finished) {
//allowing thread to sleep so futures can process a bit more and also
//so thread doesnt reach max cpu usage
std::this_thread::sleep_for(std::chrono::milliseconds(100));
for (auto& x : futures) {
if (x.wait_for(span) == std::future_status::timeout) {
++pends;
}
}
if (pends == 0) {
finished = true;
}
else {
pends = 0;
}
}
return finished;
}
I have a function (lets call it function A) that 0 to many threads can access it (at the same time, no shared resources). At any given time, the user can use to stop the process. The stop functionality needs to make sure that there are threads accessing function A, so that a graceful shutdown can be performed. Is there a native procedure to do so?
What I was going to do is have an InterlockedIncrement an integer everytime function A is called (and a corresponding InterlockedDecrement on said integer when function A exists). When an InterlockedDecrement takes place, it checks the value of the integer, if it's set to zero, a event is set to signalled. If the value is not zero, the event is set to nonsignalled.
This makes sense in my mind, but I'm curious whether there is a more native structure / functionality adapted to do so.
I still have to thing about the fact the "stop" function may get starved (in the sense, the said integer may never be set to zero). A sidenote: when the stop event takes place, the InterlockedIncrement process shall be stopped, to reduce said starvation.
what you need and want implement is called Run-Down Protection. unfortunately it supported only in kernel mode, but not hard implement it yourself in user mode too.
the simplest implementation is next:
HANDLE ghStopEvent;
LONG gLockCount = 1;
BOOLEAN bStop = FALSE;
void unlock()
{
if (!InterlockedDecrement(&gLockCount)) SetEvent(ghStopEvent);
}
BOOL lock()
{
LONG Value = gLockCount, NewValue;
for ( ; !bStop && Value; Value = NewValue)
{
NewValue = InterlockedCompareExchange(&gLockCount, Value + 1, Value);
if (NewValue == Value) return TRUE;
}
return FALSE;
}
void funcA();
void UseA()
{
if (lock())
{
funcA();
unlock();
}
}
and when you want begin rundown - once call
bStop = TRUE; unlock();
how you can see lock function is interlocked increment gLockCount on 1 but only if it not 0.
in kernel mode you can call instead
EX_RUNDOWN_REF gRunRef;
void UseA()
{
if (ExAcquireRundownProtection(&gRunRef))
{
funcA();
ExReleaseRundownProtection(&gRunRef)
}
}
and on place final unlock - ExWaitForRundownProtectionRelease
some more complex and scalable implementation of rundown-protection:
#define RUNDOWN_INIT_VALUE 0x80000000
#define RUNDOWN_COMPLETE_VALUE 0
class __declspec(novtable) RUNDOWN_REF
{
LONG _LockCount;
protected:
virtual void RundownCompleted() = 0;
public:
BOOL IsRundownBegin()
{
return 0 <= _LockCount;
}
void Reinit()
{
if (InterlockedCompareExchange(&_LockCount, RUNDOWN_INIT_VALUE, RUNDOWN_COMPLETE_VALUE) != RUNDOWN_COMPLETE_VALUE)
{
__debugbreak();
}
}
RUNDOWN_REF()
{
_LockCount = RUNDOWN_INIT_VALUE;
}
BOOL AcquireRundownProtection()
{
LONG Value = _LockCount, NewValue;
for ( ; Value < 0; Value = NewValue)
{
NewValue = InterlockedCompareExchange(&_LockCount, Value + 1, Value);
if (NewValue == Value) return TRUE;
}
return FALSE;
}
void ReleaseRundownProtection()
{
if (RUNDOWN_COMPLETE_VALUE == InterlockedDecrement(&_LockCount))
{
RundownCompleted();
}
}
void BeginRundown()
{
if (AcquireRundownProtection())
{
_interlockedbittestandreset(&_LockCount, 31);
ReleaseRundownProtection();
}
}
};
and use it like:
class MY_RUNDOWN_REF : public RUNDOWN_REF
{
HANDLE _hEvent;
virtual void RundownCompleted()
{
SetEvent(_hEvent);
}
// ...
} gRunRef;
void UseA()
{
if (gRunRef.AcquireRundownProtection())
{
funcA();
gRunRef.ReleaseRundownProtection();
}
}
and when you want stop:
gRunRef.BeginRundown();// can be safe called multiple times
// wait on gRunRef._hEvent here
interesting that in kernel exist else one (more old - from win2000, when rundown protection from xp) api Remove Locks. it do almost the same. different only in internal implementation and usage. with remove locks code will be look like this:
IO_REMOVE_LOCK gLock;
void UseA()
{
if (0 <= IoAcquireRemoveLock(&gLock, 0))
{
funcA();
IoReleaseRemoveLock(&gLock, 0);
}
}
and when we want stop - call
IoAcquireRemoveLock(&gLock, 0);
IoReleaseRemoveLockAndWait(&gLock, 0);
my first code spinet by implementation near remove locks implementation, when second near rundown-protection implementation. but by sense both do the same
I know this might already have been answered, but all the places where i found it, it wouldn't work properly. I'm making a game in Greenfoot and I'm having an issue. So I'm generating a random number every time a counter reaches 600, and then testing if that randomly generated number is equal to 1, and if it is, it creates an object. For some reason, the object will be created every time the counter reaches 600. I'm somewhat new to Java so it's probably something simple.
import greenfoot.*;
import java.util.Random;
/**
* Write a description of class Level_One here.
*
* #CuddlySpartan
*/
public class Level_One extends World
{
Counter counter = new Counter();
/**
* Constructor for objects of class Level_One.
*
*/
public Level_One()
{
super(750, 750, 1);
prepare();
}
public Counter getCounter()
{
return counter;
}
private void prepare()
{
addObject(counter, 150, 40);
Ninad ninad = new Ninad();
addObject(ninad, getWidth()/2, getHeight()/2);
Fail fail = new Fail();
addObject(fail, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
private int spawnCounter = 0;
private int invincibleCounter = 0;
Random random = new Random();
private int randomNumber;
public void act()
{
controls();
{if (spawnCounter > 500) {
spawnCounter = 0;
addObject(new Fail(), Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
spawnCounter++;
{if (spawnCounterTwo > 300) {
spawnCounterTwo = 0;
addObject(new APlus(), Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
spawnCounterTwo++;
}
if (invincibleCounter > 600)
{
int randomNumber = random.nextInt(10);
if (randomNumber == 1)
{
Invincible invincible = new Invincible();
addObject(invincible, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
invincibleCounter = 0;
}
if (randomNumber == 2)
{
Storm storm = new Storm();
addObject(storm, Greenfoot.getRandomNumber(getWidth()), Greenfoot.getRandomNumber(getHeight()));
}
else
{
}
}
invincibleCounter ++;
}
}
private int spawnCounterTwo = 100;
public void controls()
{
if (Greenfoot.isKeyDown("escape"))
{
Greenfoot.stop();
}
}
}
I'm not getting errors as it is compiling fine, but when i run it i have issues. Any help? Thanks in advance!
This is only speculation, since I cannot see the rest of your code, but I suspect that you are seeding your random number generator with some constant number. So every time you run your program, the random number generator generates numbers in the same order. In order to confirm this, please show some more code.
Also, your brackets do not match, so at least please show enough code to have matching curly braces.
Are you sure it is created exactly when the counter hits 600? You're incrementing the counter every frame, and at the default ~30 fps speed, that's twenty seconds. Then every frame after that, you're getting a random integer and have a 10% chance to make an Invincible. But 10% chance will on average come up within ten frames, which is 1/3 of a second. Then the counter will reset and you'll wait twenty more seconds, then create an Invincible within the next second, and so on. If you want a 10% chance every 20 seconds, you need to reset the Counter in the else branch, as well as the "then" branch (or just reset it just inside your very first if).
Hello everyone I have been following this tutorial here http://www.gogo-robot.com/2011/05/30/xna-skinned-model-animations/ and so far its great got the animations playing and everything, but now I want to expand it and stop the continuous loops say for instance i press the a key to make the model jump when i release the a key i want him to stop jumping but if i hold the a key i want him to keep jumping. Here what i have tried so far
and none of it works.
I am stumped here on how to do this thanks for any help with this.
private void HandleInput(GameTime gameTime)
{
currentGamePadState = GamePad.GetState(PlayerIndex.One);
// Check for changing anims
//SkinningData skinningData = model.Tag as SkinningData;
SkinningData sd = jumper.model.Tag as SkinningData;
if (currentGamePadState.Buttons.A == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "Fire")
jumper.animationPlayer.StartClip(sd.AnimationClips["Fire"]);
}
if (currentGamePadState.Buttons.X == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "DieF")
jumper.animationPlayer.StartClip(sd.AnimationClips["DieF"]);
}
//does not work
if (currentGamePadState.Buttons.X == ButtonState.Released)
{
if (jumper.animationPlayer.CurrentClip.Name == "DieF")
jumper.animationPlayer.StartClip(sd.AnimationClips["Idel"]);
}
if (currentGamePadState.Buttons.Y == ButtonState.Pressed)
{
if (jumper.animationPlayer.CurrentClip.Name != "Idel")
jumper.animationPlayer.StartClip(sd.AnimationClips["Idle"]);
}
//does not work
if (jumper.animationPlayer.CurrentTime == jumper.animationPlayer.CurrentClip.Duration)
{
//set him back to idel
jumper.animationPlayer.StartClip(sd.AnimationClips["Idle"]);
}
I have tried these configuration with no luck in the game
// Starts playing the entirety of the given clip
public void StartClip(string clip, bool loop)
{
AnimationClip clipVal = skinningData.AnimationClips[clip];
StartClip(clip, TimeSpan.FromSeconds(0), clipVal.Duration, loop);
}
// Plays a specific portion of the given clip, from one frame
// index to another
public void StartClip(string clip, int startFrame, int endFrame, bool loop)
{
AnimationClip clipVal = skinningData.AnimationClips[clip];
StartClip(clip, clipVal.Keyframes[startFrame].Time,
clipVal.Keyframes[endFrame].Time, loop);
}
// Plays a specific portion of the given clip, from one time
// to another
public void StartClip(string clip, TimeSpan StartTime, TimeSpan EndTime, bool loop)
{
CurrentClip = skinningData.AnimationClips[clip];
currentTime = TimeSpan.FromSeconds(0);
currentKeyframe = 0;
Done = false;
this.startTime = StartTime;
this.endTime = EndTime;
this.loop = loop;
// Copy the bind pose to the bone transforms array to reset the animation
skinningData.BindPose.CopyTo(BoneTransforms, 0);
}
Can you not attach a bool on the animation clip to tell it to play only once, or an active variable that can be called.