How to Run script when unity load just once? - c#

Here, I am looking for a piece of code in the Unity editor that will execute the initial panel of the created package only once when Unity is opened, but this code is executed in the initial frame every time I play Unity and then stop it, and it continuously shows the panel. Gives. I want it to be seen only once when the project is opened.
[InitializeOnLoad]
public class Autorun
{
static Autorun()
{
EditorApplication.update += RunOnce;
}
static void RunOnce()
{
Debug.Log("Once"); // but it will repeat every time I Clicking on play then stop it.
Panel.Init();
EditorApplication.update -= RunOnce;
}
}
Above is the code suggested by the user in Unity Answers, which was chosen as the best answer, but in fact, as I pointed out, it had a problem.

Although it was mentioned in the comment that the second answer in Unity answers solves the problem, after a while I noticed that the panel opens again when saving the code and I could not find a way to block it through another condition in EditorApplication. The solution below is the final method of solving the problem that uses EditorPrefs and I feel it necessary to share this method with you.
internal const string FIRST_TIME = "FIRST_TIME"; // the key
static Autorun()
{
EditorApplication.update += RunOnce;
EditorApplication.quitting += Quit;
}
private static void Quit() => EditorPrefs.DeleteKey(FIRST_TIME);
private static void RunOnce()
{
var firstTime = EditorPrefs.GetBool(FIRST_TIME, true);
Debug.Log(firstTime);
if (firstTime)
{
EditorPrefs.SetBool(FIRST_TIME, false);
if (EditorPrefs.GetBool(Panel.ShowOnStart, true)) Panel.Init();
}
EditorApplication.update -= RunOnce;
}
}

Related

Xamarin iOS app freezes: ViewDidAppear() never gets called

This seems to be a tricky one:
We're working on a Xamarin iOS app that has a UITableView control displaying a list of profiles. Once the user clicks on one of the profiles we'd like to switch to a separate "ProfileViewController" to display more detailed information. This works just fine for 99.9% of the time. In the remaining ~0.1% the item in the list gets highlighted (which happens OnClick) but the app just seemingly freezes and never switches to the other ViewController, leaving the user with an unresponsive list.
The interesting thing to note here is that the app doesn't really freeze, as the simple "swipe back" gesture brings the user back to the UITableView (to be clear the switch-to-profile-viewcontroller animation is never played so it basically switches from the unresponsive list back to the same list, but now it is responsive again).
The tricky thing is that we can't reliably reproduce this bug. It just seems to happen at random, sometimes while stuff is running in the background, other times while the app was previously in an idle state. We are pretty sure that it isn't related to multithreading (we triple-checked everything, using locking and semaphores where necessary), it rather seems to be some rendering issue (as you can still swipe back to the previous screen or at least it isn't your common dead lock).
Using a bunch of Console.WriteLine() tracers and hours of trial and error reproducing this bug we could isolate the problem and discovered the following:
Upon clicking on the list code in ViewDidLoad() and ViewWillAppear() is successfully executed. However ViewDidAppear() never gets invoked. There is nothing else happening in our code or on different threads between ViewWillAppear() and ViewDidAppear() and we don't have any funky / unusual code that gets executed previously (just the usual UI initialization like this in ViewDidLoad()):
...
LblProfileName.TextAlignment = UITextAlignment.Center;
LblProfileName.Text = string.Empty;
LblProfileName.Font = FontAgent.ForSize(30);
LblProfileSlogan.TextAlignment = UITextAlignment.Center;
LblProfileSlogan.Text = string.Empty;
LblProfileSlogan.Font = FontAgent.ForSize(20);
LblProfileRelationInfo.TextAlignment = UITextAlignment.Center;
LblProfileRelationInfo.Text = string.Empty;
LblProfileRelationInfo.Font = FontAgent.ForSize(15);
...
At this point we are kinda out of ideas as to what could be going wrong here and we have independently reviewed any of our code that could remotely be involved in this bug but we found nothing.
We didn't find anything related online but maybe someone else has encountered a similar issue like this in Xamarin / Xamarin iOS before?
Are there any steps we could take that we don't know of? When breaking the app in the Visual Studio for Mac debugger during the freezes the call stacks only contain native code and are not of much use.
Any help or ideas as to what else we could try are hugely appreciated :)
Edit: Adding some code
This is our BaseViewController defining some initialization methods to be used by it's children (again in 99.9% of all cases this works just fine):
public abstract class BaseViewController : UIViewController
{
public BaseViewController(string nibName, NSBundle nSBundle) : base(nibName, nSBundle)
{
ControllerDidInitialize();
}
public ClubmappViewController(IntPtr handle) : base(handle)
{
ControllerDidInitialize();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
CustomOrientationService.ScreenRotationPortrait();
InitializeStaticContent();
Console.WriteLine("ViewDidLoad() exits just fine...");
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
Console.WriteLine("When the bug occurs this never gets executed :C");
RefreshUI();
OnViewDidAppear?.Invoke(this, new EventArgs());
LoadData();
}
private protected abstract void InitializeStaticContent();
private protected abstract void RefreshUI();
private protected virtual void LoadData()
{
}
private protected virtual void ControllerDidInitialize()
{
}
}
This is the ProfileViewController that inherits from BaseViewController and that just stops being rendered or inititialized or whatever the actual problem might be (it just never shows up as described above) but most of the time it works just fine:
public partial class ProfileViewController : BaseViewController
{
public const string STORYBOARD_ID = "ProfileViewController";
public ProfileViewController(IntPtr handle) : base(handle)
{
}
private protected override void ControllerDidInitialize()
{
// do initialization things like initializing variables, etc
// no real logic here
}
private protected override void InitializeStaticContent()
{
// layouting loading
LblProfileTitle.TextAlignment = UITextAlignment.Center;
LblProfileTitle.Text = string.Empty;
LblProfileTitle.Font = FontAgent.ForSize(20);
LblProfileTitle.Font = UIFont.BoldSystemFontOfSize(20);
LblProfileName.TextAlignment = UITextAlignment.Center;
LblProfileName.Text = string.Empty;
LblProfileName.Font = FontAgent.ForSize(30);
LblProfileSlogan.TextAlignment = UITextAlignment.Center;
LblProfileSlogan.Text = string.Empty;
LblProfileSlogan.Font = FontAgent.ForSize(20);
// ... and so on ..
}
private protected override void RefreshUI()
{
// ... theme related stuff ...
ViewProfileActive.BackgroundColor = ThemeAgent.CurrentTheme.OnlineIndicatorColor;
LblProfileName.TextColor = ThemeAgent.CurrentTheme.PrimaryTextColor;
LblProfileSlogan.TextColor = ThemeAgent.CurrentTheme.SecondaryTextColor;
// ...
}
private protected async override void LoadData()
{
// load user data ...
ProfileData data = await ...
}
}
And this is the "OnClick" event that is triggered when a profile is clicked on, that's supposed to initialize and show the ProfileViewController (it's unlikely that something's wrong with this but including it nonetheless):
// ...
(sender, e) =>
{
ProfileViewController profileController = (ProfileViewController)UIStoryboard.FromName("Main", null).InstantiateViewController(ProfileViewController.STORYBOARD_ID);
profileController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
currentViewController.NavigationController.PushViewController(profileController, true);
}
// ...

Unity method only runs first line of code

I've AdMob test ads fully working in my project.
When the ad is watched the below code should run, however only the first line is being executed, the 2 other lines are being ignored with no error.
public void HandleUserEarnedReward(object sender, Reward args)
{
GameControl.control.life += 1;
GameControl.control.Save();
txtLife.text = GameControl.control.life.ToString();
}
I've placed the same code in another method that I trigger with a button to test.
In this instance the full method is run.
public void runtest()
{
GameControl.control.life += 1;
GameControl.control.Save();
txtLife.text = GameControl.control.life.ToString();
}
If i'm not wrong you are trying to give reward after User watches rewarded video. I had the same problem one time, the problem is that functions that are executing inside of "HandleUserEarnedReward" will NOT be executed on unity's MainThread, but on Google's SDK thread.
There are several solutions:
https://github.com/PimDeWitte/UnityMainThreadDispatcher - Switch to main thread using this. Check readme file to more info.
Create global booleans with false value. Then on "HandleUserEarnedReward" change "isRewarded" boolean to true. Create Update function to check boolean value. Something like:
void Update()
{
if (isRewarded)
{
// do all the actions
// reward the player
isRewarded = false; // to make sure this action will happen only once.
}
}
Use Coroutine. Coroutines autoMagically switch to Unity's MainThread after "yield return"
public void HandleRewardBasedVideoRewarded(object sender, Reward args)
{
string type = args.Type;
double amount = args.Amount;
Debug.Log(
"HandleRewardBasedVideoRewarded event received for "
+ amount.ToString() + " " + type);
StartCoroutine(AfunctionName());
}
IEnumerator AfunctionName()
{
yield return new WaitForSecondsRealtime(0.1f);
// FB.LogAppEvent("AdmobRewardedView");
Debug.Log("Reward Function Called!!!!!");
GiveReward();
this.RequestRewardBasedVideo();
}

MultiSourceFrameArrived -= is not working. How can I disable it?

I´m working on a Kinect project. I'm recording data from the received frames. When I have to process the frame data, the program is taking a lot of time. In the meanwhile, I want to disable the EventHandler MultiSourceFrameArrived.
The thing is, I have been reading different posts, I can't find an answer that fits my problem. The expression -= seems to work only if it is in the same scope as the expression +=. When I write them in different scopes, the frames are still arriving and I can't disable that event handler.
The NON WORKING code is this one:
private void MainWindow()
{
//Intitalize components
if (this.multiSourceFrameReader != null)
{
EnableFrameArrived();
}
}
private void MultiSourceFrameReader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
{
DisableFrameArrived();
}
private void DisableFrameArrived()
{
this.multiSourceFrameReader.MultiSourceFrameArrived -= this.MultiSourceFrameReader_MultiSourceFrameArrived;
//This doesn`t cancel my suscription to the event.
}
private void EnableFrameArrived()
{
this.multiSourceFrameReader.MultiSourceFrameArrived += MultiSourceFrameReader_MultiSourceFrameArrived;
}
The WORKING code is this one:
private void MainWindow()
{
//Intitalize components
if (this.multiSourceFrameReader != null)
{
this.multiSourceFrameReader.MultiSourceFrameArrived += this.MultiSourceFrameReader_MultiSourceFrameArrived;
//I subscribe to the event
}
this.multiSourceFrameReader.MultiSourceFrameArrived -= this.MultiSourceFrameReader_MultiSourceFrameArrived;
//I cancel my subscription. But I need to cancel my subscription in another scope.
}
I commented the rest of the code and just left this part running. I keep having incomings frames even though the Disable Method is reached. Why the cancellation to my event is only possible if I'm in the same scope? I`ve reading different blogs but I can't solve this.
Any suggestions?
Thanks!

Unity - C# - NullReferenceException: Object reference not set to an instance of an object [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
EDIT
My question is different (I think..) because the last image allows me to set a GameObject to the Communication Message and Communication Message. BUT, on play, it immediately resets to None (Text) and None (Button). I don't know why this happens or how to solve this!
I am aware this question is widely covered but still I cannot solve this. I hope someone has a solution for me.
What I have
I am working with Behavior Designer, an asset for Unity. I'm making Behavior Trees and the problem occurred when using a behavior tree reference.
First, I had my Behavior Tree like this:
It searches the front door. If it is found, it will move towards it and communicate with the human playing the game.
This worked before, but now I put this behavior tree in a Behavior Tree Reference, like this:
When I double click the reference, the first image shows. BUT, where it goes wrong, is this:
Problem
This is the human instructions node in the first picture. It doesn't load the communication message and communication button. When I load the corresponding button, it immediately resets on playing the scenario. This happened when I loaded this behavior in the Behavior Tree Reference, and the problem didn't occur when I played this from the original tree self.
NullReferenceException: Object reference not set to an instance of an object
HumanInstructions.CommunicationElements (Boolean activeOrNot) (at Assets/HumanInstructions.cs:54)
HumanInstructions.OnAwake () (at Assets/HumanInstructions.cs:19)
BehaviorDesigner.Runtime.BehaviorManager.EnableBehavior (BehaviorDesigner.Runtime.Behavior behavior)
BehaviorDesigner.Runtime.Behavior.EnableBehavior ()
BehaviorDesigner.Runtime.Behavior.Start ()
Any ideas what could cause this and how to solve this?
The code from HumanInstructions
using UnityEngine;
using UnityEngine.UI;
using BehaviorDesigner.Runtime;
using BehaviorDesigner.Runtime.Tasks;
using UnityStandardAssets.Characters.FirstPerson;
public class HumanInstructions : Action
{
public string humanInstructionsText; // The string in inspector that shows up on-screen for the human operator to communicate with UGV.
public string messageToConsole; // Print this message to console when the action is performed SUCCESSFUL.
public string textOnButton; // See inspector in Behavior Designer. Is used as text on button.
public Text CommunicationMessage;
public Button CommunicationButton;
bool boolClicked; // Is false; when the button is clicked, it will turn TRUE, calling the IF function, returning Taskstatus SUCCESS.
public override void OnAwake ()
{
CommunicationElements (false);
}
public override void OnStart ()
{
boolClicked = false;
CommunicationElements (false);
CommunicationButton.onClick.AddListener (ButtonClicked);
}
public override TaskStatus OnUpdate ()
{
CommunicationMessage.text = humanInstructionsText;
CommunicationButton.GetComponentInChildren<Text> ().text = textOnButton;
CommunicationElements (true); // The communication elements are VISIBLE on screen.
TriggerStatusCameraView (false);
if (boolClicked == true) { // this IF function is active when the button is clicked. See ButtonClicked () function.
CommunicationElements (false); // Removes the communication elements from screen.
TriggerStatusCameraView (true);
return TaskStatus.Success;
} else {
return TaskStatus.Running;
}
}
// The following function is called when the CommunicationButton is clicked on screen.
void ButtonClicked ()
{
boolClicked = true; // Changes the value to true, so it will trigger the IF function in OnUpdate ();
Debug.Log (messageToConsole); // Sends this message to the console.
}
// The following function can be called upon and turn all UI elements (such as text, buttons or images) ACTIVE or not.
void CommunicationElements (bool activeOrNot)
{
CommunicationButton.gameObject.SetActive (activeOrNot);
CommunicationMessage.gameObject.SetActive (activeOrNot);
}
// The following code will DISABLE camera control if the communication screen is active for the human operator
void TriggerStatusCameraView(bool activeOrNot)
{
GameObject.Find ("FPSController").GetComponent<RigidbodyFirstPersonController_custom> ().enabled = activeOrNot;
}
}
The solution was simple. Thanks for looking into this.
Text CommunicationMessage = GameObject.Find("CrazyMsg").GetComponent<Text>();
Button CommunicationButton = GameObject.Find("MissionButton").GetComponent<Button>();

C# speech recognition (System.Speech.Recognition) issues

I've been working with a bit of speech recognition for a few days with various test programs and it's all worked fine. However i've tried implementing it into my OpenGL project and the function 'Recognized' is now not being called.
Up in the Windows Speech Recognition thing (the thing that says "try saying 'Start Listening'" an awful lot), words that are loaded appear when i say them, so I am assuming that it is correctly detecting words, it's just for some reason not triggering the event.
Here's the code i've been using. All you really need to know (besides what is shown in the code), is that AddCommands is called somewhere else, to add in a few words that i've been testing with and that 'Initiate' is called upon the loading of the form.
public class SpeechControls
{
public static SpeechRecognizer sRecognizer;
private static Dictionary<string, IVoiceControlable> controllers = new Dictionary<string, IVoiceControlable>();
public static void Initiate()
{
sRecognizer = new SpeechRecognizer();
sRecognizer.Enabled = true;
sRecognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(Recognized);
}
private static void Recognized(object obj, SpeechRecognizedEventArgs args)
{
controllers[args.Result.Text].TriggerCommand(args.Result.Text);
}
public static void AddCommands(string[] commands, IVoiceControlable control)
{
foreach (string str in commands)
{
controllers.Add(str, control);
}
sRecognizer.LoadGrammar(new Grammar(new GrammarBuilder(new Choices(commands))));
}
}
Does anyone know why 'Recognized' would not be triggered?
Thanks for any help, much appreciated.
Because OpenGL runs of game loops rather than event listening, the thread is completely taken up by the loop. To start listening for commands a second thread is needed.

Categories

Resources