Having trouble calling a ServerRpc function from button - Unity Netcode - c#

I'm trying to spawn a monster when the player click a button but when doing so it return a NullReference. What's weird about it it's that the NullReference point to the first line of the ServerRpc function so even a Debug.Log is considered Null. (The testButton function was created to check if anything was wrong with my button, but it does work fine).
To give more context, the buttons are instantiated when the player spawn. The player is linked to the button from the prefab directly.
The player is able to spawn monsters by pressing A and that's working wonderfully so the all the logic of spawning works fine.
public class PlayerNetwork : NetworkBehaviour
{
private SpawnMonsters spawn;
public MonsterCardGame[] monsterDeck;
public Transform[] cardEmps;
public override void OnNetworkSpawn()
{
spawn = FindObjectOfType<SpawnMonsters>();
}
private void Update()
{
if (!IsOwner) return;
if (Input.GetKey(KeyCode.A))
{
SpawnMonsterServerRpc();
}
}
[ServerRpc(RequireOwnership = false)]
public void SpawnMonsterServerRpc()
{
Debug.Log("ServerRpc");
spawn.SpawnMonster(0);
}
public void testButton()
{
Debug.Log("Clickbutton");
SpawnMonsterServerRpc();
}
}

Adding an EventListener to the button fixed the problem!

Related

How to freeze camera when the game is paused in Unity?

So recently I started coding my first FPS game. I experienced a problem with my pause menu. The problem is when I have my game paused my mouse is still controling the camera and when I want to press some buttons in menu camera keeps following my mouse. I searched for solution to this problem on web, but I haven't found the solution (even my code is similar to some I've found).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PauseMenu : MonoBehaviour
{
public static bool gameIsPaused;
public GameObject pauseMenuUI;
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape))
{
Pause();
}
}
public void Resume()
{
Cursor.lockState = CursorLockMode.Locked;
pauseMenuUI.SetActive(false);
Time.timeScale = 1f;
gameIsPaused = false;
}
void Pause()
{
Cursor.lockState = CursorLockMode.None;
pauseMenuUI.SetActive(true);
gameIsPaused=true;
Time.timeScale = 0f;
}
public void LoadMenu()
{
Time.timeScale = 1f;
SceneManager.LoadScene("Menu");
}
public void QuitGame()
{
Debug.Log("Quitting game...");
Application.Quit();
}
}
What I would do is to update the camera according to the pause conditon. like so:
public class CameraRotation : MonoBehaviour
{
public isGamePaused; // changed from outside when you pause/unpause the game
void Update()
{
if (isGamePaused) {
...
}
}
}
The problem with gameIsPaused (usual code convention naming to state is a bool would be isGamePaused :)) is that until you set it to true in the menu the camera will keep moving, so you may need to set the boolean to true at the time the menu pops up.
Even its not the suited case for static variables, if you want to check the pause state of your game from the camera script, you can do so like this:
public class CameraRotation : MonoBehaviour
{
public isGamePaused; // changed from outside when you pause/unpause the game
void Update()
{
if (PauseMenu.gameIsPaused) {
...
}
}
}
static stands for static in memory, so the variable value can be checked anytime from anywhere with ClassName.staticVariableName. With this I mean that as long as you set the PauseMenu.gameIsPaused variable at the times in the code where you´d like you should be able to make it work, by working I mean freeze/unfreeze the camera at the exact moment you want.
Your static PauseMenu.IsPaused is fine and a good way to do it although I usually put something like that on a GameManager class. You can find a Unity Singleton pattern online so you can start having PauseMenu.Instance.XXX so it's easy to access anything you need. That being said, you need to find the script controlling your camera and check the PauseMenu.IsPaused. Most likely you have a script attached to your camera, and all you generally need to do is find the Update() function and just do: if (PauseMenu.IsPaused) return; to stop it from working.

Error MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it

I have been making a 2D game in Unity. I'm trying to make a game over screen appear every time a ball touches the player. I also added advertisements to release it. I added Restart and Continue buttons. When you press continue, an ad shows and the game continues. When Restart is pressed, it resets the game and your score. Whenever I restart the game and then press continue, the ad is played, but the game does not continue.
Here is the collision script:
using UnityEngine;
public class hitDetect : MonoBehaviour
{
public GameObject menuContainer;
private void OnTriggerEnter2D(Collider2D other)
{
Debug.Log("HIT");
menuContainer.SetActive(true);
Time.timeScale = 0;
}
}
This is the script that restarts the game:
using UnityEngine;
using UnityEngine.SceneManagement;
public class RestartGame : MonoBehaviour
{
public void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
Time.timeScale = 1;
}
}
Here is the advertisement and continue script:
using UnityEngine;
using UnityEngine.Advertisements;
public class continueGame : MonoBehaviour, IUnityAdsListener
{
string placement = "rewardedVideo";
public GameObject menuContain;
private void Start()
{
Advertisement.AddListener(this);
Advertisement.Initialize("4006857", true);
}
public void Continue(string p)
{
Advertisement.Show(p);
}
public void OnUnityAdsReady(string placementId)
{
}
public void OnUnityAdsDidError(string message)
{
}
public void OnUnityAdsDidStart(string placementId)
{
}
public void OnUnityAdsDidFinish(string placementId, ShowResult showResult)
{
if(showResult == ShowResult.Finished)
{
menuContain.SetActive(false);
Time.timeScale = 1;
}
}
}
Once you call
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex)
a "new" scene is loaded and therefore anything currently existing is destroyed.
In continueGame you do
private void Start()
{
Advertisement.AddListener(this);
Advertisement.Initialize("4006857", true);
}
But you never remove that listener!
Thus the next time the Advertisement fires its event it is still trying to execute them of the now already destroyed continueGame instance.
Therefore you always should remove any listeners as soon as you don't need them anymore:
private void OnDestroy ()
{
Advertisement.RemoveListener(this);
}

Pressing UI buttons alongside processing Input.GetMouseDown() in Update

The game I'm making is meant for mobile devices.
I have a PlayerInput class in which I check for mouse events in Update():
void Update()
{
if (Input.GetMouseButtonDown(0))
{
//hide UI elements
}
}
I have a button which I hide when I detect mouse input in PlayerInput class but I don't want to hide it if the player presses the button.
I've managed to solve this issue by adding this component to my UI elements:
public class UiPointerHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerEnter(PointerEventData eventData)
{
//disable mouse checks
}
public void OnPointerExit(PointerEventData eventData)
{
//enable mouse checks
}
}
It allows me to disable processing mouse events in PlayerInput's Update() to interact with certain UI elements.
This does its job fairly well on PC when I'm testing/prototyping the game but when I build the game for mobile it doesn't work at all and I can't press the buttons.
I'm looking for a solution that would work on mobile as well.
You can solve this fairly easily by adding the following check
void Update()
{
if (Input.GetMouseButtonDown(0) && !EventSystem.current.IsPointerOverGameObject())
{
//hide UI elements
}
}
What this does is it checks if your pointer (mouse or finger) is over an UI element. By checking if it's not, you get your desired behaviour.
See "Input.GetTouch" on 'Input' class on Unity, GetMouseButtonDown doesn't work on mobile. Unity designed 'Touch' event on mobile instead of mouse event so try it. it has to work with your code.
Thanks to user Immorality I've managed to solve my problem.
I've added the EventSystem.current.IsPointerOverGameObject() check to the Update() inside of my PlayerInput class.
void Update()
{
if(EventSystem.current.IsPointerOverGameObject()) return;
if (Input.GetMouseButtonDown(0))
{
//hide UI elements
}
}
I've tested this solution on its own and it did not help in my case, I still wasn't able to press the buttons.
I've introduced a bool in PlayerInput which controls whether the mouse input is being processed and 2 static methods allowing to change this variable.
public class PlayerInput : MonoBehaviour
{
private static bool _transmitInput;
void Update()
{
if(!_transmitInput || EventSystem.current.IsPointerOverGameObject()) return;
if (Input.GetMouseButtonDown(0))
{
//hide UI elements
}
}
public static void DisableInput()
{
if (!_transmitInput) return;
_transmitInput = false;
}
public static void EnableInput()
{
if (_transmitInput) return;
_transmitInput = true;
}
}
These are called from the UiPointerHandler:
public class UiPointerHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
public void OnPointerEnter(PointerEventData eventData)
{
PlayerInput.DisableInput();
}
public void OnPointerExit(PointerEventData eventData)
{
PlayerInput.EnableInput();
}
}
At this point I was still having problems on mobile. When pressing the button, the OnPointerEnter() would be called but OnPointerExit() would not.
I assume it is because of how my scene is set up. The 2 buttons I'm working with are in the same position and are the same size. I just disable one and enable the other.
I solved this issue by calling PlayerInput.EnableInput() in the onClick of the buttons.

gaze always execute even after PointExit

I have a problem about my gaze on VR . What I am trying to do is that gaze upon the button I want to select then hide the first gameobject parent then show the second gameobject parent . Now the second gameobject parent will be shown and when I try to gaze upon the back button it will show the first gameobject parent and hide the second gameobject parent . The problem occurs here, when I am trying to nothing and don't gaze on the buttons it automatically show my second gameobject parent and go back to first parent gameobject and hide and show and hide and show always.
public float gazeTime = 2f;
private float timer;
private bool gazedAt;
public Setting setting;
private void Start()
{
}
public void Update()
{
if (gazedAt)
{
timer += Time.deltaTime;
if (timer >= gazeTime)
{
// execute pointerdown handler
ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerDownHandler);
timer = 0f;
}
else
{
return;
}
}
else
{
return;
}
}
public void PointerEnter()
{
gazedAt = true;
Debug.Log("PointerEnter");
}
public void PointerExit()
{
gazedAt = false;
Debug.Log("PointerExit");
}
//Method for going to setting
public void Setting()
{
setting.ActivateSetting();
}
//Method for going back to main menu
public void GoBack()
{
setting.GoBackToMainMenu();
}
Here's how my Setting code is setup
public GameObject setting;
public GameObject back;
public void ActivateSetting()
{
setting.SetActive(false);
back.SetActive(true);
}
public void GoBackToMainMenu()
{
back.SetActive(false);
setting.SetActive(true);
}
What I want is that it will only show the gameobject parent if I gaze upon it.
After calling the click once you reset the timer but you didn't reset gazedAt
=> the Update method did still run the timer and call the click again.
It seems that your PointerExit is not called at all and therefore the button never reset.
Instead of the EventTrigger I would strongly recommend to use the interfaces IPointerEnterHandler and IPointerExitHandler like
public class YourClass : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
//...
public void OnPointerEnter()
{
}
public void OnPointerExit()
{
}
I would actually not use Update at all but prefer a Coroutine. Also don't use the complex call of ExecuteEvents.Execute(gameObject, new PointerEventData(EventSystem.current), ExecuteEvents.pointerDownHandler); instead use either Getcomponent<Button>().onClick.Invoke(); or call the method directly
private Button _button;
private void Awake()
{
// Get the reference only once to avoid
// having to get it over and over again
_button = GetComponent<Button>();
}
private IEnumerator Gaze()
{
// wait for given time
yield return new WaitForSeconds(gazeTime);
// call the buttons onClick event
_button.onClick.Invoke();
// or as said alternatively directly use the methods e.g.
setting.ActivateSetting();
}
public void OnPointerEnter()
{
Debug.Log("PointerEnter");
// start the coroutine
StartCoroutine(Gaze());
}
public void OnPointerExit()
{
Debug.Log("PointerExit");
// stop/interrupt the coroutine
StopCoroutine(Gaze());
}
As you can see there is no need at all for the timer and gazedAt values so you can't forget to reset them somewhere. It also avoids that the method is called repeatedly.
If you don't want to use a Button at all you could also add your own UnityEvent like
// add callbacks e.g. in the Inspector or via script
public UnityEvent onGazedClick;
// ...
onGazedClick.Invoke();

how to make image appear when player is dead in unity

I need to make an image pop up when the player has died or crashed but i do not know how to do it, i'm trying to make a game in unity using c#
but i have made a code that will tell show the user an image before they start (tap to start image) and all i want to do is display another one that tell to user to start again
does the code have to be similar to this or do i have to start from scratch?
public class StartScreenScript : MonoBehaviour {
static bool sawOnce = false;
// Use this for initialization
void Start () {
if(!sawOnce) {
GetComponent<SpriteRenderer>().enabled = true;
Time.timeScale = 0;
}
sawOnce = true;
}
// Update is called once per frame
void Update () {
if(Time.timeScale==0 && (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) ) {
Time.timeScale = 1;
GetComponent<SpriteRenderer>().enabled = false;
}
}
}
this code show the an image telling the user to tap the screen and the image then goes away until the user closes the game then comes back on however i want to display a "you are dead image" every time the player dies can someone please help me
p.s this is for a 2d game
Well one way to do it would be using Unity3D's GUI.DrawTexture that given a texture draws it at a given position. Here is a sample call to the method.
GUI.DrawTexture(new Rect(leftAnchor, topAnchor, textureWidth, textureHeight), textureSource);
This is my approach and it works in most cases:
Create a GameObject that will work as a dead screen. Apply a sprite
or whatever telling the user to click to restart.
Add the previous GameObject to the PlayerController so he can
instantiate it.
When the player is dead call PlayerController.ShowDeadScreen()
When the user clicks inside DeadScreen GameObject it will call your
PlayerController.PlayAgain function and destroy itself. So you must handle everything
the game need to be restarted.
PlayerController example code
public class PlayerController : MonoBehaviour {
public GameObject deadScreen;
void Start() { }
void Update() { }
public void ShowDeadScreen()
{
// show DeadScreen GameObject on the center of the screen
GameObject go = Instantiate(deadScreen, new Vector(0, 0, 0), Quaternation.Identity) as GameObject;
go.playerController = this;
}
public void PlayAgain()
{
// handle game restart
}
}
DeadScreen example code
public class DeadScreen : MonoBehaviour {
public PlayerController playerController;
void Start() { }
void Update() { }
void OnMouseDown()
{
// when user clicks inside this GameObject start the game again
playerController.PlayAgain();
Destroy(this.gameObject);
}
}

Categories