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.
Related
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.
I have a button (in UI), that I want to hide sometimes (but show again later), which means that it shouldn't show anymore and I shouldn't be able to click it. The only solution I found (that has actually managed to hide the button), is SetActive().
But in Update(), when I do SetActive(false) (the true/false is controlled with the variable wave_happening in my script), Update() doesn't run anymore, so I can't set it to true again.
When I do GameObject.Find("Start Button").SetActive(true) in another script, it just gives me a NullReferenceException (Object reference not set to an instance of an object).
This is my Update() function:
void Update() {
wave_happening = enemy_spawner_script.wave_happening;
Debug.Log(wave_happening);
transform.gameObject.SetActive(wave_happening);
}
Is there a solution to stop this problem, or another way to hide a button?
I'm fairly new to Unity and C#, so I don't know very much.
You can try disabling the button's rendering and functionality components:
GetComponent<Button>().enabled = false; // remove functionality
GetComponent<Image>().enabled = false; // remove rendering
Now, adding that to your Update function, plus a few changes for performance so you are not enabling/disabling every single frame, only when needed:
private bool isShowing = true; // or whatever your default value is
void Update() {
wave_happening = enemy_spawner_script.wave_happening;
Debug.Log(wave_happening);
if(wave_happening != isShowing) {
show(wave_happening);
isShowing = wave_happening;
}
}
void show(bool isShow) {
GetComponent<Button>().enabled = isShow; // remove functionality
GetComponent<Image>().enabled = isShow; // remove rendering
}
It's really difficult to do this well. Lots of issues arise:
Inevitably the button will be in a H or V layout group, and, as a basic software engineering issue of course you want it to work whether or not it is in a layout group, as that layout detail may be changed by your designers as the project goes on. For this reason it is a really good idea, as the OP initially guessed, to simply use .SetActive
But then you have the problem of the button being off so Update is not running. A simple solution is just to put the button in a wrapper. That is to say, simply in a UI Panel. Have the button manager script on that wrapper rather than on the button per se.
Then you just have a pretty Property on the manager script,
public bool Showme
{
etc...
and then you can just go ...
void Update()
{
Showme = enemy_spawner_script.wave_happening;
}
Can't get simpler looking code.
However, if you use a wrapper Panel. It is true that you have to be pretty expert at using the UI (particularly the auto sizing stuff) to make it work just the way you want. But, that's part of building Unity expertise unfortunately. :/
The concerns about performance is ... truly ridiculous. There's no difference between Unity's raw code "checking a boolean" and yourself "checking a boolean". However for sure as a matter of style it's crap to poll it in Update. (Note that in point "B" just above, if you're going to have heinously ugly "anti-polling" code, bury it in that Property.)
And then ...
"Trick" solution
A tip in Unity UI is you can add a CanvasGroup anywhere. Why would you do this? It allows you to FADE the whole thing, which, is often a quick solution to achieve what you want.
Hence ..
public CanvasGroup fader;
and then ..
void Update()
{
fader.alpha = enemy_spawner_script.wave_happening ? 1f : 0f;
}
and you're done!
i'm making my first enemy AI in unity. I'm trying to make a finished state machine with the animator controller to do it.
I just discovered the StateMachineBehaviour script which is called when the AI is in a state. It has multiple methods, including the OnStateEnter. It is called everytime the AI enter the state.
My problem is only about optimization, my AI need to get the GameObject "Player" in order to attack it. So i'm getting it in my OnStateEnter method for the moment, which i feel is bad, because i'm getting it every time the animation is called, i would like to get it only once, at the start.
I basicly need a start function but it's not working, i have made research and found nothing. I tried to watch video about people making a finished state machine but they are just getting the same GameObject multiple time ( example here : https://youtu.be/dYi-i83sq5g?t=409 ).
So, is there a way to have a start function or to get an element only once ?
I could make a bool that is called only the first time and that get the GameObject, but again that would be an "useless" if running in my function.
Any suggestions ? Thanks
No, unlike a MonoBehaviour a StateMachineBehaviour has no Start message only OnStateEnter, OnStateExit, OnStateIK, OnStateMove and OnStateUpdate.
There are also Awake and OnEnable but I'm pretty sure they are not used in the StateMachine and might not behave as expected.
You can however either use
OnStateMachineEnter
Called on the first Update frame when making a transition to a StateMachine. This is not called when making a transition into a StateMachine sub-state.
Or use a simple bool flag like
bool alreadyExecuted = false;
OnStateEnter()
{
if(alreadyExecuted) return;
// Do your stuff
alreadyExecuted = true;
}
(Just a guess)
In the Inspector you actually can enable and disable StateMachineBehaviours like components. So it might be able to do this also in script maybe the same way using
enabled = false;
but I didn't find anything about it in the API and since I'm currently on my Smartphone I can't test it.
I'm writing a game with some animations, and use those animations when the user clicks on a button. I would like to show the user the animation, and not "just" call a new level with Application.loadLevel. I thought I could use the Time.DeltaTime in the onMouseUp method and add it to a predefined 0f value, then check if it is bigger than (for example) 1f, but it just won't work as the onMouseUp method adds just "it's own time" as the delta time.
My script looks like this now:
public class ClickScriptAnim : MonoBehaviour {
public Sprite pressedBtn;
public Sprite btn;
public GameObject target;
public string message;
public Transform mesh;
private bool inAnim = true;
private Animator animator;
private float inGameTime = 0f;
// Use this for initialization
void Start () {
animator = mesh.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
}
void OnMouseDown() {
animator.SetBool("callAnim", true);
}
void OnMouseUp() {
animator.SetBool("callAnim", false);
animator.SetBool("callGoAway", true);
float animTime = Time.deltaTime;
Debug.Log(inGameTime.ToString());
// I would like to put here something to wait some seconds
target.SendMessage(message, SendMessageOptions.RequireReceiver);
}
}
}
Im not entirely sure what your trying to do by using Time.deltaTime in onMouseUp. This is just the time in seconds since the last frame was rendered, and should act the same no matter where you try to access it. Normally it is used in a function that is called every frame, not one-off events like onMouseUp.
Despite not being certain what you are trying to achieve, it sounds like you should be using Invoke:
http://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html
Just put the code you wish to be delayed into a separate function, and then invoke that function with a delay in onMouseUp.
EDIT: To backup what some others have said here I would not use Thread.Sleep() in this instance.
You want to do this (and all waiting functions that do not appear to make the game "freeze") by blocking the Update loop by using a Coroutine.
Here is a sample of what you are probably looking for.
void OnMouseUp()
{
animator.SetBool("callAnim", false);
animator.SetBool("callGoAway", true);
//Removed the assignement of Time.deltaTime as it did nothing for you...
StartCoroutine(DelayedCoroutine());
}
IEnumerator DoSomethingAfterDelay()
{
yield return new WaitForSeconds(1f); // The parameter is the number of seconds to wait
target.SendMessage(message, SendMessageOptions.RequireReceiver);
}
Based on your example it is difficult to determine exactly what you want to accomplish but the above example is the "correct" way to do something after a delay in Unity 3D. If you wanted to delay your animation, simply place the calling code in the Coroutine as I did the SendMessage invocation.
The coroutine is launched on it's own special game loop that is somewhat concurrent to your game's Update loop. These are very useful for many different things and offer a type of "threading" (albeit not real threading).
NOTE:
Do NOT use Thread.Sleep() in Unity, it will literally freeze the game loop and could cause a crash if done at a bad time. Unity games run on a single thread that handles all of the lifecycle events (Awake(), Start(), Update(), etc...). Calling Thread.Sleep() will stop the execution of these events until it returns and is most likely NOT what you're looking for as it will appear that the game has frozen and cause a bad user experience.
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.