Does this work? This is in the start method, using photon for networking. I am trying to wait till room time is initialised.
Wait:
if (!PhotonNetwork.CurrentRoom.CustomProperties.ContainsKey("StartTime") )
{
goto Wait;
}
else
{
goto Continue;
}
Continue:
startTime = double.Parse(PhotonNetwork.CurrentRoom.CustomProperties["StartTime"].ToString());
In general I would say avoid using goto at all!
In almost all cases I can think of any other solution in my eyes is cleaner and better to read and maintain than goto jumps. It is more a "relic" of former times. In the examples of goto might be the only use-case where it might make sense .. within a switch-case or to break out of a nested loop .. but even there you can find other (in my eyes better) solutions.
Your code basically equals writing
while(!PhotonNetwork.CurrentRoom.CustomProperties.ContainsKey("StartTime")) { }
startTime = double.Parse(PhotonNetwork.CurrentRoom.CustomProperties["StartTime"].ToString());
And latest now I hope you see the huge issue: You have a neverending while loop!
Inside the while the condition is never changed
And it can not be changed from the outside either since you run this in Start so the entire Unity main thread is blocked until that loop ends. I'm not 100% sure but afaik PhotonNetwork needs the Unity main thread to dispatch the received events -> your condition probably will never ever become true.
You should rather use a Coroutine. A Coroutine is like a small temporary Update method. It is not async but rather runs right after Update until the next yield statement and thereby still allows your Unity main thread to continue rendering and doesn't freeze your entire application.
// Yes, if you make Start return IEnumerator
// then Unity automatically runs it as a Coroutine!
private IEnumerator Start ()
{
// https://docs.unity3d.com/ScriptReference/WaitUntil.html
// This basically does what it says: Wait until a condition is true
// In a Coroutine the yield basically tells Unity
// "pause" this routine, render this frame and continue from here in the next frame
yield return new WaitUntil(() => PhotonNetwork.CurrentRoom.CustomProperties.ContainsKey("StartTime"));
startTime = double.Parse(PhotonNetwork.CurrentRoom.CustomProperties["StartTime"].ToString());
....
}
Even better than checking this every frame in a loop at all would actually be
check this once in start
only check it again once after the room properties have actually changed
So something like e.g.
bool isInitialzed;
private void Start ()
{
TryGetStartTime (PhotonNetwork.CurrentRoom.CustomProperties);
}
private void TryGetStartTime(Hashtable properties)
{
if(!properties.Contains("StartTime")) return;
startTime = double.Parse(properties["StartTime"].ToString());
isInitialzed = true;
}
public void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
TryGetStartTime (propertiesThatChanged);
}
And rather make other methods wait until isInitialized is true.
Related
I am currently experimenting with Godot C# making a basic shooter and for the gun's fire rate I have been experimenting with different delay systems. Node Timers work although I'm trying to make the script generic, and the Timer calls seem to only call functions in the parent script.
I'm now looking at C#'s Task.Delay method and it also seems to work, with it being an async action it does not look to be affected by the frame rate or slow down the game.
My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Here's the code below although I don't think it’s important:
private void shoot() {
//if "canShoot" spawn bullet
ShootCooledDown();
}
private async void ShootCooledDown() {
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
canShoot = false;
await Task.Delay(span);
canShoot = true;
}
My question is, is there any known issue for using Task.Delay in game applications: like is it unreliable or can it crash if too many instances of the method are called?
Not per se. There is nothing in particular wrong with Task.Delay in games, nor too many instances of it.
However, what you are doing after Task.Delay can be a problem. If you execute await Task.Delay(span);, the code that comes after might run in a different thread, and thus it could cause a race condition. This is because of await, not because of Task.Delay.
For example, if after await Task.Delay(span); you will be adding a Node to the scene tree (e.g. a bullet), that will interfere with any other thread using the scene tree. And Godot will be using the scene tree every frame. A quick look at Thread-safe APIs will tell you that the scene tree is not thread-safe. By the way, the same happen with virtually any widget API out there.
The solution is use call_deferred (CallDeferred in C#) to interact with the scene tree. And, yes, that could offset the moment it happens to the next frame.
I'll give you a non threading alternative to do that.
There are method get_ticks_msec and get_ticks_usec (GetTicksMsec and GetTicksUsec in C#) on the OS class, that give you monotone time which you can use for time comparison.
So, if you make a queue with the times it should shoot (computed by taking the current time plus whatever interval you need). Then in your process or physics process callback, you can check the queue. Dequeue all the times that are overdue, and create those bullets.
If you don't want to solve this with Godot APIs, then start a Stopwatch at the start of the game, and use its elapsed time.
But perhaps that is not the mechanic you want anyway. If you want a good old cool-down, you can start the Stopwatch when you need the cool-down, and then compare the elapsed time with the cool-down duration you want to know if it is over.
I don't have any experience with Godot.. but my idea would be....
instead of using a timer, you could store the last shoottime in a variable/field. If you're trying to shoot within the lastTimeShot+coolDown, just ignore the shoot command.
For example:
private DateTime _lastShot = DateTime.MinValue;
private void shoot()
{
TimeSpan span = TimeSpan.FromSeconds((double)(new decimal(shotDelay)));
// if the time when the last shot has fire with the cooldown time
// is greater than the current time. You are still in the cooldown time.
if(_lastShot.Add(span) > DateTime.UtcNow)
return; // within cooldown, do nothing
//if "canShoot" spawn bullet
ShootCooledDown();
_lastShot = DateTime.UtcNow;
}
Due to a valid comment of Theodor, about changing the system time would lead bug-prone gameplay.
I wrote a second version.
private Stopwatch _shootingCooldownStopwatch = default;
private void shoot()
{
var shotDelayMs = shotDelay * 1000;
// if the _shootingCooldownStopwatch is ever started
// and the ElapsedMilliseconds are in the showDelay
// we're not allowed to fire again. So exit the method.
if (_shootingCooldownStopwatch?.ElapsedMilliseconds < shotDelayMs)
return;
_shootingCooldownStopwatch = Stopwatch.StartNew();
//if "canShoot" spawn bullet
ShootCooledDown();
}
I think this would be a better solution.
When you develop games in Godot or any other game engine, you shouldn't use any timer based in the computer clock, like the Stopwatch or Task.delay. Instead, you have to manage yourself the time elapsed using the delta time from the previous frame, which is received in the _Process(float delta) or _PhysicsProcess(float delta) methods. The reason are:
The time will be more accurate in case of frame-rate drop.
If you pause the game, timer will pause too.
That's the main reason Godot offers you a Timer component that you have to attach to the current scene in order to work with it.
If you don't want to add anything to the scene, which completely reasonable, you have to get the delta, storing the elapsed time in a variable and check if this variable reach some limit.
In my games, I use my own timers with this very simple class:
public class Timer {
public float Elapsed { get; private set; } = 0;
public bool Stopped { get; private set; } = true;
public float Alarm { get; private set; } = float.MaxValue;
public Timer Start() {
Stopped = false;
return this;
}
public Timer Stop() {
Stopped = true;
return this;
}
public Timer Reset() {
Elapsed = 0;
return this;
}
public Timer ClearAlarm() {
Alarm = float.MaxValue;
return this;
}
public Timer SetAlarm(float finish) {
Alarm = finish;
return this;
}
public bool IsAlarm() => Elapsed > Alarm;
public Timer Update(float delta) {
if (!Stopped) {
Elapsed += delta;
}
return this;
}
}
```
You have to Update the timer in every frame
I am no expert in Godot but I can tell that Task.Delay() is considered better than alternatives like Thread.Sleep() for example because being asynchronous i releases the thread to the thread pool and when the time has passed it continues execution, in contrast to the latter option that blocks the thread instead.
The problem I can see is that each web server can accept a max limit of concurrent requests, by using Task.Delay() in your code you can start accumulating requests "just waiting" due to the delay. So if your app starts receiving a big amount of requests coupled with a long Delay time that might be an issue with requests queued up (delay) or even denied.
If the delay is a number of seconds (significant time) then I would probably think about storing user in a cache (you can also store in a dictionary Dictionary<string, bool> where string is the userId but this solution will not scale out, that is why I suggest a distributed cache), and check (TryGetValue()) your cache if user is allowed to shoot. If delay is a couple of microseconds (affordable time) still not an ideal solution but it will probably be a problem.
In contrast to the answer by #Theraot and its approach via await Task.Delay(span) and according to my understanding, asynchronous does NOT equal to multi-threading. Using await Task.Delay(span) won't cause your code executing in another thread. So you don't really need to use CallDeferred in this case.
Reference:
What is the difference between asynchronous programming and multithreading?
Does Task delay create new Thread?
Does the use of async/await create a new thread?
Dear stackoverflow community,
I have countdown timer for my double points power up and now I have problem because my code works fine in game,but when timer is active game is lagging , not too much but any lag is not good for my game because the player needs to play smoothly without any unoptimised component..
I have this code and I bet the game is lagging because the code is in update method ( I tried to put it in game manager script but then timer won't countdown so that is not solution )
This is the code ( Thanks to stackoverflow user #siusiulala , who wrote me the working code)
but seems like it needs to be in another method or something because Update method running performance when has countdown inside.
private void Update(){
if (isDoublePoints)
{
// Countdown the timer with update time
powerUpTimer -= Time.deltaTime;
Debug.Log("TIMER ISS " + powerUpTimer);
if (powerUpTimer <= 0)
{
// End of power up time
isDoublePoints = false;
}
}
}
public void OnPickPowerUp(float buffTime)
{
powerUpTimer += buffTime;
}
I hope someone will give solution to lagg because I saw a lot of games that has power up systems without any laggs inside...
Thank you stackoverflow, without you my game would not ever come to end :)
what trollingchar's answer says about the Debug.Log is correct.
To use the [SerializeField] might be considered as a dirty and lazy hack by some people. Because it has the side-effect that it is now serialized, that means the value is stored in the assets. It's not bad but if you are exact it shouldn't be done with fields that will be changed on runtime anyway.
Instead you can simply go to the Inspector, open the context menu and set it to Debug Mode
this makes the Inspector not use the Custom EditorScripts but instead reveal all private fields (of Serializable types).
For example for the Transform component
However way more efficient than using the Update method with a flag at all would be to rather use a Coroutines.
Coroutines can be started and run parallel (every frame right after) the Update method but the advantage: when a coroutine is finished - it is finished and doesn't continue checking the bool flag every frame.
So whenever you pickup a PowerUp instead of setting the flag to true rather use
StartCoroutine(PowerUpRoutine());
and implement a routine like
private IEnumerator PowerUpRoutine()
{
isDoublePoints = true;
while(powerUpTimer > 0)
{
// Countdown the timer with update time
powerUpTimer -= Time.deltaTime;
//Debug.Log("TIMER ISS " + powerUpTimer);
// yield in simple words makes Unity "pause"
// the execution here, render this frame and continue from here
// in the next frame
yield return null;
}
// End of power up time
isDoublePoints = false;
}
public void OnPickPowerUp(float buffTime)
{
powerUpTimer += buffTime;
// avoid concurrent routines
if(!isDoublePoints) StartCoroutine(PowerUpRoutine());
}
In order to display it in your game you can use a Text or TextMeshPro and set the text like e.g.
[SerializeField] private Text _text;
private IEnumerator PowerUpRoutine()
{
isDoublePoints = true;
while(powerUpTimer > 0)
{
// Countdown the timer with update time
powerUpTimer -= Time.deltaTime;
//Debug.Log("TIMER ISS " + powerUpTimer);
// set the text of the Text component to display the value
// for the $ symbol google for "c# string interpolation"
_text.text = $"TIMER IS {powerUpTimer:00.00}";
// yield in simple words makes Unity "pause"
// the execution here, render this frame and continue from here
// in the next frame
yield return null;
}
// End of power up time
isDoublePoints = false;
}
From my experience, Debug.Log() is a very expensive method. It will cause lag when called every frame. My IDE even highlights usage of Debug.Log() in Update() as warning because of that. Use this method only for debugging, and then remove.
If you want to be able to see the timer value, add [SerializeField] attribute to your field and it will show up in the inspector.
You can use the profiler by selecting Window-Analysis-Profiler, assuming you are using Unity 2018.x. It records how much time processing takes, and helps locating bottlenecks.
This question already has answers here:
Play and wait for Animation/Animator to finish playing
(2 answers)
Closed 5 years ago.
Why doesn't this work? I am finding that my while loop is exiting immediately. My death animation takes about 1second, and I am watching the death state be active for that duration, after which, it exits to my Idle state. Is there a timing issue, where my boolean condition is being tested before the death state is started?
I am trying to find a direct test on an animation for when it stops running.
private void playerDestroyed ()
{
int deathHash = Animator.StringToHash("PlayerDeath");
GameController.instance.pauseGame();
_anim.Play(deathHash);
while ( _anim.GetCurrentAnimatorStateInfo(0).nameHash == deathHash) {
System.Threading.Thread.Sleep(100);
}
GameController.instance.gameOver();
}
EDIT:
So I changed my question to reflect what I'm really after: a best practice for knowing when an animation has completed. I have seen examples using a WaitForSeconds strategy, but with the time to wait hardcoded, which is not ideal. If I was to use this, I would want to pull the time of the animation, but I have had trouble accessing the animation clip length via the animator.
Ok, kudos to rutter for mentioning the "will the game wait one frame". It was driving me mental that the AnimationInfo[] coming back was null for me when I tried accessing the running clip. I didn't think the Animator needed time to update it's statuses after a direct call to play an animation.
Also interestingly, I tried the same code but using a trigger instead of dealing with the hash business, and the code below fails. My variable s comes back with Length of Zero. The trigger needs more time than a single frame to work, I guess.
I thought I would put this together as an answer for how to achieve a test for an end of a clip. However, please let me know if there is a better way!
private void playerDestroyed ()
{
// a global var for the Animator object
_anim = GetComponent<Animator>();
int hash = Animator.StringToHash("Base Layer.PlayerDeath");
_anim.Play(deathHash);
StartCoroutine("WaitForAnimation");
}
IEnumerator WaitForAnimation() {
yield return new WaitForEndOfFrame();
AnimationInfo[] s = _anim.GetCurrentAnimationClipState(0);
yield return new WaitForSeconds( s[0].clip.length);
//do something now, after the animation is complete
GameOver();
}
Is there any function to freeze all the game or a certain class for a moment?
I'm searching for a Wait function like in Matlab.
Thanks.
EDIT: The wait function stops all the processing for a given time.
A one-line hack would be to call Thread.Sleep(x) in the main Update(), but that'll hang the game for the specified amount of time. The user will think your app has become unresponsive and he might kill it and restart it! It's probably not what you want.
The way I architecture games, each major component has its own Update() (or Tick()) method that is called on each logical update. You can selectively freeze components by simply not calling their Update() for a while. There are things you certainly never want to freeze, like refreshing the screen, responding to user input or sound processing.
Some example code:
// To pause the game for x number of frames, set pauseDelay = to x
int pauseDelay;
public void Update() {
if (pauseDelay > 0) {
--pauseDelay;
}
else {
physics.Update();
ai.Update();
}
input.Update();
sound.Update();
}
If you've based your game on GameComponents you can usually just set the Enabled flag to false which prevents the update logic being executed, this obviously depends on other factors (Object manipulation outside of the classes update logic, update logic being performed in the draw or other method ect..)
public class Car : GameComponent
{
// This logic is only called if the Enabled property is set to true.
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
}
If you've not used game component then it would be quite simple to introduce an Enabled flag to your clases and check for that before executing update logic.
If your looking for a very simple way (Andy's seems better, but this is quick way)
In your update Method a class, add at the top:
if (isPaused)
break;
You can use isActive to check is the window is active too.
I want a method in a DrawableGameComponent class to not return until a particular condition is met
Say I have this class (snippet from a DrawableGameComponent class):
public override void Update(GameTime gameTime)
{
if (moving && pixFromLastMove <= distanceToMove)
{
position += velocity;
pixFromLastMove += velocity.Length();
}
else
{
moving = false;
}
if (rotating)
{
rotation += 0.1f;
var cRotation = MathHelper.Clamp(rotation, -MathHelper.PiOver2, angleBeforeRotation + degToRotate);
if (cRotation != rotation)
{
rotation = cRotation;
angleBeforeRotation = rotation;
rotating = false;
}
}
base.Update(gameTime);
}
public void Ahead(int pix)
{
moving = true;
distanceToMove = pix;
pixFromLastMove = 0;
velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;
//DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
}
public void TurnLeft(int deg)
{
rotating = true;
degToRotate = MathHelper.ToRadians(deg);
angleBeforeRotation = rotation;
//DO NOT RETURN UNTIL THIS ROBOT HAS BEEN FULLY ROTATED
}
This class is being drawn (Draw())in the main thread (because this drawablegamecomponent is executing in seperate thread), and also in the main thread I have a list of commands that I want to be executed in order...but currently, since the Ahead method returns just after assigning a value to velocity, the methods will run almost concurrently, which in turn just executes all the animations at the same time.
So what do you think should I do to prevent methods that are commands (Ahead,TurnLeft etc..) from returning before a certain condition is met?
You need to create some kind of state machine for your Update() method. e.g.
public override void Update() {
if (movingRobot) {
OnlyUpdateRobotPosition();
}
else {
DoStuffPerhapsIncludingStartingRobotMove();
}
}
Or am I missing the question?
Ahh, two words: Cooperative multitasking. With the joy of Fibers (or your cooperative multitasking building block of choice) you could (after laying some ground work, such as this to enable fibers in C#) do something like this:
public void Ahead(int pix)
{
moving = true;
distanceToMove = pix;
pixFromLastMove = 0;
velocity = new Vector2((float) Math.Cos(rotation), (float) Math.Sin(rotation))*5.0f;
//DO NOT RETURN UNTIL THIS ROBOT HAS MOVED TO ITS DESTINATION
while(!HasReachedDestination())
{
Yield(); // let another fiber run
}
}
In order to make this work however you need to implement a simple round-robin scheduler. C# isn't really my boat, but what I'd do is to keep it simple and create some sort of base-class that I'd call Cooperative (or something). This class would have a static list of all created fibers as well as the static methods Create() and Yield(). Create() will create a new fiber (or whatever) and Yield() will simply schedule next fiber to execute (round-robin style), in fiber-world that would include a call to SwitchToFiber(). It will also have a virtual method called Start() (or whatever) that is where the fiber will start to run.
To make it more fancy-smancy you could later keep separate lists of fibers that are either runnable or not runnable (i.e. waiting for something to happen). In that case you might be able to simplify the loop in Ahead to:
WaitFor(HasReachedDestination);
But I suggest getting your feet wet with the concept of cooperative multitasking first.
Finally some thoughts on what should be made fibers, typically your main update loop is one fiber, updating and drawing all objects and then calls Yield(). The all game objects would also be fibers (this may not be feasible if you have a lot of game objects). For your game objects you'd do something like:
public override Start()
{
do
{
if(EnemyToTheLeft())
{
TurnLeft(90); // this will call Yield and return when we have finished turning
Shoot();
}
Yield(); // always yield
}while(!dead);
}
I agree with Pop Catalin: it is probably best not to block in those command functions. I think you could improve your game by thinking about the design a bit more. Let me provide some thoughts for you on how you could possibly improve your design.
First, it sounds like the problem you are describing is that you want to send a lot of move commands, in a certain order, to a game component and have it execute those commands in that certain order. As you have noticed, there is a difference in the time it takes the computer to perform the calculations (for the velocity or rotation) and the time it takes the component to actually perform the action (move or rotate).
The problem with blocking during the calculations (Ahead, TurnLeft, etc) is that the update loop that is calling that function cannot update any other components. That may work okay if there is only one component to worry about, but that's not usually the case in most games.
Now for the good part: how do we fix this problem? I think erikkallen has the right idea, but I would take it a bit further. It sounds like the game component is some kind of entity that will be moving around, so why not give it an action queue? A simple implementation would be to just have your calling function call something like:
gameComponent.queueAction( (MethodInvoker)delegate()
{ gameComponent.Ahead(10); });
Your queueAction function might look like this:
public void queueAction(MethodInvoker action)
{
queue.Enqueue(action);
}
At the top of your Update function you could add:
if(noCurrentAction && queue.Count > 0)
{
((MethodInvoker)queue.Dequeue()).Invoke();
noCurrentAction = false;
}
And you'd need to add a line at the end of the Update function like:
if(!moving && !rotating)
noCurrentAction = true;
Now, I definitely wouldn't call this the best solution, but it doesn't take much code to implement it. Of course if you need to move and rotate at the same time you'll have to tweak it a bit. It will also get messier when you add different types of actions.
For a more general solution, I would think about making a base Action class, and deriving specific action classes from it. Then you could just push actions to the queue, and your Update function could call the action's Update function, which would do the work the two sections of your game components Update function is doing now.
These are just some ideas to think about, I hope something here will get you started.
One last thing I wanted to mention was that I don't see you using gameTime variable that is passed to Update. The amount your component moves and rotates may need to be a function of the elapsed time since Update was last called. Meaning that the Update function would move and rotate your game component based on the amount of time that has passed, not just how many times the Update function was called. I'm not very good at explaining it, and it depends on how you'd like your game to function. Here are a couple different posts from Shawn Hargreaves (XNA expert). Also, an XNA Forum post discussing the point I was trying to make.
Although I find your design somewhat odd, best way to accomplish what you want is to use an EventWaitHandle and signal it from another thread.
Say you have an instance of the waithandle on your class
you can call waithadle.WaitOne() in your method, and signal the even from another thread using waithandle.Set() when the condition is met, at which point your method will resume from waiting.