How to disable Prefabs in Unity 2D? - c#

Im working on an 2d local multiplayer platformer Game. In the game are obstacles (Spikes), when the player collides with them the player will die. I want the Players of the game to decide if they would like to enable or disable the Spikes (the link leads to an image that will help understanding my problem)by pressing a Key. I already wrote a script for that and added it to my dontdestroyOnLoad GameManager. So all my spikes I built are the same Prefabs. My idea was to disable the main Prefab from the Project folder to disable all the spikes in every scene, until you press a Key to reactivate them again. The Problem is, that only the texture itself in the Project Panel disables and not the Spikes Prefabs in the Hierarchy, because the prefabs turn into regular gameObjects. How can I fix this?
My Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using System.Threading;
public class DisableSpikes : MonoBehaviour
{
[Header("Spikes")]
public KeyCode disableSpikes;
public float time;
public GameObject prefabSpikes;
public bool toggleSpikes = true;
[Header("Player Green")]
public KeyCode disableGreen;
public GameObject prefabGreen;
public bool toggleGreen = true;
[Header("Reset Score")]
public KeyCode resetScore;
// Start is called before the first frame update
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == true)
{
prefabSpikes.SetActive(false);
Debug.Log("Disable");
//Thread.Sleep(1000);
Invoke("SetFalse", time);
}
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == false)
{
prefabSpikes.SetActive(true);
Debug.Log("Anable");
//Thread.Sleep(1000);
Invoke("SetTrue", time);
}
if (Input.GetKeyDown(disableGreen) && toggleGreen == true)
{
prefabGreen.SetActive(false);
Debug.Log("Disable");
//Thread.Sleep(1000);
Invoke("SetFalse", time);
}
if (Input.GetKeyDown(disableGreen) && toggleGreen == false)
{
prefabGreen.SetActive(true);
Debug.Log("Anable");
//Thread.Sleep(1000);
Invoke("SetTrue", time);
}
if (Input.GetKeyDown(resetScore))
{
ScoreScriptBlue.scoreValueBlue = 0;
ScoreScriptRed.scoreValueRed = 0;
ScoreScriptGreen.scoreValueGreen = 0;
RoundScript.scoreValueRound = 0;
TimeScript.scoreValueTime = 0;
}
}
public void SetFalse()
{
toggleGreen = false;
toggleSpikes = false;
}
public void SetTrue()
{
toggleGreen = true;
toggleSpikes = true;
}
}

void Update() {
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == true){
// show
// renderer.enabled = true;
gameObject.GetComponent<Renderer>().enabled = true;
}
if (Input.GetKeyDown(disableSpikes) && toggleSpikes == false) {
// hide
// renderer.enabled = false;
gameObject.GetComponent<Renderer>().enabled = false;
}
}

Related

Using the same script for dealing with different triggers

I have a scene with multiple triggers and a Player with collider. My idea is to have one script to deal with all interactions between triggers and Player collider. I thought that using the same script to different GameObjects would be enough but this thing doesn't work properly. While working with one trigger I need to change one GameObject attached to this trigger but the other GameObjects with this script are changing as well.
One more detail about script is that I have two types of triggers: one is for GameObjects that need some input from user, some doesn't need it. I check it by checking two fields firstChoiceText and secondChoiceText. And if they are empty, the interaction with GameObject doesn't need any choice from the player. Otherwise, I show a plane with two option and change the text of this options using firstChoiceTextfield and secondChoiceTextfield.
So the main idea of script is that when the Player enter the trigger the script activates E key of keyboard. And if we press the E button and if this interaction wasn't done yet, we go further. We check the type of trigger and if we need to make a choice, we activate so called choiceMode of PlayerScript. PlayerScript is just a script for movements of the player, and we need choiceMode just to use W and S keys to select the choice. We make our choice and return to usual movement of the player. If we don't need to make a choice we just do some action and mark the trigger as isDone.
Everything works great with one trigger but when I use several triggers and GameObjects with InteractionScript, all this triggers are mixed up. While working with one trigger I accidentally change the other script. And I don't quite understand how to separate this scripts from each other.
Can anybody give me some piece of advice?
using UnityEngine;
using UnityEngine.UI;
public class InteractionScript : MonoBehaviour
{
[SerializeField]
private GameObject buttonE;
[SerializeField]
private GameObject choiceMenu;
[SerializeField]
private PlayerScript ps;
private int choiceNum = 0;
[SerializeField]
private Transform choicePoint;
[SerializeField]
private Text firstChoiceTextfield;
[SerializeField]
private Text secondChoiceTextfield;
[SerializeField]
private string firstChoiceText;
[SerializeField]
private string secondChoiceText;
[SerializeField]
private bool enteredMe;
[SerializeField]
private bool isDone;
void OnTriggerEnter2D() {
if (!isDone) {
enteredMe = true;
buttonE.SetActive(true);
Debug.Log("++");
}
}
void OnTriggerExit2D() {
if (!isDone) {
buttonE.SetActive(false);
enteredMe = false;
}
}
void Update() {
if (!isDone) {
if (Input.GetKeyDown(KeyCode.E) && buttonE.activeSelf && enteredMe) {
if (firstChoiceText != "" && secondChoiceText != "") {
choiceMenu.SetActive(true);
buttonE.SetActive(false);
ps.choiceMode = true;
Debug.Log("with choice");
} else {
Debug.Log("without choice");
//Action
buttonE.SetActive(false);
isDone = true;
}
}
}
if (ps.choiceMode) {
firstChoiceTextfield.text = firstChoiceText;
secondChoiceTextfield.text = secondChoiceText;
if (Input.GetKeyDown(KeyCode.W)) {
choiceNum += 1;
}
if (Input.GetKeyDown(KeyCode.S)) {
choiceNum -= 1;
}
if (choiceNum > 1) {
choiceNum = 0;
} else if (choiceNum < 0) {
choiceNum = 1;
}
if (choiceNum == 0) {
choicePoint.localPosition = new Vector3(0f, 24f, 0f);
if (Input.GetKeyDown(KeyCode.Return)) {
Debug.Log("choice1");
choiceMenu.SetActive(false);
isDone = true;
enteredMe = false;
ps.choiceMode = false;
}
} else if (choiceNum == 1) {
choicePoint.localPosition = new Vector3(0f, -21.5f, 0f);
if (Input.GetKeyDown(KeyCode.Return)) {
Debug.Log("choice2");
choiceMenu.SetActive(false);
isDone = true;
enteredMe = false;
ps.choiceMode = false;
}
}
}
}
}

Detect whether there is a button in Canvas when user taps on screen

I am building an AR application that spawns a 3d model when user taps the screen on to the ground plane.
But the issue I am facing is that, I have placed a button at the bottom of the screen to take a screenshot. On clicking the button,it does take screenshots,but it spawns an image below the button also.
How can I avoid this ? Can I use raycast to detect a button,and not spawn the object there ?
Below is the code I use to place objects
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.Experimental.XR;
using System;
public class ArTapToPlace : MonoBehaviour
{
public GameObject objectToPlace;
public GameObject placementIndicator;
private ARSessionOrigin arOrigin;
private Pose placementPose;
private bool placementPoseIsValid = false;
void Start()
{
arOrigin = FindObjectOfType<ARSessionOrigin>();
}
void Update()
{
UpdatePlacementPose();
UpdatePlacementIndicator();
if (placementPoseIsValid && Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
PlaceObject();
}
}
private void PlaceObject()
{
Instantiate(objectToPlace, placementPose.position, placementPose.rotation);
}
private void UpdatePlacementIndicator()
{
print(placementIndicator);
if (placementPoseIsValid)
{
placementIndicator.SetActive(true);
placementIndicator.transform.SetPositionAndRotation(placementPose.position, placementPose.rotation);
}
else
{
placementIndicator.SetActive(false);
}
}
private void UpdatePlacementPose()
{
var screenCenter = Camera.current.ViewportToScreenPoint(new Vector3(0.5f, 0.5f));
var hits = new List<ARRaycastHit>();
arOrigin.GetComponent<ARRaycastManager>().Raycast(screenCenter, hits, UnityEngine.XR.ARSubsystems.TrackableType.Planes);
print(hits.Count);
print(hits);
placementPoseIsValid = hits.Count > 0;
if (placementPoseIsValid)
{
placementPose = hits[0].pose;
var cameraForward = Camera.current.transform.forward;
var cameraBearing = new Vector3(cameraForward.x, 0, cameraForward.z).normalized;
placementPose.rotation = Quaternion.LookRotation(cameraBearing);
}
}
}
Depending on how your UI is setup you can probably use EventSystems.EventSystem.IsPointerOverGameObject for checking if the pointer is over a UI element and skip the placing in this case
if (placementPoseIsValid && Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
if(EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))) return;
PlaceObject();
}

Unity. controlling getcomponent with keyboard

I am a beginer and have a problem with coding Unity. I want to show and hide 3D text meshes using two arrow keys. one mesh at once. but it doesn't work as I thought. I think you will easily find out what problem is.
and one more question. It will be worked at mobile device and dozens of meshes are going to be used. I'm not sure this is the best way, so please tell me if there is better. (especially about performance and optimization issue) thanks to read.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class TextmeshSelection : MonoBehaviour{
public List <GameObject> Textmeshes = new List<GameObject> ();
public int Num;
void Update() {
if (Input.GetKeyDown(KeyCode.RightArrow)) {
Num++;
Renderer rend = Textmeshes[Num].GetComponent<Renderer> ();
if (rend.enabled)
rend.enabled = false;
else
rend.enabled = true;
}
if (Input.GetKeyDown(KeyCode.LeftArrow)) {
Num--;
Renderer rend = Textmeshes[Num].GetComponent<Renderer> ();
if (rend.enabled)
rend.enabled = false;
else
rend.enabled = true;
}
if (Num < 0) {
Num = 0;
Renderer rend = Textmeshes[Num].GetComponent<Renderer> ();
if (rend.enabled)
rend.enabled = false;
else
rend.enabled = true;
}
}
}
You shouldn't call GetComponent every time in Update but instead initialize all of them once e.g. in a dictionary
// Dictionary to store the references to the Renderer components
// Makes it easier to find them later
// You could as well only use a List instead and rely on the index
Dictionary<GameObject, Renderer> renderers = new Dictionary<GameObject, Renderer>();
private void Awake()
{
// Get all references already at app start
foreach(var textMesh in Textmeshes)
{
renderers[textMesh] = textMesh.GetComponent<Renderer>();
// And hide all from beginning
renderers[textMesh].enabled = false;
}
// Then enable only the first one depending what your Num is at start
SanatizeNum();
SetRendererEnabled(Num, true);
}
Then I would extract your code from Update into multiple methods to make it cleaner, remove redundancy and make it easier to maintain.
private void Update()
{
if (Input.GetKeyDown(KeyCode.RightArrow))
{
GoToNext();
}
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
GoToLast();
}
}
private void GoToNext()
{
// Hide the current renderer
SetRendererEnabled(Num, false);
Num++;
SanatizeNum();
// Show the new renderer
SetRendererEnabled(Num, true);
}
private void GoToLast()
{
SetRendererEnabled(Num, false);
Num--;
SanatizeNum();
SetRendererEnabled(Num, true);
}
private void SanatizeNum()
{
Num = Mathf.Clamp(Num, 0, Textmeshes.Count -1);
}
private void SetRendererEnabled(int index, bool enabled)
{
renderers[Textmeshes[index]].enabled = enabled;
}

Unity run non-looped animation again when button is pressed

I am currently creating some (non-looped) animations in Unity, that should start when a UI button is pressed. I have four buttons for four animations. Currently it works like that: I press button1 then animation1 is playing. If I then press button2 to play animation2, I can click again button1 to start animation1.
The thing is now: animation1 can only be played again, when another animation played before. So my question is: what do I need to change on the following code to let for example animation1 play every time button1 is pressed?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class MultiAnimations : MonoBehaviour {
public Animator cubeAnimator;
public bool anim1;
public bool anim2;
public bool anim3;
public bool anim4;
// Use this for initialization
void Start () {
cubeAnimator.enabled = false;
anim1 = false;
anim2 = false;
anim3 = false;
anim4 = false;
}
public void anim1Clicked ()
{
cubeAnimator.enabled = true;
anim1 = true;
anim2 = false;
anim3 = false;
anim4 = false;
if (anim1 == true)
{
cubeAnimator.SetBool("anim1", true);
cubeAnimator.SetBool("anim2", false);
cubeAnimator.SetBool("anim3", false);
cubeAnimator.SetBool("anim4", false);
}
}
public void anim2Clicked ()
{
cubeAnimator.enabled = true;
anim1 = false;
anim2 = true;
anim3 = false;
anim4 = false;
if (anim2 == true)
{
cubeAnimator.SetBool("anim1", false);
cubeAnimator.SetBool("anim2", true);
cubeAnimator.SetBool("anim3", false);
cubeAnimator.SetBool("anim4", false);
}
}
public void anim3Clicked()
{
cubeAnimator.enabled = true;
anim1 = false;
anim2 = false;
anim3 = true;
anim4 = false;
if (anim3 == true)
{
cubeAnimator.SetBool("anim1", false);
cubeAnimator.SetBool("anim2", false);
cubeAnimator.SetBool("anim3", true);
cubeAnimator.SetBool("anim4", false);
}
}
public void anim4Clicked()
{
cubeAnimator.enabled = true;
anim1 = false;
anim2 = false;
anim3 = false;
anim4 = true;
if (anim4 == true)
{
cubeAnimator.SetBool("anim1", false);
cubeAnimator.SetBool("anim2", false);
cubeAnimator.SetBool("anim3", false);
cubeAnimator.SetBool("anim4", true);
}
}
}
The animations are connected with transitions and bools. I oriented myself on this tutorial: https://www.youtube.com/watch?v=Q_5FhXF9a3k
SOLVED: The code provided in the YouTube tutorial is pretty circuitously. You can save a lot lines of code to simple write it like that:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MultiAnimations : MonoBehaviour {
public Animator cubeAnimator;
// Play Animation 1 - Copy this for the other animations
public void playAnimation1 ()
{
cubeAnimator.Play("animation1", -1, 0f);
}
}
Where's your update method? How are you calling these void methods?
Put an update method with conditions to check which button is clicked. So something like this:
void Update()
{
if (Input.GetKeyDown("space"))
{
//Play animation.
}
}
EDIT: Ok, when you press the button to play the first animation, and you press that button again, the animation is already true, so the animation already played. You need to set it to false after you're done playing the animation. Which is the reason why it plays again when you press other buttons.
EDIT: Try this style
public void anim1Clicked()
{
animation.Play("anim1");
}

When I run a script which is attached to my canvas to pop up a pause menu it only runs once

I attached a script to my canvas called PauseMenu which runs once and pauses initially and resumes but never pauses again when clicking escape. Here is my code:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
#if UNITY_EDITOR
using UnityEditor;
#endif
using RTS;
public class PauseMenu : MonoBehaviour {
Canvas canvas;
private Player player;
public Button Button2;
void Start()
{
Debug.Log ("asdf");
player = transform.root.GetComponent< Player >();
canvas = GetComponent<Canvas>();
canvas.enabled = false;
ResourceManager.MenuOpen = false;
Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
}
void Update()
{
Debug.Log ("Jake");
if(Input.GetKeyDown(KeyCode.Escape) && ResourceManager.MenuOpen == false) Pause();
//Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
//if(Input.GetKeyDown(KeyCode.Escape)) Pause();
//if(Input.GetKeyDown(KeyCode.Escape) && ResourceManager.MenuOpen == true) Resume();
}
public void Pause()
{
//if(Event.current.type == KeyCode.Escape)Debug.Log ("as12d12f2");
//if(Event.current.type == EventType.KeyDown)Debug.Log ("as12d12f2");
Debug.Log ("asdf2");
canvas.enabled = true;
Time.timeScale = 0.0f;
if(player) player.GetComponent< UserInput >().enabled = false;
//canvas.enabled = !canvas.enabled;
//Time.timeScale = Time.timeScale == 0 ? 1 : 0;
//ResourceManager.MenuOpen = true;
}
public void ResumePublic(){
Resume ();
}
private void Resume() {
Debug.Log ("asdf1");
Time.timeScale = 1.0f;
GetComponent< PauseMenu >().enabled = false;
if(player) player.GetComponent< UserInput >().enabled = true;
Cursor.visible = false;
canvas.enabled = false;
//Screen.showCursor = false;
//GetComponent<UserInput > ().enabled = true;
Debug.Log ("a2323sdf1");
ResourceManager.MenuOpen = false;
Button2.GetComponent<Button>().onClick.AddListener(() => { Resume();});
}
public void Quit()
{
#if UNITY_EDITOR
EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
}
What is happening is that this is attached to the parent object canvas which has the child object panel which has child objects button1,2and3 . And when the user presses escape the menu should pop up, pause time(which it does) and resume when either the resume button is clicked (button2) or escape is pressed however this only works once and the code no longer runs (ie the update procedure is no longer running) - please can someone help me fix this issue.
In your Resume() you set the PauseMenu Component to false
GetComponent< PauseMenu >().enabled = false;
But you did nothing to turn back that component in your pause function. So the script get disable after the first toggle and is never running again.
Could this be the problem?

Categories