UNITY - Make a gameobject inactive and active - c#

I have game objects which is button (Called as tiles), when the button is clicked it will be inactive and there's a condition to be tested if the condition is true the button will be destroyed but if its false the button will back to its active status.
My game Manager script (The condition):
public void checkword()
{
wordBuilded = displayer.text.ToString();
if (txtContents.Contains(wordBuilded))
{
Debug.Log(wordBuilded + " Is on the list");
wordScore++;
Debug.Log(wordScore);
}
else
{
Debug.Log("Someting is wrong..");
FindObjectOfType<LetterTiles>().tileStatus();
}
}
On my Button (Tile) script (Script attached to the buttons):
public void letterClick()
{
gameManager.currentWord += letter;
gameObject.SetActive(false);
}
public void tileStatus()
{
gameObject.SetActive(true);
}

When an object is deactivated Unity won't find it using FindObjectOfType.
either keep a local reference to the object [the button] in the game manager before you disable it or hide the button in a different way.
Since you are using a Button, you can use the interactable property of the button to make it disabled [and if you want it to be hidden then change the disabled color to transparent] like:
gameobject.GetComponent<Button>().interactable = false;

Related

Area2D only becomes invisible when clicked on the edges. (c#)

I have created a pause screen Area2D for my game, in any case the player goes AFK. I wrote a code so whenever the key P is pressed it appears and everything pauses, and if it is clicked it disappears and everything goes back to normal. I wrote a code, but it didn't work
I tried this:
public override void _PhysicsProcess(float delta)
{
// Makes the pause screen visible when P is pressed
if (Input.IsActionPressed("Pause"))
{
Visible = true;
}
}
public override void _Ready()
{
}
public void _on_PauseScreen_mouse_entered()
{
if (Input.IsActionPressed("click"))
{
Visible = false;
}
}
But it only works when clicked on the edges, I know that's how collisions are but how do I make it so when anywhere the sprite is pressed, it disappears?
The problem in your code should be, that you are just checking if the action is pressed, when the mouse entered the area.
If you move the mouse to the middle of the area and click then, your event was already fired.
Create a variable to track, if the mouse is currently in the area by using entered and exit signals and use that to determine if something should happen when you click:
bool bMouseEntered = false
public override void _PhysicsProcess(float delta)
{
// Makes the pause screen visible when P is pressed
if (Input.IsActionPressed("Pause"))
{
Visible = true;
}
if (Input.IsActionPressed("click") && bMouseEntered)
{
Visible = false;
}
}
public override void _Ready()
{
}
public void _on_PauseScreen_mouse_entered()
{
bMouseEntered = true;
}
public void _on_PauseScreen_mouse_exited()
{
bMouseEntered = false;
}
I want it so if it is pressed anywhere on the pause screen, it dissapears.
That is probably the simplest case. And the easier way to do it is to put the check in _physics_process, where the other check is:
public override void _PhysicsProcess(float delta)
{
// Makes the pause screen visible when P is pressed
if (Input.IsActionPressed("Pause"))
{
Visible = true;
}
if (Input.IsActionPressed("click"))
{
Visible = false;
}
}
So it has nothing to do with collision or the mouse. It is just checking for the action regardless of where or how it happens.
We can argue that using _input or _unhandled_input is better, in particular if timing is critical, but I don't expect it to be an issue in this case.
Addendum:
I want it so when it is pressed anywhere ON THE PAUSE SCREEN. it disappears. it doesn't cover the full screen.
At the time of writing Bugfish already has a working solution. I'll give you an alternative.
Since you are using an Area2D it must have the property input_pickable, when it is set to true (which is the default) it allows to "pick" the Area2D with the mouse. And you would get this interaction in the input_event signal or overwriting _input_event. Which would look like this:
void _InputEvent(Viewport viewport, InputEvent ev, int shapeIdx)
{
var btn = ev as InputEventMouseButton;
if(btn != null && ev.ButtonIndex == ButtonList.Left && ev.Pressed)
{
Visible = false;
}
}

Onclick I am Ready Button Using Photon

So am currently developing a way where players in a current room are in a waiting room entering or selecting their specific item. When each player has completed a button is clicked which is 'I am Ready!'...When a player clicks I am ready then an Int variable ReadyPlayers Updates according to how many have clicked the I am ready Button. If the readyplayers (int) match the number of players in the room then a countdown starts. The problem I am facing is configuring the custom properties. I wrote this code hoping that it would solve this problem but I end up getting logical errors where the readyplayers (int) are not counted from the players.
using Hashtable = ExitGames.Client.Photon.Hashtable;
//Variables
public int ReadyPlayers = 0;
//added this to the button on the inspector : onclick event
public void OnClickIamReady()
{
ReadyPlayers = (int)PhotonNetwork.LocalPlayer.CustomProperties["PlayerReady"];
ReadyPlayers++;
Hashtable hash = new Hashtable() { { "PlayerReady", ReadyPlayers } };
PhotonNetwork.LocalPlayer.SetCustomProperties(hash);
//when a player clicks this button deactivate it
IamReadyButton.gameObject.SetActive(false);
foreach (Player player in PhotonNetwork.PlayerList)
{
Debug.Log(player.NickName.ToString() + " " + " is Ready. " + " " + " Players Who are Ready : " + player.CustomProperties["PlayerReady"].ToString());
}
}
It makes no sense that every player uses his own custom properties in order to store how many ready players he is aware of in total.
Instead you rather want to set only yourself to ready.
Then check of everyone is ready and start the match. But you don't want to make this check on the clients themselves. What about network lag? What if two clients press the button at the same time and the properties are not synced yet?
-> I would rather only check on the Master client within OnPlayerPropertiesUpdate
So something like
using System.Linq;
...
public void OnClickIamReady()
{
// Do not use a new hashtable everytime but rather the existing
// in order to not loose any other properties you might have later
var hash = PhotonNetwork.LocalPlayer.CustomProperties;
hash["Ready"] = true;
PhotonNetwork.LocalPlayer.SetCustomProperties(hash);
IamReadyButton.gameObject.SetActive(false);
if(!PhotonNetwork.IsMasterClient) return;
CheckAllPlayersReady ();
}
public override void OnPlayerPropertiesUpdate (Player targetPlayer, Hashtable changedProps)
{
if(!PhotonNetwork.IsMasterClient) return;
if(!changedProps.ContainsKey("Ready")) return;
CheckAllPlayersReady();
}
public override void OnMasterClientSwitched(Player newMasterClient)
{
if(newMasterClient != PhotoNework.LocalPlayer) return;
CheckAllPlayersReady ();
}
private void CheckAllPlayersReady ()
{
var players = PhotonNetwork.PlayerList;
// This is just using a shorthand via Linq instead of having a loop with a counter
// for checking whether all players in the list have the key "Ready" in their custom properties
if(players.All(p => p.CustomProperties.ContainsKey("Ready") && (bool)p.CustomProperties["Ready"]))
{
Debug.Log("All players are ready!");
}
}

Unity - Input.GetMouseButtonDown

I created a script where by clicking on the smartphone display, an object was activated. I used Input.GetMouseButtonDown(0) to check if a tap was made on the display. The script works fine, but I have a problem: if I insert a button in the scene, clicking on the button I receive both the click of the button and that of the Input.GetMouseButtonDown function. How could I "divide" the two touches?
// Example
void Update()
{
if (Input.GetMouseButtonDown(0))
myObject.SetActive(true);
}
public void PauseButton()
{
// Open Pause Panel
}
I was thinking of deleting "Input.GetMouseButtonDown (0)" and using an invisible button and resizing it on the portion of the display I needed.
Add Tag to your UI button like: "UI"
Below function tells whether a click was Over a UI object tagged with a UI tag, so you can check in your screen tap function if you should fire your event or not
public static class InputHandler
{
public const string CompareTagForUIElements = "UI";
public static bool IsPointerOverUIObject(int touchId)
{
var eventDataCurrentPosition = new PointerEventData(EventSystem.current);
// I'm using touch since you are talking about smartphones,
// if you still need click use Input.mousePosition
eventDataCurrentPosition.position = new Vector2(GetTouch(touchId).position.x, GetTouch(touchId).position.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
for (int i = 0; i < results.Count; i++)
{
if (results[i].gameObject.CompareTag(CompareTagForUIElements))
return true;
}
return false;
}
}
So rather than
public void ITappedOnScreen()
{
if(Input.GetMouseButtonDown(0))
Debug.Log("Screen tapped");
}
use
public void ITappedOnScreen()
{
if(Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Begin &&
!InputHandler.IsPointerOverUIObject(0))
Debug.Log("Screen tapped");
}

How to delete dynamically loaded gameobjects from a List in Untiy?

I have a list that loads its content dynamically. The Elements of the List are buttons that are being transformed into gameobjects. For every object in the user list a new Element is created. Now I want to be able to delete the Element along with the button itself, when the button is pressed, where each Element has its own dynamically created delete button. I tried putting a box collider with an OnMouseDown Event, however onMouseDown is never called.
public void ShowLectures()
{
foreach (var course in selectedCourses)
{
AddMoreButton();
}
}
public void AddMoreButton()
{
GameObject button = (GameObject)Instantiate(prefabButton);
button.transform.SetParent(panel.transform, false);
button.layer = 5;
button.SetActive(true);
}
public void OnMouseDown()
{
Destroy(gameObject);
}
First of all OnMouseDown is not called on the created Button but in your case rather on the GameObject your script is attached to.
Then
Destroy(gameObject);
the same way would destroy the GameObject your script is attached to, not the instantiated button GameObjects.
Since you commented that you are using a UI.Button component rather add it to the onClick event as a callback when the Button is instantiated :
public void AddMoreButton()
{
GameObject button = (GameObject)Instantiate(prefabButton);
button.transform.SetParent(panel.transform, false);
button.layer = 5;
button.SetActive(true);
// get the Button on the button object or any child
var buttonInstance = button.GetComponentInChildren<Button>();
// add a callback to destroy the button gameObject
// () => {} is a lambda expression
buttonInstance.onClick.AddCallback(()=>{ Destroy(button); });
}
A little hint: In case the Button is already on the same GameObject anyway you should rather change the prefab type itself to Button like e.g.
public Button prefabButton;
and than simply use
public void AddMoreButton()
{
Button button = Instantiate(prefabButton, panel.transform);
button.gameObject.layer = 5;
button.gameObject.SetActive(true);
// add a callback to destroy the button gameObject
// () => {} is a lambda expression
button.onClick.AddListener(()=>{ Destroy(button.gameObject); });
}
Instead of creating a gameobject with an OnMouseDown, I'd probably create a Button instead and binding an event to it:
var closeButton = /* Dynamically create button */
closeButton.GetComponent<Button>().onClick.AddListener(HandleCloseClick);
void HandleCloseClick() {
Destroy(gameObject);
}
You can, however, do the architecture you've already implemented - you just need to implement IPointerClickHandler.
Here's an answer describing how to implement & use the interface.
Check the docs for instructions on how to use each event (Mouse Down, Up, Enter, Exit)

Unity C# Shop Menu

Hey guys I have been building a shop menu that is activated when the button is pressed. I have four buttons in the menu that correspond to several buy able items in a grid. The buttons and text and Image attached are inside a GameObject. I'm trying to switch between menus with SetActive. I've successfully used SetActive to open and close the menu but when I try with the other portions they stay inactive regardless. Even when the button supposedly activating is pressed. The picture I uploaded shows the hierarchy of the shop. The buttons are under ShopSelection and the actual menu is Under Shop
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class UIManager : MonoBehaviour {
private static UIManager instance;
public static UIManager Instance;
public GameObject shopMenu, motherShips, resources, fleets, research;
bool menuIsOpen = false;
bool motherShipOpen = false;
bool resourcesOpen = false;
bool fleetOpen = false;
public Button shop, motherShipButton, resourceButton, fleetButton, exitButton;
void Start () {
shopMenu.SetActive(false);
//Open Shop Menu
Button btn = shop.GetComponent<Button>();
btn.onClick.AddListener(TaskOnClick);
//Open Motherships portion of shop
Button btn1 = shop.GetComponent<Button>();
btn1.onClick.AddListener(TaskOnClick3);
//Open resources portion of shop
Button btn2 = shop.GetComponent<Button>();
btn2.onClick.AddListener(TaskOnClick4);
//Open fleet portion of shop
Button btn3 = shop.GetComponent<Button>();
btn3.onClick.AddListener(TaskOnClick5);
//Open Research portion of shop
Button btn4 = shop.GetComponent<Button>();
btn4.onClick.AddListener(TaskOnClick6);
//Exit Menu
Button bttn = exitButton.GetComponent<Button>();
bttn.onClick.AddListener(TaskOnClick2);
}
// Update is called once per frame
void Update () {
}
void TaskOnClick()
{
shopMenu.SetActive(true);
menuIsOpen = true;
motherShips.SetActive(true);
}
void TaskOnClick2()
{
if (menuIsOpen == true)
{
shopMenu.SetActive(false);
menuIsOpen = false;
}
}
void TaskOnClick3()
{
if(menuIsOpen == true)
{
//Open Motherships Shop
motherShips.SetActive(true);
resources.SetActive(false);
fleets.SetActive(false);
}
}
void TaskOnClick4()
{
if (menuIsOpen == true)
{
//Open resources Shop
motherShips.SetActive(false);
resources.SetActive(true);
fleets.SetActive(false);
}
}
void TaskOnClick5()
{
if(menuIsOpen == true)
{
//Open Fleet Shop
motherShips.SetActive(false);
resources.SetActive(false);
fleets.SetActive(true);
}
}
void TaskOnClick6()
{
if (menuIsOpen == true)
{
//Open Research Page
motherShips.SetActive(false);
resources.SetActive(false);
fleets.SetActive(false);
}
}
}
You added all callbacks allways to the shop button e.g.
Button btn2 = shop.GetComponent<Button>();
btn2.onClick.AddListener(TaskOnClick4);
not to the supposed buttons motherShipButton, resourceButton, fleetButton
Note that you don't have to call GetComponent again if you declare the variable as Button it will automatically reference the Button component of the drag&dropped GameObject in the Inspector so instead it should simply be
shop.onClick.AddListener(TaskOnClick);
//Open Motherships portion of shop
motherShipButton.onClick.AddListener(TaskOnClick3);
//Open resources portion of shop
resourcesButton.onClick.AddListener(TaskOnClick4);
//Open fleet portion of shop
fleetButton.onClick.AddListener(TaskOnClick5);
//Open Research portion of shop
// Whatever button this belongs to
???.onClick.AddListener(TaskOnClick6);
//Exit Menu
exitButton.onClick.AddListener(TaskOnClick2);
Now also name the methods accordingly e.g. OpenMenu, CloseMenu etc. that would make it a lot easier for you and everyone else to understand the code.
I also doubt that you need the check for if(menuIsOpen). Since the other GameObjects are children of the menu anyway they will simply stay invisible even if SetActive was called. Instead I would make sure that only one panel is active by using a method with e.g. an enum instead like
enum MenuPanel
{
MotherShips,
Resources,
Fleets,
Research
}
private void ShowPanel(MenuPanel panel)
{
// First disable all
motherShips.SetActive(false);
fleets.SetActive(false);
resources.SetActive(false);
// Than only activate according panel
switch(panel)
{
case MenuPanel.MotherShips:
motherShips.SetActive(true);
break;
case MenuPanel.Reaources:
resources.SetActive(true);
break;
case MenuPanel.Fleets:
fleets.SetActive(true);
break;
}
}
And than I would still use dedicated methods for each panel like e.g.
void Start()
{
//...
motherShipButton.onClick.AddListener(ShowMotherShips);
//...
}
private void ShowMotherShips()
{
ShowPanel(MenuPanel.MotherShips);
}
you could do it also directly as lambda expression
void Start()
{
//...
motherShipButton.onClick.AddListener(() => {
ShowPanel(MenuPanel.MotherShips);
});
//...
}
I usually try to avoid it since 1. you can not reuse this expression but you might want to call it from else where as well and 2. you will not be able to use RemoveListener to eventually get rid of that call.

Categories