How can I solve the Unity GameObject Problem? Solved - unity3d

When the Continue Ads gameobject is closed, the Game over button works, but when the Continue Ads is turned on, the Game over button does not work. I cannot understand why I make a mistake?
!Me fixed the problem, the problem is that I noticed that it is related to the continue ads dimension, thank you for your time.
void Update()
{
if (Application.internetReachability == NetworkReachability.NotReachable)
{
//Debug.Log("No internet access");
Destroy(GameObject.FindWithTag("ContinuePanel"));
}
else
{
//Debug.Log("internet connection");
if (tag == "Skull")
{
ContinueAds();
}
}
}
public void ContinueAds()
{
gameObject.AddComponent<AdsScript1>();
gameoverPanel.SetActive(false);
PausedGamePanel();
}
public void GameoverButton()
{
gameoverPanel.SetActive(false);
SceneManager.LoadScene(0);
}

Your continue ads object is in gameover panel. When you set gameoverPanel.SetActive(false) you also do the same on the child objects.

Related

Original HTC Vive inputs not working with Unit's OpenXR

I created a game that uses Unity's OpenXR. I am trying to make the game compatible with both Oculus and HTC Vive.
In the code below, I am just trying to detect when the user presses their right primary button. This works just fine on Oculus, but I've gotten many Vive users who say that this doesn't work.
bool primary = false;
bool secondary = false;
bool trigger = false;
bool grip = false;
public InputDevice device;
void Start()
{
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevicesAtXRNode(XRNode.RightHand, devices);
device = devices[0];
}
public void Update(){
bool newGrip;
bool newTrigger;
bool newSecondary;
bool newPrimary;
device.TryGetFeatureValue(CommonUsages.gripButton, out newGrip);
device.TryGetFeatureValue(CommonUsages.triggerButton, out newTrigger);
device.TryGetFeatureValue(CommonUsages.secondaryButton, out newSecondary);
device.TryGetFeatureValue(CommonUsages.primaryButton, out newPrimary);
if (newGrip != grip)
{
if (newGrip)
{
//grip pressed
}
else
{
//grip released
}
grip = newGrip;
}
if (newTrigger != trigger)
{
if (newTrigger)
{
//trigger pressed
}
else
{
//trigger released
}
trigger = newTrigger;
}
if (newSecondary != secondary)
{
if (newSecondary)
{
//secondary pressed
}
else
{
//secondary released
}
secondary = newSecondary;
}
if (newPrimary != primary)
{
if (newPrimary)
{
//primary pressed
}
else
{
//primary released
}
primary = newPrimary;
}
}
Note that the triggers and grips get detected just fine on both HTC Vive and Oculus. The Secondary button isn't supported on Vive, so I'm assuming device.TryGetFeatureValue(CommonUsages.secondaryButton, out newSecondary) always returns false. It is just the primary button that is giving me an unexpected issue.
Now according to unity (https://docs.unity3d.com/Manual/xr_input.html), the Vive's primary button is supported.
Does anyone know why the above implementation wouldn't recognize the Vive's primary button being pressed?
Also, is there any way to detect the menu button for Vive players with unity's OpenXR? The link above says the menu button is not supported, but having an extra button to work with would be useful.
Thank you in advance!
The problem was fixed by converting to unity's new action-based input system.

Referencing to gameobject's renderer material after being instantiated from downloaded asset bundle not working

Hi! If you want to save time and still help please read this section and the last one to get glimpse of my problem (part 1 and 6). So much code was needed to fully present problem
Using Unity 2019.3.0b2
1.
Im creating WebGL application that allows you to customize your character via assets from downloaded asset bundles. So far I got downloading and instantiating work, but I also want to change downloaded gameobject material to custom color from color-picker. In this case I need to refer to adequate Renderer. I've got function that sends request and it goes like so:
private IEnumerator SendRequestCoroutine(UnityWebRequest request, UnityAction<UnityWebRequest> OnDownloadCompleteHandler, UnityAction<float> OnDownloadProgressHandler = null)
{
request.SendWebRequest();
while(!request.isDone)
{
if(OnDownloadProgressHandler != null)
OnDownloadProgressHandler.Invoke(request.downloadProgress);
yield return null;
}
// Has to fire once more because progress stops at around 0.87,
// never returning 1 unless download is finished.
if (OnDownloadProgressHandler != null)
OnDownloadProgressHandler.Invoke(1);
OnDownloadCompleteHandler.Invoke(request);
}
2.
I fire this coroutine like that:
public void DownloadAssetBundle(string url, ProgressBar bar = null)
{
if (isRequestSend)
{
Alerter.ShowMessage("Request has been already send, please wait untill complete.");
return;
}
UnityWebRequest request = HttpService.Instance.GetAssetBundleRequest(url);
if(bar != null)
{
HttpService.Instance.SendDownloadRequest
(
request,
(rq) => { OnDownloadAssetBundleCompleteHandler(rq); },
(rq) => OnDownloadProgressHandler(rq, bar)
);
isRequestSend = true;
}
else
{
HttpService.Instance.SendDownloadRequest
(
request,
(rq) => { OnDownloadAssetBundleCompleteHandler(rq); }
);
isRequestSend = true;
}
}
3.
OnDownloadAssetBundleCompleteHandler looks like this:
//Function that will handle asset bundle when completed.
private void OnDownloadAssetBundleCompleteHandler(UnityWebRequest request)
{
isRequestSend = false;
if(request.isHttpError || request.isNetworkError)
{
//Handle downloading error
Alerter.ShowMessage("Seems like there was a problem with downloading, try again.");
}
else
{
AssetBundle bundle;
//Handle content update
bundle = DownloadHandlerAssetBundle.GetContent(request);
AssetBundleInfo assetBundleInfo = bundle.LoadAllAssets<AssetBundleInfo>().FirstOrDefault();
if (assetBundleInfo == null)
{
//Handle error
Alerter.ShowMessage("Couldn't read information about this Character Part. AssetBundleInfo null exception.");
bundle.Unload(false);
return;
}
GameObject goToLoad = null;
goToLoad = bundle.LoadAsset<GameObject>(assetBundleInfo.ObjectName);
if (goToLoad == null)
{
Alerter.ShowMessage("Couldn't read information about this Character Part. Downloaded asset's gameobject null exception.");
bundle.Unload(false);
return;
}
Sticher.ConnectComponent(goToLoad, assetBundleInfo.PartType);
ColorSetter.Instance.ChangeSelectedBodyPart(assetBundleInfo.PartType);
bundle.Unload(false);
}
}
4.
Now the final step is to set adequate transform so my script will search for component of type Renderer, get its material of index 0 as current material to modify, class that contain ChangeSelectedBodyPart function looks like so:
using Assets.Scripts.Models.Enums;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ColorSetter : MonoBehaviour
{
public Renderer rend;
public ColorPicker picker;
public static ColorSetter Instance;
private void Awake()
{
if(Instance != null)
{
Destroy(this);
}
else
{
Instance = this;
DontDestroyOnLoad(this);
}
}
// Start is called before the first frame update
void Start()
{
picker.onValueChanged.AddListener(color =>
{
if (rend == null)
return;
rend.material.SetColor("_BaseColor", color);
}
);
}
public void ChangeSelectedBodyPart(AvatarPartType p)
{
switch(p)
{
case AvatarPartType.ClothesUpper:
SetActiveMaterial(Sticher.Instance.Clothes_Upper);
break;
case AvatarPartType.ClothesLower:
SetActiveMaterial(Sticher.Instance.Clothes_Lower);
break;
case AvatarPartType.Shoes:
SetActiveMaterial(Sticher.Instance.Shoes);
break;
case AvatarPartType.Hair:
SetActiveMaterial(Sticher.Instance.Hair);
break;
case AvatarPartType.Skin:
SetActiveMaterial(Sticher.Instance.Skin);
break;
}
}
private void SetActiveMaterial(Transform parent)
{
rend = parent.GetComponentInChildren<Renderer>();
}
}
5.
PS. parent has only one child that contains Renderer component
Now, finally, problem is that I don't get proper material reference, I got the old one that is being set via toggle button, simply as that:
public void OnValueChanged(bool value)
{
if(value)
{
ColorSetter.Instance.ChangeSelectedBodyPart(PartType);
ButtonManager.Instance.RemoveAllButtonsFromPartsWindow();
ButtonManager.Instance.PopulatePartsPanelWithAvatarPartsOfType(PartType);
}
}
6.
So in conclusion when I press on "toggle button" that represents some avatar body/clothing part it sets its parent and material properly via function, even after asset bundle has been downloaded (but I have to click the same toggle again to make it work), but when I fire the same function in OnDownloadAssetBundleCompleteHandler just after asset been downloaded it doesn't work :S Why? Is it related with asset unloading speed? Any tips on fixing this?
In Game View it behave like that:
I fixed it. Since you can't use DestoyImmediate like #derHugo said because it can cause reference errors or even it could destroy assets permamently I had to use Destroy() instead before Instantiating new gameobject from assetbundle, however Destroy() will delete given object at the end of the frame while I try to access Renderer component on freshly instantiated GameObject just at the same frame, before old one is acutally destoryed. I fixed it yielding one frame using yield return new WaitForEndOfFrame(); just after function that takes care of destroying old GameObjects before trying to access new GameObject.

How to network a VR button with PUN in Unity?

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

Multiplayer [SyncEvent] problem with non-player objects

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/

Authority with UNET client

I need to modify a non-player object. I am able to do it but for some reasons, I get warning:
Trying to send command for object without authority.
UnityEngine.Networking.NetworkBehaviour:SendCommandInternal(NetworkWriter, Int32, String)
ModelControl:CallCmdSetCube()
ModelControl:Update() (at Assets/Scripts/ModelControl.cs:21)
I have gone through the unity docs and the various answers but the weird part is that it does work but I wish to prevent the warning.
First there is a Manager object that creates the neutral object. This happens on the host.
public class ObjectControl : NetworkBehaviour
{
public GameObject cube;
public override void OnStartServer()
{
if (GameObject.Find("Cube") != null) { return; }
GameObject cubeInstance = (GameObject)Instantiate(this.cube,
new Vector3(0f, 0f, 5f), Quaternion.identity);
cubeInstance.name = "Cube";
NetworkServer.Spawn(cubeInstance);
}
}
Then each player has the following:
private void CmdSetCube()
{
GameObject cube = GameObject.Find("Cube"); // This is the neutral object
if (cube != null)
{
NetworkIdentity ni =cube.GetComponent<NetworkIdentity>();
ni.AssignClientAuthority(connectionToClient);
RpcPaint(cube, new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f)));
ni.RemoveClientAuthority(connectionToClient);
}
}
[ClientRpc]
void RpcPaint(GameObject obj, Color col)
{
obj.GetComponent<Renderer>().material.color = col;
}
The host does not trigger the warning. Only the remote clients gets the warning. When I have many clients, I can see in the editor console that it will print as many times as there are clients.
But again, it does actually work, I can see the new data being propagated to all sessions but I am expecting something to go down later on.
So the issue came from the Update method:
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
CmdSetCube();
}
}
The problem here being that all instances of that script will run the code while only one is really getting authority.
Solution:
void Update()
{
if (this.isLocalPlayer == false) { return; }
if (Input.GetKeyDown(KeyCode.Space))
{
CmdSetCube();
}
}
Add the line to make sure this is the local player calling.