Disable GameObject creation when clicking on a GUI Button - c#

I have a chunk of code similar to this:
GameObject prefab; // Gets set when GUI button is clicked
void Update(){
if(Input.GetMouseButtonUp(0) && prefab){
Instantiate(prefab, /* At mouse position on ground */);
prefab = null;
}
}
Here is the code when I click the button:
public void SetBuilding(GameObject building){
prefab = building;
Destroy(ghostBuildingObject);
ghostBuildingObject = Instantiate(building);
if (ghostBuildingObject) {
// Set the alpha to half
Color c = ghostBuildingObject.GetComponent<MeshRenderer>().material.color;
c.a = 0.5f;
ghostBuildingObject.GetComponent<MeshRenderer>().material.color = c;
// Disable Components
ghostBuildingObject.GetComponent<Collider>().isTrigger = true;
Destroy(ghostBuildingObject.GetComponent<NavMeshObstacle>());
Destroy(ghostBuildingObject.GetComponent<Building>());
ghostBuilding = ghostBuildingObject.AddComponent<GhostBuilding>();
ghostBuildingObject.layer = LayerMask.NameToLayer("Ghost");
ghostBuildingObject.name = "Ghost Building";
}
}
Basically what it does is creates an object where I click on the ground object. What happens is when I click on a button it still creates the game object. How can I stop it from creating a gameObject when I click on a GUI Button?

Was in the process of typing this before you put your own answer. I still decided to put my answer because what you did in your answer is so wrong and unnecessary. You are allocating memory multiple times per frame, in the code in your answer only to detect a click...
I am using a Button (UnityEngine.GUI.Button)
I am using the unity5 GUI elements
You shouldn't be using that to begin with. Some people suggests you should use a raycast but the problem of a ray passing through a UI will still remain.
What you need is the a Button from UnityEngine.UI.Button not UnityEngine.GUI.Button. You have to change your whole program to use UI from UnityEngine.UI.
To create your button, you go to GameObject->UI->Button. That should create Canvas and other components required to get Button to work. Here are Unity UI tutorials.
Basically what it does is creates an object where I click on the
ground object.
You can detect a button click by implementing IPointerClickHandler and overriding the OnPointerClick function.
Attach the script below to the ground you want to detect the click.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class Click : MonoBehaviour, IPointerClickHandler
{
void Start()
{
Camera.main.gameObject.AddComponent<PhysicsRaycaster>();
}
public void OnPointerClick(PointerEventData eventData)
{
Debug.Log("Clicked!");
}
}
For your Button, you can just subscribe to to Buttons using the Button.onClick.AddListener(() => functionName());. Below is a full code for detecting clicks on 3 buttons. The good thing about this is that only one click will be detected. Clicks will not go through other GameObjects and you are NOT allocating memory each frame just to detect a button click.
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour
{
public Button button1;
public Button button2;
public Button button3;
void OnEnable()
{
//Register Button Events
button1.onClick.AddListener(() => buttonCallBack(button1));
button2.onClick.AddListener(() => buttonCallBack(button2));
button3.onClick.AddListener(() => buttonCallBack(button3));
}
private void buttonCallBack(Button buttonPressed)
{
if (buttonPressed == button1)
{
//Your code for button 1
//Call your SetBuilding(GameObject building) function for any button
SetBuilding(someGameOBject);
}
if (buttonPressed == button2)
{
//Your code for button 2
}
if (buttonPressed == button3)
{
//Your code for button 3
}
}
void OnDisable()
{
//Un-Register Button Events
button1.onClick.RemoveAllListeners();
button2.onClick.RemoveAllListeners();
button3.onClick.RemoveAllListeners();
}
}

I don't know if i clearly understand but you are Instantiating on the button and at the click:
ghostBuildingObject = Instantiate(building);
and
Instantiate(prefab, /* At mouse position on ground */);
so it's normal for it to be created 2 times

Have you tried with:
if(Input.GetMouseButtonUp(0) && prefab != null){
Instantiate(prefab, /* At mouse position on ground */);
prefab = null;
}

Using Pointer Events seems to fix the issue:
void Update(){
// Get pointer events
var pointer = new PointerEventData(EventSystem.current);
pointer.position = Input.mousePosition;
// Test the raycast
List<RaycastResult> raycastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointer, raycastResults);
// Check if anything was cast
if(Input.GetMouseButtonUp(0) && raycastResults.Count == 0 && prefab){
Instantiate(prefab, /* At mouse position on ground */);
prefab = null;
}
}

Related

Unity Changing the button image by clicking

Well, I already know that Unity itself has the Sprite Swap function, for that, but I wanted it to click when I changed the image and returned the old one only when it closed the window that was opened, or if I clicked it again on the icon, I tried to several ways so I turned to a helpy
Video link:- https://youtu.be/-H7j3vdKl8A.
Visit github if u dont undertand it here.
https://github.com/NareshBisht/Unity-UI-Shop-Select-2-UI-object-at-same-time/blob/master/ButtonAnimationHold.cs
Thank you.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
//*************************Script to select one "Category(say Weapon)" UI Button till anathor category button(say Vehicles) is pressed.********************************//
/*
* Steps to be followed to make this script work
* Select All the Category Buttons (for example:- Suppose u r builiding a shop UI then Select all Category button Like Helics, Weapons -- refer to video link above;
* Now tag all these category button as same (say UI_CategoryButtons).
* Attach this script to all the UI_category button.
* the script will aotomatically add Button, Animator, Image component to the Ui Gameobjects.
* now select Animation in Transition tab.
* now press the Auto genrate Animation in Button component tab.
* now, set Transition from Animation to none in button Tab.
* Now, Do the above step for Sub category UI element too (for eg do for Apache, Tiger, f-22 etc which is the sub category of Helics --- refer video)
* open Animation window and Animate ur Ui elements.
* ur good to go now.
*/
[RequireComponent(typeof(Button))]
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(Image))]
public class ButtonAnimationHold : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerClickHandler
{
public float TransitionTime = 0.3f; //Time taken to transition from one animation state to anathor.
private Animator MyAnim; //reference to animator attacted to the UI gameObject.
private void Start()
{
MyAnim = GetComponent<Animator>();
PlayNoramlState(); //Playing normal state at beginning.
}
public void HighlightThisButton_UnhighlightRest() //called when button is pressed (Called by OnPointerClick() defined below)
{
string TagOfPressedButton = gameObject.tag; //the tag of the button pressed by user.
foreach (Button button in gameObject.GetComponentInParent<Transform>().root.gameObject.GetComponentsInChildren<Button>()) //searching the gameobject with tag as in TagOfPressedButton inside the canvas which contain all UI element.
{ //we search inside Canvas to improve perf.
if(button.gameObject.tag == TagOfPressedButton && button.gameObject != this.gameObject) //selecting gameobjects with same tag(tag of button which was pressed) execpt the one which was pressed and then playing normal state in all selected GO.
{
button.gameObject.GetComponent<ButtonAnimationHold>().PlayNoramlState(); //Playing normal state in all UI gameObject with same tag except the one which called it.
}
}
MyAnim.Play("Pressed"); //Playing Pressed state in the UI element that was pressed.
}
public void PlayNoramlState()
{
MyAnim.CrossFadeInFixedTime("Normal", TransitionTime); //smoothly transitioning to Normal state;
}
public void OnPointerEnter(PointerEventData eventData) //Called when pointer hover over the Ui elemnt;
{
if(MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Normal")) //Playing highlighted state only when it is in normal state and not when it is in Pressed state.
{
MyAnim.CrossFadeInFixedTime("Highlighted", TransitionTime); //smoothly transitioning to Highlighted state;
}
}
public void OnPointerExit(PointerEventData eventData)
{
if (MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Highlighted") || MyAnim.GetCurrentAnimatorStateInfo(0).IsName("Normal")) //Playing Normal state only when it is in Highlighted state and not when it is in Pressed state
{
MyAnim.CrossFadeInFixedTime("Normal", TransitionTime); //smoothly transitioning to Normal state;
}
}
public void OnPointerClick(PointerEventData eventData) //called when button is pressed that is pointer down and pointer up both have to be done over button
{
HighlightThisButton_UnhighlightRest();
}
}
//video link
//https://youtu.be/-H7j3vdKl8A

Unity how to scale gameobjects using mouseclick?

does anyone know how to scale up different game objects using mouse click and after doing the scaling, the game object should not be able to scale up again. Currently my code is able to scale up but its not what i wanted.
Heres my current code:
public void ScaleForRuler()
{
transform.localScale += new Vector3 (3.0F, 0, 0.1F);
}
void OnMouseDown()
{
if (touch == false)
{
if(ruler.GetComponent<Collider>().name == "Ruler")
{
ScaleForRuler ();
touch = true;
Debug.Log (touch);
}
if(TriangleThingy.GetComponent<Collider>().name == "Triangle_Set_Square_Ruler")
{
ScaleForTriangleThingy ();
touch = true;
Debug.Log (touch);
}
if (Tsquare.GetComponent<Collider> ().name == "Tsquare")
{
if (LineR.GetComponent<Collider> ().name == "LineRight" || LineL.GetComponent<Collider> ().name == "LineLeft")
{
TsquareScaleForTB ();
touch = true;
Debug.Log (touch);
}
else if (LineB.GetComponent<Collider> ().name == "LineBottom" || LineT.GetComponent<Collider> ().name == "LineTop")
{
TsquareScaleForTB ();
touch = true;
Debug.Log (touch);
}
}
if (protractor.GetComponent<Collider> ().name == "Protractor")
{
ScaleForProtractor ();
touch = true;
Debug.Log (touch);
Debug.Log ("protractor scale");
}
}
}
Stop using OnMouseDown(), Unity has introduced since a while some new handler interfaces like IPointerDownHandler, IDragHandler, etc. within the EventSystem class, which works perfectly with mouse AND touch inputs.
It's not really clear what you want to achieve, if you want to scale every single object separately when it's clicked or just scale all together regardless which one is clicked.
I'll assume you want to be able to scale all objects separately. The steps to do that are the following:
1) Add the Physics 2D Raycaster component to your scene camera.
2) To every single object you want to scale, add this simple script:
using UnityEngine;
using UnityEngine.EventSystems;
public class ScaleExample : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {
private Vector2 startPosition;
private float scalingFactor = .01f;
private bool isObjectAlreadyScaled = false;
public void OnBeginDrag(PointerEventData eventData) {
startPosition = Vector2.zero;
}
public void OnDrag(PointerEventData eventData) {
if (!isObjectAlreadyScaled) {
startPosition += eventData.delta;
var scalingAmount = new Vector2(Mathf.Abs(startPosition.x), Mathf.Abs(startPosition.y));
transform.localScale = (Vector3)scalingAmount * scalingFactor;
}
}
public void OnEndDrag(PointerEventData eventData) {
isObjectAlreadyScaled = true;
}
}
The example works with 2D objects (i.e.: scales up the X and Y of the object), you can ofc change this very easily in order to accomodate different coordinates scaling.
The use of the interfaces should be clear by example: OnBeginDrag is called once as soon as the dragging starts, OnDrag is called repeatedly every time there's a change in the position of the pointer during the drag, and OnEndDrag is called as soon as the drag is over (i.e.: user releases the button/finger).
In a comment to your question, you wrote
So i wanted to ask if i could just use a single script to control scaling for many diff objects
The answer is yes (and it is a really good idea also)
Here is an idea on how to do it:
From the doc of OnMouseDown:
OnMouseDown is called when the user has pressed the mouse button while over the GUIElement or Collider.
This means that if your script contains the OnMouseDown function:
private void OnMouseDown()
{
}
you can add this script to several different objects. If you click on object1, the function will be called only for object1. If you click on object2, the function will be called for object2. So you don't need to check which object is clicked.
Your script should look like this:
private void OnMouseDown()
{
// touch is a boolean, you don't need to write touch == true, it will do it automatically
// Also, instead of nesting all the code if touch == false, we just stop if it is true, so the code is easier to read
if (touch)
return;
touch = true;
Debug.Log (touch);
// transform is the transform of the object that has the script
// you don't need any check
transform.localScale += new Vector3 (3.0f, 0f, 0.1f);
}
I hope this helps
Good luck

How do I add a restart function to a game in Unity?

I have followed and completed a Unity tutorial however once the tutorial is said and done, there was no function mentioned to restart the game.
Other than closing the application and re-opening, how would I go about adding something like this in?
There are do ways to restart game in Unity:
1.Reset every useful variables such as position, rotation, score to their default position. When you use this method, instead of #2, you will reduce how much time it take for your game to load.
Create a UI Button then drag it to the resetButton slot in the Editor.
//Drag button from the Editor to this
public Button resetButton;
Vector3 defaultBallPos;
Quaternion defaultBallRot;
Vector3 defaultBallScale;
int score = 0;
void Start()
{
//Get the starting/default values
defaultBallPos = transform.position;
defaultBallRot = transform.rotation;
defaultBallScale = transform.localScale;
}
void OnEnable()
{
//Register Button Event
resetButton.onClick.AddListener(() => buttonCallBack());
}
private void buttonCallBack()
{
UnityEngine.Debug.Log("Clicked: " + resetButton.name);
resetGameData();
}
void resetGameData()
{
//Reset the position of the ball and set everything to the starting postion
transform.position = defaultBallPos;
transform.rotation = defaultBallRot;
transform.localScale = defaultBallScale;
//Reset other values below
}
void OnDisable()
{
//Un-Register Button Event
resetButton.onClick.RemoveAllListeners();
}
2.Call SceneManager.LoadScene("sceneName"); to load the scene again. You can call this function when Button.onClick.AddListener is called..
Create a UI Button then drag it to the resetButton slot in the Editor.
//Drag button from the Editor to this
public Button resetButton;
void OnEnable()
{
//Register Button Event
resetButton.onClick.AddListener(() => buttonCallBack());
}
private void buttonCallBack()
{
UnityEngine.Debug.Log("Clicked: " + resetButton.name);
//Get current scene name
string scene = SceneManager.GetActiveScene().name;
//Load it
SceneManager.LoadScene(scene, LoadSceneMode.Single);
}
void OnDisable()
{
//Un-Register Button Event
resetButton.onClick.RemoveAllListeners();
}
The decision to which method to use depends on how much Objects in your scene and how much time it takes your scene to load. If the scene has a huge world with baked light maps and HQ textures then go with #1.
For example you can reload main scene for restart game.
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);

Pause don't works (Unity c#)

I writing runner game on Unity (C#) for mobile phones.
I made Pause button on screen, using Canvas - Button.
Also I made code for Pause in Platformer2DUserControl script.
Here it is code of this script:
using UnityEngine;
using UnitySampleAssets.CrossPlatformInput;
namespace UnitySampleAssets._2D
{
[RequireComponent(typeof(PlatformerCharacter2D))]
public class Platformer2DUserControl : MonoBehaviour
{
private PlatformerCharacter2D character;
private bool jump;
public bool paused;
private void Awake()
{
character = GetComponent<PlatformerCharacter2D>();
paused = false;
}
private void Update()
{
/*if (Input.GetButton("Fire1"))
{
}*/
if (!jump)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1"); //&& CrossPlatformInputManager.GetButtonDown("Jump");
}
private void FixedUpdate()
{
// Read the inputs.
bool crouch = Input.GetKey(KeyCode.LeftControl);
// float h = CrossPlatformInputManager.GetAxis("Horizontal");
// Pass all parameters to the character control script.
character.Move(1, false, jump);
jump = false;
}
public void Pause()
{
if (!jump)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1"); //&& CrossPlatformInputManager.GetButtonDown("Jump");
paused = !paused;
if (paused)
{
jump = !jump;
Time.timeScale = 0;
}
else if (!paused)
{
// jump = Input.GetButton("Fire1");
Time.timeScale = 1;
}
}
}
}
My Pause Button is WORKS well. But when I tap it , my character is jumping and game is pausing.
I want to make that , when I tapping the button game just pausing and character don't jump.
How I can make it. Thank's for help.
I would advise you not to use the same input for jumping and pausing. Also, separate your jump and pause functionalities into separate functions. For pausing, create a UI button on the screen and make it call a public function on a Pause script, that will toggle pause. Then, in the same function, check if you are paused or not and adjust Time.timescale accordingly
You will have to attach the script with pause functionality on to an object that will always be in a screen (Say, a panel in your canvas or your MainCamera). Under the button, add a new onClick() function after dragging the GO with the apt script to the box. Then, select the public function aforementioned.
private bool paused = false;
//The function called by the button OnClick()
public void TogglePause()
{
paused = !paused;
if(paused)
Time.timescale = 0f;
else
Time.timescale = 1f;
}
Hope this helped!
Well, your code is messed up, but just remove the jump script from the pause method. So it will just pause...
public void Pause()
{
paused = !paused;
if (paused)
{
Time.timeScale = 0;
}
else
{
Time.timeScale = 1;
}
}
Note that Input.GetButton should only be called in Update
EDIT
The problem that you have to tap your screen to press the button. And the code jump = Input.GetButton("Fire1"); basically means "Am I tapping the screen?" So both JUMP and PAUSE are triggered.
One solution would be to put a canvas filling the whole screen under your buttons. You will trigger a JUMP action only when this canvas is clicked. So when you click your pause button, it will stop the propagation and won't click the full screen canvas, which won't trigger the jump action.
EDIT2
Try changing the lines (in the Update function) :
if (!jump)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1");
for :
if (!jump && !paused)
// Read the jump input in Update so button presses aren't missed.
jump = Input.GetButton("Fire1");
I think the button event is called before the Update, see reference
One solution would be possible make sure the raycast on of pause button.
I have always done it like this, essentially surround the entire fixed update (or wherever you have your game motion) with the paused-bool
private void FixedUpdate()
{
if (paused != true){
// Read the inputs.
bool crouch = Input.GetKey(KeyCode.LeftControl);
// float h = CrossPlatformInputManager.GetAxis("Horizontal");
// Pass all parameters to the character control script.
character.Move(1, false, jump);
jump = false;
}
}

Creating a start menu in Unity 3D

I was trying to create a start menu to my unity game when I found this script that enables a hidden sprite as soon as the game starts. The script then disables it when the player presses the left mouse button or space. When I try to make multiple sprites show up and the disappear, using the same script, only one sprite appears. I'm also trying to find a way to change the scipt so that the payer have to click on the actual sprite to disable it instead of just pressing the space key.
This is the script:
using UnityEngine;
using System.Collections;
public class StartScreen : 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;
}
}
}
It sounds as if you are looking to do something like this: http://docs.unity3d.com/ScriptReference/MonoBehaviour.OnMouseDown.html
Also, I always create a separate scene for my main menu systems, as they have done in that link.

Categories