In the new Unity3D UI (Unity > 4.6), I'm trying to create a simple script I can attach to a UI component (Image, Text, etc) that will allow me to wedge in a custom tooltip handler. So what I need is to capture a PointerEnter and PointerExit on my component. So far I'm doing the following with no success. I'm seeing the EVentTrigger component show up but can't get my delegates to fire to save my life.
Any ideas?
public class TooltipTrigger : MonoBehaviour {
public string value;
void Start() {
EventTrigger et = this.gameObject.GetComponent<EventTrigger>();
if (et == null)
et = this.gameObject.AddComponent<EventTrigger>();
EventTrigger.Entry entry;
UnityAction<BaseEventData> call;
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerEnter;
call = new UnityAction<BaseEventData>(pointerEnter);
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(call);
et.delegates.Add(entry);
entry = new EventTrigger.Entry();
entry.eventID = EventTriggerType.PointerExit;
call = new UnityAction<BaseEventData>(pointerExit);
entry.callback = new EventTrigger.TriggerEvent();
entry.callback.AddListener(call);
et.delegates.Add(entry);
}
private void pointerEnter(BaseEventData eventData) {
print("pointer enter");
}
private void pointerExit(BaseEventData eventData) {
print("pointer exit");
}
}
Also... the other method I can find when poking around the forums and documentations is to add event handlers via interface implementations such as:
public class TooltipTrigger : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
public string value;
public void OnPointerEnter(PointerEventData data) {
Debug.Log("Enter!");
}
public void OnPointerExit(PointerEventData data) {
Debug.Log("Exit!");
}
}
Neither of these methods seems to be working for me.
Second method (implementation of IPointerEnterHandler and IPointerExitHandler interfaces) is what you're looking for. But to trigger OnPointerEnter and OnPointerExit methods your scene must contain GameObject named "EventSystem" with EventSystem-component (this GameObject created automatically when you add any UI-element to the scene, and if its not here - create it by yourself) and components for different input methods (such as StandaloneInputModule and TouchInputModule).
Also Canvas (your button's root object with Canvas component) must have GraphicRaycaster component to be able to detect UI-elements by raycasting into them.
I just tested code from your post and its works just fine.
Related
How can I pass score value from one scene to another?
I've tried the following:
Scene one:
void Start () {
score = 0;
updateScoreView ();
StartCoroutine (DelayLoadlevel(20));
}
public void updateScoreView(){
score_text.text = "The Score: "+ score;
}
public void AddNewScore(int NewscoreValue){
score = score + NewscoreValue;
updateScoreView ();
}
IEnumerator DelayLoadlevel(float seconds){
yield return new WaitForSeconds(10);
secondsLeft = seconds;
loadingStart = true;
do {
yield return new WaitForSeconds(1);
} while(--secondsLeft >0);
// here I should store my last score before move to level two
PlayerPrefs.SetInt ("player_score", score);
Application.LoadLevel (2);
}
Scene two:
public Text score_text;
private int old_score;
// Use this for initialization
void Start () {
old_score = PlayerPrefs.GetInt ("player_score");
score_text.text = "new score" + old_score.ToString ();
}
but nothing displayed on screen, and there's no error.
Is this the correct way to pass data ?
I am using Unity 5 free edition, develop game for Gear VR (meaning the game will run in android devices).
Any suggestion?
There are many ways to do this but the solution to this depends on the type of data you want to pass between scenes. Components/Scripts and GameObjects are destroyed when new scene is loaded and even when marked as static.
In this answer you can find
Use the static keyword
Use DontDestroyOnLoad
Store the data local
3a PlayerPrefs
3b serialize to XML/JSON/Binary and use FileIO
1. Use the static keyword.
Use this method if the variable to pass to the next scene is not a component, does not inherit from MonoBehaviour and is not a GameObject then make the variable to be static.
Built-in primitive data types such as int, bool, string, float, double. All those variables can be made a static variable.
Example of built-in primitive data types that can be marked as static:
static int counter = 0;
static bool enableAudio = 0;
static float timer = 100;
These should work without problems.
Example of Objects that can be marked as static:
public class MyTestScriptNoMonoBehaviour
{
}
then
static MyTestScriptNoMonoBehaviour testScriptNoMono;
void Start()
{
testScriptNoMono = new MyTestScriptNoMonoBehaviour();
}
Notice that the class does not inherit from MonoBehaviour. This should work.
Example of Objects that cannot be marked as static:
Anything that inherits from Object, Component or GameObject will not work.
1A.Anything that inherits from MonoBehaviour
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
This will not work because it inherits from MonoBehaviour.
1B.All GameObject:
static GameObject obj;
void Start()
{
obj = new GameObject("My Object");
}
This will not work either because it is a GameObject and GameObject inherit from an Object.
Unity will always destroy its Object even if they are declared with the static keyword.
See #2 for a workaround.
2.Use the DontDestroyOnLoad function.
You only need to use this if the data to keep or pass to the next scene inherits from Object, Component or is a GameObject. This solves the problem described in 1A and 1B.
You can use it to make this GameObject not to destroy when scene unloads:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
You can even use it with the static keyword solve problem from 1A and 1B:
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
The testScript variable will now be preserved when new scene loads.
3.Save to local storage then load during next scene.
This method should be used when this is a game data that must be preserved when the game is closed and reopened. Example of this is the player high-score, the game settings such as music volume, objects locations, joystick profile data and so on.
Thare are two ways to save this:
3A.Use the PlayerPrefs API.
Use if you have just few variables to save. Let's say player score:
int playerScore = 80;
And we want to save playerScore:
Save the score in the OnDisable function
void OnDisable()
{
PlayerPrefs.SetInt("score", playerScore);
}
Load it in the OnEnable function
void OnEnable()
{
playerScore = PlayerPrefs.GetInt("score");
}
3B.Serialize the data to json, xml or binaray form then save using one of the C# file API such as File.WriteAllBytes and File.ReadAllBytes to save and load files.
Use this method if there are many variables to save.
General, you need to create a class that does not inherit from MonoBehaviour. This class you should use to hold your game data so that in can be easily serialized or de-serialized.
Example of data to save:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Grab the DataSaver class which is a wrapper over File.WriteAllBytes and File.ReadAllBytes that makes saving data easier from this post.
Create new instance:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
Save data from PlayerInfo to a file named "players":
DataSaver.saveData(saveData, "players");
Load data from a file named "players":
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
There is another way:
ScriptableObject
ScriptableObjects are basically data containers but may also implement own logic. They "live" only in the Assets like prefabs. They can not be used to store data permanently, but they store the data during one session so they can be used to share data and references between Scenes ... and - something I also often needed - between Scenes and an AnimatorController!
Script
First you need a script similar to MonoBehaviours. A simple example of a ScriptableObject might look like
// fileName is the default name when creating a new Instance
// menuName is where to find it in the context menu of Create
[CreateAssetMenu(fileName = "Data", menuName = "Examples/ExamoleScriptableObject")]
public class ExampleScriptableObject : ScriptableObject
{
public string someStringValue = "";
public CustomDataClass someCustomData = null;
public Transform someTransformReference = null;
// Could also implement some methods to set/read data,
// do stuff with the data like parsing between types, fileIO etc
// Especially ScriptableObjects also implement OnEnable and Awake
// so you could still fill them with permanent data via FileIO at the beginning of your app and store the data via FileIO in OnDestroy !!
}
// If you want the data to be stored permanently in the editor
// and e.g. set it via the Inspector
// your types need to be Serializable!
//
// I intentionally used a non-serializable class here to show that also
// non Serializable types can be passed between scenes
public class CustomDataClass
{
public int example;
public Vector3 custom;
public Dictionary<int, byte[]> data;
}
Create Instances
You can create instances of ScriptableObject either via script
var scriptableObject = ScriptableObject.CreateInstance<ExampleScriptableObject>();
or to make things easier use the [CreateAssetMenu] as shown in the example above.
As this created ScriptabeObject instance lives in the Assets it is not bound to a scene and can therefore be referenced everywhere!
This when you want to share the data between two Scenes or also e.g. the Scene and an AnimatorController all you need to do is reference this ScriptableObject instance in both.
Fill Data
I often use e.g. one component to fill the data like
public class ExampleWriter : MonoBehaviour
{
// Here you drag in the ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void StoreData(string someString, int someInt, Vector3 someVector, List<byte[]> someDatas)
{
example.someStringValue = someString;
example.someCustomData = new CustomDataClass
{
example = someInt;
custom = someVector;
data = new Dictionary<int, byte[]>();
};
for(var i = 0; i < someDatas.Count; i++)
{
example.someCustomData.data.Add(i, someDatas[i]);
}
example.someTransformReference = transform;
}
}
Consume Data
So after you have written and stored your required data into this ExampleScriptableObject instance every other class in any Scene or AnimatorController or also other ScriptableObjects can read this data on just the same way:
public class ExmpleConsumer : MonoBehaviour
{
// Here you drag in the same ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void ExampleLog()
{
Debug.Log($"string: {example.someString}", this);
Debug.Log($"int: {example.someCustomData.example}", this);
Debug.Log($"vector: {example.someCustomData.custom}", this);
Debug.Log($"data: There are {example.someCustomData.data.Count} entries in data.", this);
Debug.Log($"The data writer {example.someTransformReference.name} is at position {example.someTransformReference.position}", this);
}
}
Persistence
As said the changes in a ScriptableObject itself are only in the Unity Editor really persistent.
In a build they are only persistent during the same session.
Therefore if needed I often combine the session persistence with some FileIO (as described in this answer's section 3b) for loading and deserializing the values once at session begin (or whenever needed) from the hard drive and serialize and store them to a file once on session end (OnApplicationQuit) or whenever needed.
(This won't work with references of course.)
Besides playerPrefs another dirty way is to preserve an object during level loading by calling DontDestroyOnLoad on it.
DontDestroyOnLoad (transform.gameObject);
Any script attached to the game object will survive and so will the variables in the script.
The DontDestroyOnLoad function is generally used to preserve an entire GameObject, including the components attached to it, and any child objects it has in the hierarchy.
You could create an empty GameObject, and place only the script containing the variables you want preserved on it.
I use a functional approach I call Stateless Scenes.
using UnityEngine;
public class MySceneBehaviour: MonoBehaviour {
private static MySceneParams loadSceneRegister = null;
public MySceneParams sceneParams;
public static void loadMyScene(MySceneParams sceneParams, System.Action<MySceneOutcome> callback) {
MySceneBehaviour.loadSceneRegister = sceneParams;
sceneParams.callback = callback;
UnityEngine.SceneManagement.SceneManager.LoadScene("MyScene");
}
public void Awake() {
if (loadSceneRegister != null) sceneParams = loadSceneRegister;
loadSceneRegister = null; // the register has served its purpose, clear the state
}
public void endScene (MySceneOutcome outcome) {
if (sceneParams.callback != null) sceneParams.callback(outcome);
sceneParams.callback = null; // Protect against double calling;
}
}
[System.Serializable]
public class MySceneParams {
public System.Action<MySceneOutcome> callback;
// + inputs of the scene
}
public class MySceneOutcome {
// + outputs of the scene
}
You can keep global state in the caller's scope, so scene inputs and outputs states can be minimized (makes testing easy). To use it you can use anonymous functions:-
MyBigGameServices services ...
MyBigGameState bigState ...
Splash.loadScene(bigState.player.name, () => {
FirstLevel.loadScene(bigState.player, (firstLevelResult) => {
// do something else
services.savePlayer(firstLevelResult);
})
)}
More info at https://corepox.net/devlog/unity-pattern:-stateless-scenes
There are various way, but assuming that you have to pass just some basic data, you can create a singelton instance of a GameController and use that class to store the data.
and, of course DontDestroyOnLoad is mandatory!
public class GameControl : MonoBehaviour
{
//Static reference
public static GameControl control;
//Data to persist
public float health;
public float experience;
void Awake()
{
//Let the gameobject persist over the scenes
DontDestroyOnLoad(gameObject);
//Check if the control instance is null
if (control == null)
{
//This instance becomes the single instance available
control = this;
}
//Otherwise check if the control instance is not this one
else if (control != this)
{
//In case there is a different instance destroy this one.
Destroy(gameObject);
}
}
Here is the full tutorial with some other example.
you have several options.
The first one I see is to use static variables, which you will not lose their information or value passing from scenes to scenes (since they are not bound to the object). [you lose the information when closing the game, but not when passing between scenes]
the second option is that the player or the object of which you do not want to lose the information, you pass it through the DontDestroyOnLoad function
Here I give you the documentation and the sample code. [You lose the information when you close the game, but not when you go between scenes]
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
Third is to use the playerPrefab [https://docs.unity3d.com/ScriptReference/PlayerPrefs.html]
that allow you to save information and retrieve it at any time without hanging it even after closing the game [you must be very careful with the latter if you plan to use it to save data even after closing the game since you can lose the data if you close the game suddenly , since player prefab creates a file and retrieves the information from there, but it saves the file at the end or closes the app correctly]
How can I pass score value from one scene to another?
I've tried the following:
Scene one:
void Start () {
score = 0;
updateScoreView ();
StartCoroutine (DelayLoadlevel(20));
}
public void updateScoreView(){
score_text.text = "The Score: "+ score;
}
public void AddNewScore(int NewscoreValue){
score = score + NewscoreValue;
updateScoreView ();
}
IEnumerator DelayLoadlevel(float seconds){
yield return new WaitForSeconds(10);
secondsLeft = seconds;
loadingStart = true;
do {
yield return new WaitForSeconds(1);
} while(--secondsLeft >0);
// here I should store my last score before move to level two
PlayerPrefs.SetInt ("player_score", score);
Application.LoadLevel (2);
}
Scene two:
public Text score_text;
private int old_score;
// Use this for initialization
void Start () {
old_score = PlayerPrefs.GetInt ("player_score");
score_text.text = "new score" + old_score.ToString ();
}
but nothing displayed on screen, and there's no error.
Is this the correct way to pass data ?
I am using Unity 5 free edition, develop game for Gear VR (meaning the game will run in android devices).
Any suggestion?
There are many ways to do this but the solution to this depends on the type of data you want to pass between scenes. Components/Scripts and GameObjects are destroyed when new scene is loaded and even when marked as static.
In this answer you can find
Use the static keyword
Use DontDestroyOnLoad
Store the data local
3a PlayerPrefs
3b serialize to XML/JSON/Binary and use FileIO
1. Use the static keyword.
Use this method if the variable to pass to the next scene is not a component, does not inherit from MonoBehaviour and is not a GameObject then make the variable to be static.
Built-in primitive data types such as int, bool, string, float, double. All those variables can be made a static variable.
Example of built-in primitive data types that can be marked as static:
static int counter = 0;
static bool enableAudio = 0;
static float timer = 100;
These should work without problems.
Example of Objects that can be marked as static:
public class MyTestScriptNoMonoBehaviour
{
}
then
static MyTestScriptNoMonoBehaviour testScriptNoMono;
void Start()
{
testScriptNoMono = new MyTestScriptNoMonoBehaviour();
}
Notice that the class does not inherit from MonoBehaviour. This should work.
Example of Objects that cannot be marked as static:
Anything that inherits from Object, Component or GameObject will not work.
1A.Anything that inherits from MonoBehaviour
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
This will not work because it inherits from MonoBehaviour.
1B.All GameObject:
static GameObject obj;
void Start()
{
obj = new GameObject("My Object");
}
This will not work either because it is a GameObject and GameObject inherit from an Object.
Unity will always destroy its Object even if they are declared with the static keyword.
See #2 for a workaround.
2.Use the DontDestroyOnLoad function.
You only need to use this if the data to keep or pass to the next scene inherits from Object, Component or is a GameObject. This solves the problem described in 1A and 1B.
You can use it to make this GameObject not to destroy when scene unloads:
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
You can even use it with the static keyword solve problem from 1A and 1B:
public class MyTestScript : MonoBehaviour
{
}
then
static MyTestScript testScript;
void Awake()
{
DontDestroyOnLoad(transform.gameObject);
}
void Start()
{
testScript = gameObject.AddComponent<MyTestScript>();
}
The testScript variable will now be preserved when new scene loads.
3.Save to local storage then load during next scene.
This method should be used when this is a game data that must be preserved when the game is closed and reopened. Example of this is the player high-score, the game settings such as music volume, objects locations, joystick profile data and so on.
Thare are two ways to save this:
3A.Use the PlayerPrefs API.
Use if you have just few variables to save. Let's say player score:
int playerScore = 80;
And we want to save playerScore:
Save the score in the OnDisable function
void OnDisable()
{
PlayerPrefs.SetInt("score", playerScore);
}
Load it in the OnEnable function
void OnEnable()
{
playerScore = PlayerPrefs.GetInt("score");
}
3B.Serialize the data to json, xml or binaray form then save using one of the C# file API such as File.WriteAllBytes and File.ReadAllBytes to save and load files.
Use this method if there are many variables to save.
General, you need to create a class that does not inherit from MonoBehaviour. This class you should use to hold your game data so that in can be easily serialized or de-serialized.
Example of data to save:
[Serializable]
public class PlayerInfo
{
public List<int> ID = new List<int>();
public List<int> Amounts = new List<int>();
public int life = 0;
public float highScore = 0;
}
Grab the DataSaver class which is a wrapper over File.WriteAllBytes and File.ReadAllBytes that makes saving data easier from this post.
Create new instance:
PlayerInfo saveData = new PlayerInfo();
saveData.life = 99;
saveData.highScore = 40;
Save data from PlayerInfo to a file named "players":
DataSaver.saveData(saveData, "players");
Load data from a file named "players":
PlayerInfo loadedData = DataSaver.loadData<PlayerInfo>("players");
There is another way:
ScriptableObject
ScriptableObjects are basically data containers but may also implement own logic. They "live" only in the Assets like prefabs. They can not be used to store data permanently, but they store the data during one session so they can be used to share data and references between Scenes ... and - something I also often needed - between Scenes and an AnimatorController!
Script
First you need a script similar to MonoBehaviours. A simple example of a ScriptableObject might look like
// fileName is the default name when creating a new Instance
// menuName is where to find it in the context menu of Create
[CreateAssetMenu(fileName = "Data", menuName = "Examples/ExamoleScriptableObject")]
public class ExampleScriptableObject : ScriptableObject
{
public string someStringValue = "";
public CustomDataClass someCustomData = null;
public Transform someTransformReference = null;
// Could also implement some methods to set/read data,
// do stuff with the data like parsing between types, fileIO etc
// Especially ScriptableObjects also implement OnEnable and Awake
// so you could still fill them with permanent data via FileIO at the beginning of your app and store the data via FileIO in OnDestroy !!
}
// If you want the data to be stored permanently in the editor
// and e.g. set it via the Inspector
// your types need to be Serializable!
//
// I intentionally used a non-serializable class here to show that also
// non Serializable types can be passed between scenes
public class CustomDataClass
{
public int example;
public Vector3 custom;
public Dictionary<int, byte[]> data;
}
Create Instances
You can create instances of ScriptableObject either via script
var scriptableObject = ScriptableObject.CreateInstance<ExampleScriptableObject>();
or to make things easier use the [CreateAssetMenu] as shown in the example above.
As this created ScriptabeObject instance lives in the Assets it is not bound to a scene and can therefore be referenced everywhere!
This when you want to share the data between two Scenes or also e.g. the Scene and an AnimatorController all you need to do is reference this ScriptableObject instance in both.
Fill Data
I often use e.g. one component to fill the data like
public class ExampleWriter : MonoBehaviour
{
// Here you drag in the ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void StoreData(string someString, int someInt, Vector3 someVector, List<byte[]> someDatas)
{
example.someStringValue = someString;
example.someCustomData = new CustomDataClass
{
example = someInt;
custom = someVector;
data = new Dictionary<int, byte[]>();
};
for(var i = 0; i < someDatas.Count; i++)
{
example.someCustomData.data.Add(i, someDatas[i]);
}
example.someTransformReference = transform;
}
}
Consume Data
So after you have written and stored your required data into this ExampleScriptableObject instance every other class in any Scene or AnimatorController or also other ScriptableObjects can read this data on just the same way:
public class ExmpleConsumer : MonoBehaviour
{
// Here you drag in the same ScriptableObject instance via the Inspector in Unity
[SerializeField] private ExampleScriptableObject example;
public void ExampleLog()
{
Debug.Log($"string: {example.someString}", this);
Debug.Log($"int: {example.someCustomData.example}", this);
Debug.Log($"vector: {example.someCustomData.custom}", this);
Debug.Log($"data: There are {example.someCustomData.data.Count} entries in data.", this);
Debug.Log($"The data writer {example.someTransformReference.name} is at position {example.someTransformReference.position}", this);
}
}
Persistence
As said the changes in a ScriptableObject itself are only in the Unity Editor really persistent.
In a build they are only persistent during the same session.
Therefore if needed I often combine the session persistence with some FileIO (as described in this answer's section 3b) for loading and deserializing the values once at session begin (or whenever needed) from the hard drive and serialize and store them to a file once on session end (OnApplicationQuit) or whenever needed.
(This won't work with references of course.)
Besides playerPrefs another dirty way is to preserve an object during level loading by calling DontDestroyOnLoad on it.
DontDestroyOnLoad (transform.gameObject);
Any script attached to the game object will survive and so will the variables in the script.
The DontDestroyOnLoad function is generally used to preserve an entire GameObject, including the components attached to it, and any child objects it has in the hierarchy.
You could create an empty GameObject, and place only the script containing the variables you want preserved on it.
I use a functional approach I call Stateless Scenes.
using UnityEngine;
public class MySceneBehaviour: MonoBehaviour {
private static MySceneParams loadSceneRegister = null;
public MySceneParams sceneParams;
public static void loadMyScene(MySceneParams sceneParams, System.Action<MySceneOutcome> callback) {
MySceneBehaviour.loadSceneRegister = sceneParams;
sceneParams.callback = callback;
UnityEngine.SceneManagement.SceneManager.LoadScene("MyScene");
}
public void Awake() {
if (loadSceneRegister != null) sceneParams = loadSceneRegister;
loadSceneRegister = null; // the register has served its purpose, clear the state
}
public void endScene (MySceneOutcome outcome) {
if (sceneParams.callback != null) sceneParams.callback(outcome);
sceneParams.callback = null; // Protect against double calling;
}
}
[System.Serializable]
public class MySceneParams {
public System.Action<MySceneOutcome> callback;
// + inputs of the scene
}
public class MySceneOutcome {
// + outputs of the scene
}
You can keep global state in the caller's scope, so scene inputs and outputs states can be minimized (makes testing easy). To use it you can use anonymous functions:-
MyBigGameServices services ...
MyBigGameState bigState ...
Splash.loadScene(bigState.player.name, () => {
FirstLevel.loadScene(bigState.player, (firstLevelResult) => {
// do something else
services.savePlayer(firstLevelResult);
})
)}
More info at https://corepox.net/devlog/unity-pattern:-stateless-scenes
There are various way, but assuming that you have to pass just some basic data, you can create a singelton instance of a GameController and use that class to store the data.
and, of course DontDestroyOnLoad is mandatory!
public class GameControl : MonoBehaviour
{
//Static reference
public static GameControl control;
//Data to persist
public float health;
public float experience;
void Awake()
{
//Let the gameobject persist over the scenes
DontDestroyOnLoad(gameObject);
//Check if the control instance is null
if (control == null)
{
//This instance becomes the single instance available
control = this;
}
//Otherwise check if the control instance is not this one
else if (control != this)
{
//In case there is a different instance destroy this one.
Destroy(gameObject);
}
}
Here is the full tutorial with some other example.
you have several options.
The first one I see is to use static variables, which you will not lose their information or value passing from scenes to scenes (since they are not bound to the object). [you lose the information when closing the game, but not when passing between scenes]
the second option is that the player or the object of which you do not want to lose the information, you pass it through the DontDestroyOnLoad function
Here I give you the documentation and the sample code. [You lose the information when you close the game, but not when you go between scenes]
https://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
Third is to use the playerPrefab [https://docs.unity3d.com/ScriptReference/PlayerPrefs.html]
that allow you to save information and retrieve it at any time without hanging it even after closing the game [you must be very careful with the latter if you plan to use it to save data even after closing the game since you can lose the data if you close the game suddenly , since player prefab creates a file and retrieves the information from there, but it saves the file at the end or closes the app correctly]
How to change Vuforia the AnchorInputListenerBehaviour, the original setting is clicked on the screen, I want to change it to judge the Micro Switch high or low signal?
You don't need the Vuforia code at all!
You seem to rather just want to have your own custom UnityEvent in the Inspector you can invoke whenever you want to ;)
If you need it you can even extend this and add some parameters as described here using UnityEvent<T> e.g. something like
[Serializable]
public class CustomEvent : UnityEvent<bool> { }
public class Example : MonoBehaviour
{
public CustomEvent _onButtonStateChanged;
private bool lastState;
// Now however you check your button states and get your pin data
// on whatever condition you can simply invoke your event
private void Update()
{
//TODO
var currentState = GetYourButtonStateByMagic();
if(currentState != lastState)
{
_onButtonStateChanged.Invoke(currentState);
lastState = currentState;
}
}
}
This question already has answers here:
How to detect click/touch events on UI and GameObjects
(4 answers)
Closed 5 years ago.
using UnityEngine;
public class LinkEnd : MonoBehaviour
{
public GameObject linkTarget;
private PointEffector2D effector;
private CircleCollider2D contact;
private AimSystem aimer;
private float distFromLink = .2f;
public bool connected;
private void Start()
{
aimer = GetComponent<AimSystem>();
}
private void Update()
{
SyncPosition();
ReactToInput();
}
public void ConnectLinkEnd(Rigidbody2D endRB)
{
HingeJoint2D joint = GetComponent<HingeJoint2D>();
if (GetComponent<HingeJoint2D>() == null)
{
joint = gameObject.AddComponent<HingeJoint2D>();
}
joint.autoConfigureConnectedAnchor = false;
joint.connectedBody = endRB;
joint.anchor = Vector2.zero;
joint.connectedAnchor = new Vector2(0f, -distFromLink);
}
private void SyncPosition()
{
if (linkTarget != null)
{
if (Vector2.Distance(transform.position, contact.transform.position) <= 0.1f)
{
connected = true;
effector.enabled = false;
contact.usedByEffector = false;
}
}
if (connected)
{
GetComponent<Rigidbody2D>().isKinematic = true;
GetComponent<Rigidbody2D>().position = linkTarget.transform.position;
}
else
GetComponent<Rigidbody2D>().isKinematic = false;
}
private void ReactToInput()
{
if (Input.GetKeyUp(KeyCode.Mouse0) || Input.GetKey(KeyCode.Mouse1))
{
connected = false;
}
}
public void OnTriggerEnter2D(Collider2D collision)
{
if (collision.GetComponent<PointEffector2D>() != null)
{
connected = true;
linkTarget = collision.gameObject;
effector = linkTarget.GetComponent<PointEffector2D>();
contact = linkTarget.GetComponent<CircleCollider2D>();
}
}
public void OnTriggerExit2D(Collider2D collision)
{
connected = false;
contact.usedByEffector = true;
effector.enabled = true;
}
}
This is an object that pins its position to another mobile object on collision, and it's supposed to stay that way until it's 'detached' by player action.
It's working almost fine, but it's not working 'per instance.'
Whether this object is a prefab or not, ReactToInput() is affecting all instances of it unlike how I wanted.
I'm missing some per instance specification here and I'm not seeing where.
Any suggestion will help and be appreciated!
++ The method ReactToInput() is triggered by key inputs. I wanted this method to be called when Player's attack 'method' happens which are bound to those key inputs, but I did what I've done only because I couldn't find an elegant way to execute it otherwise, and am really hoping there's a better way rather than using tags or GetComponent to specific object since it's supossed to affect other objects as well.
These methods are what you are looking for.
/// <summary>
/// OnMouseDown is called when the user has pressed the mouse button while
/// over the GUIElement or Collider.
/// </summary>
void OnMouseDown()
{
Debug.Log("Hi!");
}
/// <summary>
/// OnMouseUp is called when the user has released the mouse button.
/// </summary>
void OnMouseUp()
{
Debug.Log("Bye!");
}
MonoBehaviour provides many event callbacks other than Update(), and these two are some of them. The full list of event callbacks you can use for MonoBehaviour is explained in the official Monobehaviour page.
There are two methods for OnMouseUp():
OnMouseUp is called when the user has released the mouse button.
OnMouseUpAsButton is only called when the mouse is released over the
same GUIElement or Collider as it was pressed.
The GameObject your script is attached to is requires to have GUIElement or Collider as described in the manual page to use these functions.
If you do not want to use these methods, you could alternatively write your own custom InputModule, raycast to the mouse position on the screen to find which object is clicked, and send MouseButtonDown() event to a clicked GameObject.
I had to implement a custom input module to do this plus a couple of other stuff and I assure you writing custom InputModules is a headache.
EDIT:
If many different classes need to be notified when something happens, and who listens to such cases is unknown, event is a good option.
If you are using events, each event listener class such as LinkEnd is responsible to register and remove itself to such event.
Below is an example of how you could achieve this behaviour:
class Player
{
public delegate void OnSkillAFiredListener(object obj, SkillAFiredEventArgs args);
public static event OnSkillAFiredListener SkillAPressed = delegate { };
// ...
}
class LinkEnd
{
void OnEnable()
{
Player.SkillAPressed += WhatToDoWhenSkillAFired;
}
void OnDisable()
{
Player.SkillAPressed -= WhatToDoWhenSkillAFired;
}
void OnDestroy()
{
Player.SkillAPressed -= WhatToDoWhenSkillAFired;
}
public void WhatToDoWhenSkillAFired(object obj, SkillAFiredEventArgs args)
{
// get info from args
float someInfo = args.someInfo
// do something..
Bark();
}
// ...
}
It's necessary to deregister from the event in both OnDisable() and OnDestory() to avoid memory leaks (some claim such memory leaks are very minor).
Look for Observer and Publisher/Subscriber pattern to learn more about these approaches. It may not be very related to your case, but the Mediator Pattern is something that's often compared with the Observer Pattern so you might be interested to check it as well.
This is related to happyfuntimes plugin if you have used it .
I am trying to make a game on it and stuck at a point of displaying score along with name to display on large screen while user is playing on his mobile.(i have already tried to display name and score on mobile screens have seen in sample do not need that ). Please suggest how can this be done if you have used happyfuntimes plugin.
I could see the HFTgamepad input having public GameObject player name which I am trying to access ,do I have to make array ?
public string playerName;
I am trying to put these name on array.
Displaying anything in unity is really normal unity issue and not special to happyfuntimes. Games display highscore lists, item lists, inventory lists, etc... A list of players is no different
Use the GUI system display text.
According to the docs if you want to generate UI dynamically you should make a prefab
So basically you'd make a UI hierarchy in the scene. When a player is added to the game Instantiate your name-score prefab, search for the UI hierarchy gameObject (do that at init time), then set the parent of the preafab you just instantiated so it's in the UI hierarchy.
Look up the UI.Text components that represent name and score and set their text properties.
There's various auto layout components to help layout your scores
When a player disconnects Destroy the prefab you instantiated above.
OR ...
Conversely you can use the old immediate mode GUI. You'd make a GameObject, give it a component that has a OnGUI function. Somewhere keep a list of players. Add players to the list as they connect and remove them from the list as they disconnect. In your OnGUI function loop over the list of players and call the GUI.Label function or similar to draw each name and score
Here's a hacked up example.
Assuming you have a PlayerScript script component that's on each player that has a public accessor PlayerName for getting the player's name then you can make a GameObject and put a script like this on it.
using UnityEngine;
using System.Collections.Generic;
public class ExamplePlayerListGUI : MonoBehaviour
{
static ExamplePlayerListGUI s_instance;
List<PlayerScript> m_players = new List<PlayerScript>();
static public ExamplePlayerListGUI GetInstance()
{
return s_instance;
}
void Awake()
{
if (s_instance != null)
{
Debug.LogError("there should only be one ExamplePlayerListGUI");
}
s_instance = this;
}
public void AddPlayer(PlayerScript bs)
{
m_players.Add(bs);
}
public void RemovePlayer(PlayerScript bs)
{
m_players.Remove(bs);
}
public void OnGUI()
{
Rect r = new Rect(0, 0, 100, m_players.Count * 20);
GUI.Box(r, "");
r.height = 20;
foreach(var player in m_players)
{
GUI.Label(r, player.PlayerName);
r.y += 20;
}
}
}
PlayerScript can then call ExamplePlayerListGUI.GetInstance().AddPlayer in its Start function and ExamplePlayerListGUI.GetInstance().RemovePlayer in it's OnDestroy function
public PlayerScript : MonoBehaviour
{
private string m_playerName;
...
public string PlayerName
{
get
{
return m_playerName;
}
}
void Start()
{
...
ExamplePlayerListGUI playerListGUI = ExamplePlayerListGUI.GetInstance();
// Check if it exists so we can use it with or without the list
if (playerListGUI != null)
{
playerListGUI.AddPlayer(this);
}
}
void OnDestroy()
{
...
ExamplePlayerListGUI playerListGUI = ExamplePlayerListGUI.GetInstance();
if (playerListGUI != null)
{
playerListGUI.RemovePlayer(this);
}
}
}