I'm trying to build a simple MQTT application. I want to display the received MQTT message in a 3dText with Unity.
I put the string assignment into the Update() function, but appearently when a message is received the Update() function is stopped. When i click somewhere in the editor the Update() function wake up and update the string.
C#
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Net;
using uPLibrary.Networking.M2Mqtt;
using uPLibrary.Networking.M2Mqtt.Messages;
using uPLibrary.Networking.M2Mqtt.Utility;
using uPLibrary.Networking.M2Mqtt.Exceptions;
using System;
public class mqttTest : MonoBehaviour {
private MqttClient client;
public TextMesh mytext=null;
string msg;
// Use this for initialization
void Start () {
// create client instance
client = new MqttClient(IPAddress.Parse("192.168.83.128"),1883 , false , null );
// register to message received
client.MqttMsgPublishReceived += client_MqttMsgPublishReceived;
string clientId = Guid.NewGuid().ToString();
client.Connect(clientId);
client.Subscribe(new string[] { "test" }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
}
void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
{
msg = System.Text.Encoding.UTF8.GetString(e.Message);
Debug.Log("Received: " + msg );
}
// Update is called once per frame
void Update () {
Debug.Log("update");
mytext.text = msg;
}
}
This stopping is due to the development environment or the event mechanism?
That's probably because Unity only executes the PlayMode (Update events etc) while the UnityEditor window and in specific the Game view is focused. If another window has or gains focus in the moment your message is received Unity freezes until the Game view of unity editor gains focus again.
You can fix this by going to the Player Settings → Resolution and Presentation → Resolution and enable the option
Run In Background
Enable this option to make the game keep running (rather than pausing) if the app loses focus.
Apparently this also applies to the player within UnityEditor itself.
However it only works/exists if your project target is set to Standalone or Web.
For iOS and Android this does not work because on those devices an app can not run in background. Unity automatically also applies the same behaviour to the player within UnityEditor itself.
But you can still get around it setting Application.runInBackground (which is basically what before mentioned option does)
Should the player be running when the application is in the background?
Default is false (application pauses when it is in the background).
directly from a component (attached to any Scene GameObject) like
public class EditorRunInBackground : MonoBehaviour
{
private void Awake ()
{
if (Application.isEditor) Application.runInBackground = true;
}
}
which only sets the runInBackground for the UnityEditor itself.
Alternatively if you don't want to attach it to anything you could also use a script with [RuntimeInitializeOnLoadMethod]
public static class EditorRunInBackground
{
[RuntimeInitializeOnLoadMethod]
private static void OnRuntimeMethodLoad()
{
if(Application.isEditor) Application.runInBackground = true;
}
}
and could even play it within an Editor folder so it gets stripped of in a build.
Related
I have a small scene setup with the UFPS asset from unity assetstore. When I load DIRECTLY the scene its working with less then 1 sec loading time, BUT when i load it from my menu the editor crashes. I also have a "loader" scene with the async method that one is working also so i think something went off with the button (I also try loading the async scene from menu and also try loading the game scene from menu crash each time) The same with builded versions I could't find ANY solutions. Here is the button's script (c#) :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class ButtonEvents : MonoBehaviour
{
[SerializeField]
public int selected;
public Button ok;
void Start()
{
Button okbtn = ok.GetComponent<Button>();
okbtn.onClick.AddListener(StartGame);
}
public void Quit()
{
Application.Quit();
}
public void markabreakdown()
{
selected = 1;
}
void Update()
{
Button okbtn = ok.GetComponent<Button>();
okbtn.onClick.AddListener(StartGame);
Debug.Log(selected);
}
public void StartGame()
{
SceneManager.LoadScene(selected);
}
}
Why do you use AddListener in Update -> adding a callback each and every frame?! When you click on that button you are trying to call the StartGame method hundreds of times depending how long you have spent in that scene .. and then most probably it tries to call that method the second time in a moment when the scene is already changed -> this button and this class already destroyed -> null ref exception.
Remove your entire Update method!
You already added the callback in Start
Further note that ok already is a Button so calling ok.GetComponent<Button>() is completely redundant. Simply do
void Start()
{
ok.onClick.AddListener(StartGame);
}
I'm creating a project using the Gear VR, where you can rotate an object and display information based on the swipe and tap controls on the side of the headset.
Everything works great, I can rotate and select stuff when I use the touchpad on the side of the Gear VR, but when I change scenes and return to the main menu, and then go back into the scene I was just on, the functionality stops working.
I am using this script I've made:
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
using System;
public class GearVRTouchpad : MonoBehaviour
{
public GameObject heart;
public float speed;
Rigidbody heartRb;
void Start ()
{
OVRTouchpad.Create();
OVRTouchpad.TouchHandler += Touchpad;
heartRb = heart.GetComponent<Rigidbody>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
SceneManager.LoadScene("Main Menu");
}
}
void Touchpad(object sender, EventArgs e)
{
var touches = (OVRTouchpad.TouchArgs)e;
switch (touches.TouchType)
{
case OVRTouchpad.TouchEvent.SingleTap:
// Do some stuff
break;
case OVRTouchpad.TouchEvent.Up:
// Do some stuff
break;
//etc for other directions
}
}
}
I've noticed that when I start my game, an OVRTouchpadHelper is created. I don't know if that has anything to do with my problem.
The error I am getting is:
MissingReferenceException: The object of type 'GearVRTouchpad' has
been destroyed but you are still trying to access it. Your script
should either check if it is null or you should not destroy the
object.
BUT I have not referenced this script anywhere else.
When I check my scene in play mode, the script is still there with the variable assignments still present.
Any help would be great!
OVRTouchpad.TouchHandler is a static EventHandler (so it will persist through the lifetime of the game). Your script is subscribing to it when it's created but isn't unsubscribing when it's destroyed. When you reload the scene the old subscription is still in the event but the old GearVRTouchpad instance is gone. This will result in the MissingReferenceException next time the TouchHandler event fires. Add this to your class:
void OnDestroy() {
OVRTouchpad.TouchHandler -= Touchpad;
}
Now, whenever a GameObject with the GearVRTouchpad behaviour is destroyed, the static event in OVRTouchpad will no longer have a reference to it.
I'm working with Unity 5.3 with C# as code editor
These are what I have :
I have 2 scenes in my project : home and options. I have bg object on both scenes. Both bg objects have Audio Source component, which contains same background music that play on awake. I don't use any codes for these background musics, I only click the Add Component button from Unity and add Audio Source.
This is what I want :
Options scene can toggle the background music on/off for all scenes. Therefore, there are btnOn and btnOff in Options scene.
This is my code in Audio Manager.cs :
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class AudioManager : MonoBehaviour {
public Button btnOn;
public Button btnOff;
// Use this for initialization
void Start () {
btnOn = GetComponent<Button>();
btnOff = GetComponent<Button>();
btnOn.onClick.AddListener(() => PlayAudio());
btnOff.onClick.AddListener(() => StopAudio());
}
void PlayAudio()
{
AudioSource.volume = 0.5f;
}
void StopAudio()
{
AudioSource.volume = 0f;
}
}
This is the problem :
I have this error : An object reference is required to access non-static member UnityEngine.AudioSource.volume. Maybe, this is because I don't write public AudioSource audioSource in my code. But, if I write this, I have to add another audio in Get Component box, and I will have double Audio Source in one scene. What should I do? Thanks
As you have a bg object in both scenes and as your AudioManager isn't marked as [DontDestroyOnLoad] (then I assume you also have one AudioManager in both scenes), it's Start() function will fire each time you load a scene.
So you can declare a private AudioSource and get a reference of it by finding your bg object in your scene and calling GetComponent on it :
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class AudioManager : MonoBehaviour
{
public Button btnOn;
public Button btnOff;
private AudioSource audioSource;
// Use this for initialization
void Start()
{
btnOn = GetComponent<Button>();
btnOff = GetComponent<Button>();
btnOn.onClick.AddListener(() => PlayAudio());
btnOff.onClick.AddListener(() => StopAudio());
audioSource = GameObject.Find("bg").GetComponent<AudioSource>();
}
void PlayAudio()
{
audioSource.volume = 0.5f;
}
void StopAudio()
{
audioSource.volume = 0f;
}
}
The error is raised because you need to assign the property on an individual object; the volume is not shared between sources. For this reason you will either need a field to assign in the inspector, or get a reference with GetComponent.
While using different scenes for handling options is not wrong, it is a tad clumsy; the current scene has to be unloaded (destroying all object not marked as DontDestroyOnLoad and information associated with them), after which the options are loaded, to then load the previous scene. While unloading the music most likely stops playing, which, after loading, starts at the beginning again. Not mention any settings on these objects are lost (volume, change of track, etc.).
The afore mentioned DontDestroyOnLoad can help since you make your changes on the same object, but you will have to deal with duplicates each time a scene is loaded where such an object exists... you can use the function OnLevelWasLoaded (documentation is a tad lacking at the moment) as a moment to determine which objects to destroy.
Another point is that you currently have public Button fields. This allows the for the assignment of them via the inspector, but that is rather moot as you overwrite them in Start (new value being the first button component assigned to the same object). I would make these fields private, or at least make sure they are not assigned. But I'm getting slightly of topic on how to keep settings persistent between scenes.
Here is some code to give you an idea, but be warned it is untested as I currently have no access to an environment to test it. This solution uses an object which is persistent between scenes. Keep in mind that any connections established to this object via the editor are lost after another scene has loaded.
public class AudioManager : MonoBehaviour
{
private AudioSource source;
// Called regardless of whether the object is enabled or not.
// Should not be called in a new scene.
private void Awake()
{
// Protect this object from being destroyed so its volume
// is maintained between scenes.
DontDestroyOnLoad(this.gameObject);
source = GetComponent<AudioSource>();
}
public void DestroyPossibleDuplicates()
{
AudioManager[] managers = FindObjectsOfType(typeof(AudioManager)) as AudioManager[];
foreach (AudioManager manager in managers)
{
// Use something to determine whether a manager is a duplicate.
// It must not be this, but have something in common; a name perhaps?
if ((manager != this) && (manager.gameObject.name == this.gameObject.name))
{
// Destroy the duplicates so their sound won't interfere.
Destroy(manager.gameObject);
}
}
}
private void BindToInterface()
{
Slider[] sliders = FindObjectsOfType(typeof(Slider)) as Slider[];
foreach (Slider slider in sliders)
{
// Determine whether the specified slider should have effect on this object.
// If the slider's name contains this object's name assume it should.
if (slider.gameObject.name.indexOf(this.gameObject.name)!=-1)
{
slider.onValueChanged.addListener((float value)=>
{
// In this case a slider is used for more control over the volume.
// Different elements require other logic to function.
source.volume = value;
});
}
}
}
// If my memory serves correct this method is only called on objects
// that were in the scene before it started loading.
// Just to be safe, don't have it do anything depending on this difference.
private void OnLevelWasLoaded()
{
DestroyPossibleDuplicates();
BindToInterface();
}
}
Still learning here and starting of with basics (just a plain Plane and moving as the first person around)
However i can run the app and look around and up and down etc. but can;t make the camera move when touching the touchpad on the GearVR headset.
I have created the script (c#) and attached to the camera in unity:
using UnityEngine;
using System.Collections;
public class Moving : MonoBehaviour {
// Use this for initialization
void Start()
{
if (Input.GetButton("Tap"))
{
// Do something if tap starts
}
if (Input.GetButtonUp("Tap"))
{
// Do something if tap ends
}
}
// Update is called once per frame
void Update () {
if (Input.GetButton("Tap"))
{
// Do something if tap starts
}
if (Input.GetButtonUp("Tap"))
{
// Do something if tap ends
}
}
}
But it still doesn't seem to work. When i build and run the app it does nothing :-(
I know i am doing something wrong but not sure what.
Handling Single Tap in Oculus Gear VR:
void Start()
{
OVRTouchpad.Create();
OVRTouchpad.TouchHandler += OVRTouchpad_TouchHandler;
}
void OVRTouchpad_TouchHandler (object sender, System.EventArgs e)
{
OVRTouchpad.TouchArgs touchArgs = (OVRTouchpad.TouchArgs)e;
OVRTouchpad.TouchEvent touchEvent = touchArgs.TouchType;
if(touchArgs.TouchType == OVRTouchpad.TouchEvent.SingleTap)
{
// Your response to Tap goes here.
}
}
Tap and Hold to Move:
You need to register Tapkey in your input following this
tutorial.
Add OVRPlayerController prefab to move around the scene. This will
let you move using keyboard W/A/S/D keys in Unity Editor.
Next you need to integrate Tap key with OVR Player controller script
to move in forward direction.
here are some useful links:
http://forum.unity3d.com/threads/gear-vr-touchpad-fps-script.373103/
http://rifty-business.blogspot.co.uk/2014/04/unity-pro-4-using-ovrcameracontroller.html
I'm new to IOS and just tried to make the simplest game just for test it on IOS Simulator.
Here is the all code
using UnityEngine;
using System.Collections;
public class Controller : MonoBehaviour {
private Rigidbody2D rb;
// Use this for initialization
void Start () {
rb = transform.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
if(Input.GetMouseButton(0) || Input.touchCount > 0)
{
rb.AddForce(Vector2.up, ForceMode2D.Impulse);
}
}
}
As you see, when user press the button or just touch the screen, some object fly up.
Of course in Unity it works fine, but when I make IOS build (with IOS Simulator SDK) and try to run it in XCODE it runs, but when I press a mouse button - controlled object does not fly up.
Here is the video of all that process.
What could be the problem? Why it doesn't work?