I'm trying to create a timer which updates a label every tick, This is what I have so far:
public override void ViewDidLoad ()
{
timer = new Timer ();
timer.Elapsed += new ElapsedEventHandler (TimerOnTick);
timer.Interval = 1000;
timer.Start ();
}
private void TimerOnTick (object obj, EventArgs ea)
{
timerLabel.Text = DateTime.Now.ToString ();
timerLabel.SetNeedsDisplay ();
}
But this doesn't update the label. In debug I can see that timerLabel.Text is being set, but I cant get the view to update or redraw.
How can I get my view to redraw after I update my timerLabel.text?
The label is not being updated because System.Timers.Timer invokes the handler on a separate thread. You cannot change ui elements in a thread other than the main.
Enclose your handler code to be executed on the main thread:
private void TimerOnTick (object obj, EventArgs ea)
{
this.InvokeOnMainThread(delegate {
timerLabel.Text = DateTime.Now.ToString ();
timerLabel.SetNeedsDisplay ();
});
}
Related
I have a "Start Game" button
public static bool GameIsStart;
public void changeCamera ()
{
if (GameIsStart == true)
return;
GameIsStart = true;
SceneManager.LoadScene ("Game");
}
}
``
There is a script that I added to the Prefabs
public GameObject [] gameobject;
private bool gameobject_IS_Spawn;
private float RandomPositionforX;
private int RandomObjects;
private void Update ()
{
if (StartGame.GameIsStart &&! gameobject_IS_Spawn)
{
StartCoroutine (Spawngameobject ());
gameobject_IS_Spawn = true;
}
}
IEnumerator Spawngameobject ()
{
while (true)
{
if (StartGame.GameIsStart)
{
yield return new WaitForSeconds (1.3f);
RandomPositionforX = Random.Range (-2.28f, 2.28f);
RandomObjects = Random.Range (0, gameobject.Length);
Instantiate (gameobject [RandomObjects], new Vector2 (RandomPositionforX, 24f), Quaternion.identity);
}
}
}
}
There is a button on the "Game" scene to access the preview
public void ChangeScene ()
{
SceneManager.LoadScene ("preview");
}
}
I click on the button, the "Preview" scene is loaded, but the "Start game" button does not work.
If I put in the "Preview" button SceneManager.LoadScene ("Game")
then I restart the scene ("Game") and everything works.
But if SceneManager.LoadScene ("Preview") but the buttons don't work.
When switching between scenes, is it necessary to stop Coroutine
How can this problem be corrected?
Without seeing the code it's a bit harder to find where the problem is coming from.
The only thing that is coming to my mind is that it may be something related with how the scene is stored and loaded after.
According to the Scene Manager Documentation, you could save the scene1 in a variable and keep the DontDestroyOnLoad(scene1) on its awake method, then add something like:
Scene scene2 = SceneManager.GetActiveScene(); SceneManager.LoadScene(scene1); To the button that reloads the previous scene.
I have a GameController in Scene1 and I made it DontDestroyOnLoad.
When I loaded Scene2, I'm trying to find a GameObject in Scene2 and the thing is obj2 is null but obj1 is not.
Why?
How could I find the GameObjectInScene2?
public class GameController: MonoBehaviour
{
private void Awake()
{
DontDestroyOnLoad(this);
}
private void Start()
{
SceneManager.LoadScene("Scene2");
GameObject obj1 = GameObject.Find("GameObjectInScene1");
GameObject obj2 = GameObject.Find("GameObjectInScene2");
}
}
Start is not called again since your component already ran it in Scene1
You can register to SceneManager.sceneLoaded and do the find in the callback instead.
I would also store the references global like
private GameObject obj1;
private GameObject obj2;
void Start()
{
// This first line just makes sure the listener isn't added twice
SceneManager.sceneLoaded -= OnSceneLoaded;
// Whenever a scene is loaded call OnSceneLoaded
SceneManager.sceneLoaded += OnSceneLoaded;
obj1 = GameObject.Find("GameObjectInScene1");
SceneManager.LoadScene("Scene2");
}
void OnDestroy ()
{
// Always clean up listeners when not needed anymore!
SceneManager.sceneLoaded -= OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if(scene.name == "Scene2")
{
obj2 = Find("GameObjectInScene2");
}
}
I want to wait until "next" button is pressed then continue
child.addChild(tmp);
childrenAdded.Push(tmp);
neighbor.GetComponent.<Renderer>().material.mainTexture = null;
-WAIT UNTIL CLICK ON NEXT BUTTON THEN CONTINUE-
toExpand.Push(tmp);
any idea? I tried:
while(true) {
if(GUI.Button(Rect(500,680 ,100,30),"Next"))
break
}
But it doesn't work; it freezes.
Instead of waiting, you can just have your code called when the button is clicked, like this:
void OnGUI() {
if(GUI.Button(Rect(500,680 ,100,30),"Next"))
toExpand.Push(tmp);
}
}
If possible, consider using Unity 4.6 or later so you can use the new UI which is much easier work with.
You can use Toggle button instead of button so you controll a boolean with toogle and loops what you need in your Update or LateUpdate function like this:
private Rect myRect = new Rect(500,680 ,100,30);
private bool myToggle = false;
void OnGui() {
myToggle = GUI.Toogle(myRect, myToggle, "Next");
}
void Update() {
if(myToggle){
// what I need to create while true;
}
}
Note that is not a good practice to create a new Rect every OnGUI cycle because it runs more than once per frame and it will create a performance issue.
Reading your code again may I could've misinterpreted your needing so if you could clarify what you really what your code to do would be easier to help.
Also, if you just need a "wizard" like sequence of actions I suggest you to take a look on delegates and use something like this:
delegate void MyDelegate();
private MyDelegate myDelegate;
private Rect myRect = new Rect(500,680 ,100,30);
void Start () {
myDelegate = FirstFunction;
}
void FirstFunction() {
// will execute until next button is clicked
}
void SecondFunction() {
// will execute after next button is clicked
}
void OnGui() {
if(GUI.Button(myRect, "Next")) {
myDelegate = SecondFunction;
}
}
Using a UIWebView in my application and I cant seem to release the memory it's using.
I have a UIButton which loads a view controller which holds the UIWebView.
When the webView is loaded the Real Memory (checking it using Instruments) rises but doesn't get lower after my attempts to release it.
When the button is pressed:
if (childBroswer != null)
{
childBroswer.Dispose();
childBroswer = null;
}
childBroswer = new ChildBrowser(url);
AppDelegate d = (AppDelegate)UIApplication.SharedApplication.Delegate;
if ( d.rootNavigationController.RespondsToSelector(
new MonoTouch.ObjCRuntime.Selector("presentViewController:animated:completion:")))
{
d.rootNavigationController.PresentViewController(childBroswer, true, null);
}
else
{
d.rootNavigationController.PresentModalViewController(childBroswer, true);
}
Child browser class:
public partial class ChildBrowser : UIViewController
{
public string _url {get;set;}
UIActivityIndicatorView activityIndicator;
UIWebView webBrowser;
NSUrl nsURL;
NSUrlRequest nsURLRequest;
public ChildBrowser (string url) : base ("ChildBrowser", null)
{
nsURL = new NSUrl(url);
nsURLRequest = new NSUrlRequest(nsURL);
}
public override void DidReceiveMemoryWarning ()
{
// Releases the view if it doesn't have a superview.
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
if (webBrowser == null)
{
webBrowser = new UIWebView(new RectangleF(0,41,320,380));
}
this.Add(webBrowser);
webBrowser.LoadFinished += (object sender, EventArgs e) => {
activityIndicator.StopAnimating();
} ;
webBrowser.LoadStarted += (object sender, EventArgs e) => {
if (activityIndicator == null)
{
activityIndicator = new UIActivityIndicatorView(new RectangleF(UIScreen.MainScreen.Bounds.Width / 2 - 50,
UIScreen.MainScreen.Bounds.Height / 2 - 30,100,100));
activityIndicator.Color = UIColor.Black;
}
activityIndicator.StartAnimating();
this.Add(activityIndicator);
} ;
webBrowser.LoadHtmlString("<html><head></head><body></body></html>",null); //stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML = \"\";"];
webBrowser.LoadRequest(nsURLRequest);
closeBrowser.TouchUpInside += handleClose;
// Perform any additional setup after loading the view, typically from a nib.
}
private void handleClose(object sender, EventArgs e)
{
webBrowser.Delegate = null;
webBrowser.StopLoading();
webBrowser.Dispose();
DismissViewController(true,delegate {
closeBrowser.TouchUpInside -= handleClose;
webBrowser.RemoveFromSuperview();
this.Dispose();
} );
}
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(true);
//webBrowser.RemoveFromSuperview();
}
public void webViewDidFinishLoad(UIWebView webView)
{
//string u = "";
}
protected override void Dispose(bool disposing)
{
ReleaseDesignerOutlets();
base.Dispose(disposing);
}
What am i missing?
Thank you!
Memory for native objects is not reclaimed when you call Dispose. Calling Dispose only drops the managed reference - but the ObjC runtime (reference counted) won't free the object until there's no native reference as well. See this Q&A for more details...
This means that code such as:
this.Add(webBrowser);
will create such a native reference and is likely (i.e. if not removed elsewhere) to keep the webBrowser instance alive as long as this is alive. If you keep Adding then you memory usage will keep growing.
I'm the OP - It seems that releasing the memory usage of UIWebView is quite hard, even when doing so in Objective-C.
What I have eventually done, which didn't solve the problem but improved the memory release is adding the following lines when closing the UIWebView:
NSUrlCache.SharedCache.RemoveAllCachedResponses();
NSUrlCache.SharedCache.DiskCapacity = 0;
NSUrlCache.SharedCache.MemoryCapacity = 0;
webView.LoadHtmlString("",null);
webView.EvaluateJavascript("var body=document.getElementsByTagName('body')[0];body.style.backgroundColor=(body.style.backgroundColor=='')?'white':'';");
webView.EvaluateJavascript("document.open();document.close()");
webView.StopLoading();
webView.Delegate = null;
webView.RemoveFromSuperview();
webView.Dispose();
In a scene of my quiz game I have an animation object that changes for another animation when a button to move to the next question is pressed (the button reload the scene). I would like to keep the animation, the last animation referenced to the object, after the scene is reloaded, but I don't know how. The object always returns to its normal state (the first animation).
I currently have a script called 'tower' referenced to the object where I make a static object and a DontDestroyOnLoad function:
public static SpriteRenderer towerAnimation;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
}
And this code in the Update of 'GameManager' script:
public static int counterQuestionChances = 2;
void DestroyTower()
{
if (counterQuestionChances == 1)
{
Tower.towerAnimation.SetTrigger("error 1");
}
else
{
if (counterQuestionChances == 0)
{
Tower.towerAnimation.SetTrigger("error 2");
}
}
But it doesn't work. I'm taking shots in the dark because I don't know how to solve this. I'd appreciate if you could give me any ideas that can help me with this. Thanks!
You're going to have to use the SceneManagement library that Unity has so when the scene changes the method below called OnActiveSceneChanged gets called.
using UnityEngine.SceneManagement;
public class Tower : MonoBehaviour
{
public static SpriteRenderer towerAnimation;
public int storedCounter = 0;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
}
private void OnActiveSceneChanged(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.Scene currentScene)
{
//tower animation stuff here
}
}