I have made an AR app in Unity using Vuforia. I have some Virtual Buttons in the scene. The problem I am facing is that the virtual button is getting pressed on their own. I am not able to figure out what I am doing wrong. All the buttons are in a layer named "Buttons". Here is the virtual Button handler script:
private List<GameObject> vbtns= new List<GameObject>();
// Use this for initialization
void Start () {
var goArray = FindObjectsOfType<GameObject>();
for(var i=0; i<goArray.Length; i++)
{
if(goArray[i].GetComponent<VirtualButtonBehaviour>())
{
//Debug.Log("The game component is " + goArray[i]);
goArray[i].GetComponent<VirtualButtonBehaviour>().RegisterEventHandler(this);
vbtns.Add(goArray[i]);
}
}
}
// Update is called once per frame
void Update () {
}
public void OnButtonPressed(VirtualButtonAbstractBehaviour vb)
{
Debug.Log("Button Pressed.");
Debug.Log("The name of the vbutton is "+ vb.VirtualButtonName);
SceneManager.LoadScene("scene_"+vb.VirtualButtonName,LoadSceneMode.Single);
}
public void OnButtonReleased(VirtualButtonAbstractBehaviour vb)
{
Debug.Log("Button Released");
}
Please suggest what could be the reason for this. I have attached the screenshot of the game view below. Thanks in advance.
Related
I am trying to make a unity ad so that when the player loses, he can watch an ad to continue. However, when i change scenes and try to watch the ad again, it shows the gameobject which is the HeartMenu.SetActive(false) has been destroyed but you are still trying to access it but my script just sets the heart menu to SetActive(false). How can i go around this?
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Advertisements;
public class RewardedAdsButton : MonoBehaviour,
IUnityAdsLoadListener, IUnityAdsShowListener
{
[SerializeField] Button _showAdButton;
[SerializeField] string _androidAdUnitId =
"Rewarded_Android";
[SerializeField] string _iOSAdUnitId = "Rewarded_iOS";
string _adUnitId = null; // This will remain null for
unsupported platforms
public GameObject Restart;
public GameObject HeartMenu;
void Awake()
{
#if UNITY_IOS
_adUnitId = _iOSAdUnitId;
#elif UNITY_ANDROID
_adUnitId = _androidAdUnitId;
#endif
}
public void Update()
{
}
// Load content to the Ad Unit:
public void LoadAd()
{
// IMPORTANT! Only load content AFTER initialization (in this example, initialization is handled in a different script).
Debug.Log("Loading Ad: " + _adUnitId);
Advertisement.Load(_adUnitId, this);
}
// If the ad successfully loads, add a listener to the button and enable it:
public void OnUnityAdsAdLoaded(string adUnitId)
{
Debug.Log("Ad Loaded: " + adUnitId);
if (adUnitId.Equals(_adUnitId))
{
// Configure the button to call the ShowAd() method when clicked:
_showAdButton.onClick.AddListener(ShowAd);
// Enable the button for users to click:
_showAdButton.interactable = true;
}
}
// Implement a method to execute when the user clicks the button:
public void ShowAd()
{
// Disable the button:
_showAdButton.interactable = false;
// Then show the ad:
Advertisement.Show(_adUnitId, this);
}
// Implement the Show Listener's OnUnityAdsShowComplete callback method to determine if the user gets a reward:
public void OnUnityAdsShowComplete(string adUnitId, UnityAdsShowCompletionState showCompletionState)
{
if (adUnitId.Equals(_adUnitId) && showCompletionState.Equals(UnityAdsShowCompletionState.COMPLETED))
{
Debug.Log("Unity Ads Rewarded Ad Completed");
// Grant a reward.
HeartMenu.SetActive(false);
OnDestroy();
Time.timeScale = 1f;
// Load another ad:
Advertisement.Load(_adUnitId, this);
}
}
Im new in developing so need some help for my game!
On my game I have 2 buttons one is "Play" and other "Level Select"
I stuck at the "Play" button, need to make a script that is always loading the highest level that is unlocked, not current but highest.
Here is the code that im using for level manager
public List<Button> levelButton;
public Sprite lockimage;
public bool delete;
private void Start()
{
int saveIndex = PlayerPrefs.GetInt("SaveIndex");
for (int i = 0; i < levelButton.Count; i++)
{
if (i <= saveIndex)
{
levelButton[i].interactable = true;
}
else
{
levelButton[i].interactable = false;
levelButton[i].GetComponent<Image>().sprite = lockimage;
}
}
}
public void LevelSelect()
{
int level = int.Parse(EventSystem.current.currentSelectedGameObject.name);
SceneManager.LoadScene(level);
}
public void PlayGame()
{
//code here
}
public void ResetGame()
{
PlayerPrefs.SetInt("SaveIndex", 0);
SceneManager.LoadScene(0);
}
public void DontResetGame()
{
SceneManager.LoadScene(0);
}
}
SceneManager.LoadScene(PlayerPrefs.GetInt("SaveIndex"));
edit: adding some info/context.
I realized that you set level buttons interactivity on the start functions based on the int save_index value you get from PlayerPrefs.
From there, I assumed that you could load the level directly using that same value on the PlayGame function.
Do note that the code I wrote will throw an error, if the "SaveIndex" key is not yet on PlayerPrefs
I've been working on a solution for weeks now and I think it's time to reach out. I'm trying to make a button that plays a sound when pressed by a controller, everyone will hear that sound. Using VRTK and PlayoVR, I'm able to make a non-networked version where the player can put their hand through a cube, click the trigger from the controller, and it makes a sound.
This is the code for that cube:
namespace VRTK.Examples {
using UnityEngine;
public class Whirlygig : VRTK_InteractableObject
{
public GameObject AudioSource;
public AudioSource LeftSpeaker;
public override void StartUsing(VRTK_InteractUse currentUsingObject =
null)
{
AudioSource.GetComponent<AudioSource>().Play();
}
}
}
Where I get lost is how to network it with Photon Unity Networking. This is what I have:
namespace PlayoVR
{
using UnityEngine;
using VRTK;
using UnityEngine.Video;
using NetBase;
public class PlaySync : Photon.MonoBehaviour
{
public AudioSource LeftSpeaker;
public GameObject Whirlgig;
private bool StartUsing;
// Use this for initialization
void Awake()
{
GetComponent<VRTK_InteractableObject>().InteractableObjectUsed +=
new InteractableObjectEventHandler(DoPlay);
}
void DoPlay(object sender, InteractableObjectEventArgs e)
{
StartUsing = true;
}
// Update is called once per frame
void Update()
{
// Handle firing
if (StartUsing)
{
CmdPlay();
StartUsing = false;
}
}
void CmdPlay()
{
photonView.RPC("NetPlay", PhotonTargets.All);
}
[PunRPC]
void NetPlay()
{
LeftSpeaker.Play();
}
}
}
As you can probably see, I'm a beginner. With this code, when I put my hand in the cube and press the trigger, nothing happens. If anyone can provide any help or even an alternative, I'd be very grateful.
Kind regards,
TheMusiken
I'm developing a multiplayer game based on turns.
So I have an script named gameController which is the one who has the global timer to alter the turns and also choose which players are attacking and which players are defending in the current turn.
This script is a singleton attached to a gameObject with a network identity on it (This network identity has no checkboxes marked to be controller by the server). I tried to have this game object spawned to all the clients when the server connects and also to have the game object already in the scene (booth cases aren't working).
Well, the main problem is that in the gameController script I have a checker in the update function to check if any new player is connected. In case is connected, it should call a syncEvent named EventOnNewPlayerAddedDelegate (I tried to call it directly, also using [command] and using [ ClientRpc]) to let the players know that they have to call their function named "OnRegisterPlayer", which is a function in their own player script that calls a function on gameController script, passing the player object (I tried via command and rpc also), something like this: GameController.instance.RegisterPlayer(this);
So anyone knows how can I trigger this SyncEvent to register the player to a non-player object controlled by the server?
Thank you very much.
I attach here a brief of booth scripts to make it easier to understand:
GameController:
public class GameController : NetworkBehaviour
{
public delegate void OnNewPlayerAddedDelegate();
[SyncEvent]
public event OnNewPlayerAddedDelegate EventOnNewPlayerAddedDelegate;
List<GamePlayerManager> players = new List<GamePlayerManager>();
public static GameController instance { get; private set; }
float timePerTorn = 30f;
bool isCountdown = false;
[System.NonSerialized]
public float countdownTime;
int roundNumber = 0;
int NumberOfPlayers;
int NumberOfPlayersChanged;
void Awake()
{
Debug.Log("Awaking ");
if (instance != null)
{
Debug.Log("Destoring ");
DestroyImmediate(this);
return;
}
instance = this;
}
// Use this for initialization
void Start()
{
if (!isServer)
{
return;
}
players = new List<GamePlayerManager>();
StartCountdown(5f);//20
}
void Update()
{
if (isServer)
{
if (isCountdown)
{
countdownTime -= Time.deltaTime;
if (countdownTime <= 0)
{
AlterGlobalTurns();
}
}
}
NumberOfPlayers = NetworkManager.singleton.numPlayers;
if (NumberOfPlayersChanged != NumberOfPlayers)
{
Debug.Log("num of players changed ---> " + NumberOfPlayers);
NumberOfPlayersChanged = NumberOfPlayers;
EventOnNewPlayerAddedDelegate();
//RpcNewPlayerAdded();
//CmdNewPlayerAdded();
}
}
[ClientRpc]
void RpcNewPlayerAdded()
{
Debug.Log("---------------- RpcNewPlayerAdded ------------");
EventOnNewPlayerAddedDelegate();
}
[Command]
void CmdNewPlayerAdded()
{
Debug.Log("---------------- CmdNewPlayerAdded ------------");
EventOnNewPlayerAddedDelegate();
}
public void RegisterPlayer(GamePlayerManager player)
{
Debug.Log("player ---> " + player.name);
if (players.Contains(player))
{
return;
}
Debug.Log("players ---> " + players);
players.Add(player);
}
}
PlayerScript:
public class GamePlayerManager : NetworkBehaviour
{
[System.NonSerialized]
public bool isPlayingOnTorn = true;
void Awake()
{
GameController.instance.EventOnNewPlayerAddedDelegate += OnRegisterPlayer;
}
private void Start()
{
if (!isLocalPlayer)
{
return;
}
}
public override void OnStartServer()
{
GameObject gc = (GameObject)Instantiate(NetworkManager.singleton.spawnPrefabs[2], transform.position, transform.rotation);
NetworkServer.Spawn(gc);
}
void OnRegisterPlayer(){
if (isLocalPlayer)
{
//GameController.instance.RegisterPlayer(this);
//RpcRegisterPlayer();
CmdRegisterPlayer();
}
}
[Command]
void CmdRegisterPlayer(){
Debug.Log("-------------Command Register player -------------");
GameController.instance.RegisterPlayer(this);
}
[ClientRpc]
void RpcRegisterPlayer()
{
Debug.Log("------------- RPC REgister Player -------------");
GameController.instance.RegisterPlayer(this);
}
}
I think I already saw the problem here.
The problem is that GameController is spawned by the playerScript(just if the player is also the host) in the function OnStartServer(). So the first problem is that the GameController doesn't detect the host player because it is not a new connections. And the second problem is when a second client is connected, the GameController detect the client connection and send the event signal faster than the client wakeup, so when the client is already working the signal is gone.
I solved the problem deleting this signal and checking directly in the playerScript if the GameController exists then check if the player is already registered.
My question now is that if there is anyway to instance and awake the server objects before the player(Host), which I understand that the answer is "no" because as the player is the host it needs to be running to have the server.
And the second question is if there is anyway or any signal to know that a new player is connected, and wait until it is awaked.
Thank you very much.
You can check the hole thread at Unity forums: https://forum.unity.com/threads/multiplayer-syncevent-problem-with-non-player-objects.589309/
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.