I have 4 buttons and each of this button activates an image (Please see the link - Stacking). One script is attached to all the 4 buttons. There are 4 placeholders. I am using an approach of stack to stack images one after another. That is, if the first slot is empty, the image goes there. The button has two functions, to add image and to remove image. If the first slot's image is removed, the second slot's image is placed on 1st slot and third slot's image is placed on 2nd slot.
How do I add push and pop to this scenario?
Edit: I tried with List but I am lost. Could there be a way simpler approach?
public class ActivateStackImages : MonoBehaviour {
public GameObject ImageGameObject_To_Add; //Each instance of this script has unique image
public Vector3[] PositionOfImages; //4 positions
private ActivateStackImages [] activateImages; //Script added to 4 buttons
public bool Slot_1_Filled = false;
public bool Slot_2_Filled = false;
public bool Slot_3_Filled = false;
public bool Slot_4_Filled = false;
public bool isImageAdded = false;
private void Awake () {
activateImages= FindObjectsOfType (typeof (ActivateStackImages )) as ActivateStackImages [];
}
public void ActivateGraph () {
if (this.isImageAdded == false) {
for (int i = 0; i < activateImages.Length; i++) {
if (activateImages[i].Slot_1_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[0];
activateImages[i].Slot_1_Filled = true;
} else if (activateImages[i].Slot_2_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[2];
activateImages[i].Slot_2_Filled = true;
} else if (activateImages[i].Slot_3_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[2];
activateImages[i].Slot_3_Filled = true;
} else if (activateImages[i].Slot_4_Filled == false) {
ImageGameObject_To_Add.SetActive (true);
ImageGameObject_To_Add.GetComponent<RectTransform> ().anchoredPosition = PositionOfImages[3];
activateImages[i].Slot_4_Filled = true;
}
}
this.isImageAdded = true;
} else if (this.isImageAdded == true) {
ImageGameObject_To_Add.SetActive (false);
}
}
}
Stacking
Related
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;
}
}
I have troubles trying to make two different actions on trigger enter, its same name tag so I have no idea how to do it. For example I have ground button which has function, etc on first trigger enter it is disabling rotation of some other object, on second trigger enter it enables rotation back.Tried with bools but its not working well, Im thinking about int, but Im not sure. Thanks for any help, Im new in coding.
Heres the code;
if (other.gameObject.CompareTag("Player"))
{
var buttonRenderer = button.GetComponent<Renderer>();
buttonRenderer.material.SetColor("_Color", Color.red);
Rotationplane.isRotated = false;
}
EDIT:
#derHugoDont know mate, lost my mind...but finally I managed to do it over the if statements, I have no idea does it effect the performance. Heres code if someone has the same problem. Opening the bottle of whiskey...done for today.
private void FixedUpdate()
{
if(firstCollisionDone == true)
{
firstCollisionAavaliable = false;
secondCollisionAvaliable = true;
}
if(secondCollisionDone == true)
{
secondCollisionAvaliable = false;
firstCollisionAavaliable = true;
}
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if(firstCollisionAavaliable == true)
{
var buttonRenderer = button.GetComponent<Renderer>();
buttonRenderer.material.SetColor("_Color", Color.red);
Rotationplane.isRotated = false;
firstCollision = true;
}
if(secondCollisionAvaliable == true)
{
var buttonRenderer = button.GetComponent<Renderer>();
buttonRenderer.material.SetColor("_Color", Color.white);
Rotationplane.isRotated = true;
secondCollision = true;
}
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if(firstCollision == true)
{
firstCollisionDone = true;
firstCollision = false;
firstCollisionAavaliable = false;
secondCollisionDone = false;
}
if(secondCollision == true)
{
secondCollisionDone = true;
secondCollision = false;
secondCollisionAvaliable = false;
firstCollisionDone = false;
}
}
}
}```
I assume the flag you want to change is the Rotationplane.isRotated.
You could simply invert it's state like e.g.
if (other.gameObject.CompareTag("Player"))
{
var buttonRenderer = button.GetComponent<Renderer>();
buttonRenderer.material.SetColor("_Color", Color.red);
Rotationplane.isRotated = !Rotationplane.isRotated;
}
I am trying to draw a line from camera to a instantiated object.I am using the scene UnityARHitTest Example.When I touch on a vertical plane the object gets instantiated and i want to draw a line from camera to the object.When I move my device the line should show from the centre of my camera.For some reason line renderer is not showing when I call it in the Late update.
LineRenderer lins;
public GameObject Lineprefab;
bool HitTestWithResultType (ARPoint point, ARHitTestResultType resultTypes)
{
List<ARHitTestResult> hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface ().HitTest (point, resultTypes);
if (hitResults.Count > 0 && check==true)
{
foreach (var hitResult in hitResults)
{
Debug.Log ("Got hit!");
if (Select == 0)
{
Debug.Log("hit-zero!");
Instantiate(Instaobj[0], ForSelect);
check = false;
}
if (Select == 1)
{
Debug.Log("hit-one!");
Instantiate(Instaobj[1], ForSelect);
check = false;
}
if (Select == 2)
{
Debug.Log("hit-two!");
Instantiate(Instaobj[2], ForSelect);
check = false;
}
if (Select == 3)
{
Debug.Log("hit-three!");
Instantiate(Instaobj[3], ForSelect);
check = false;
}
if (Select == 4)
{
Debug.Log("hit-four!");
Instantiate(Instaobj[4], ForSelect);
check = false;
}
if (Select == 5)
{
Debug.Log("hit-five!");
Instantiate(Instaobj[5], ForSelect);
check = false;
}
m_HitTransform.position = UnityARMatrixOps.GetPosition (hitResult.worldTransform);
m_HitTransform.rotation = UnityARMatrixOps.GetRotation (hitResult.worldTransform);
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
obj.StopPlaneTracking();
if (GameObject.Find("debugPlanePrefab(Clone)"))
GameObject.Find("debugPlanePrefab(Clone)").SetActive(false);
else
Debug.Log("no prefab");
//lins.SetPosition(0, m_HitTransform.position);
//lins.SetPosition(1, obj.m_camera.transform.position);
return true;
}
}
return false;
}
When I use lins.setposition() in the above method(which is commented) a line is shown in the output.When I use lins.setposition() in the below LateUpdate() the output is not shown nothing comes.
private void Start()
{
spawngenerator();
}
void spawngenerator()
{
GameObject newline = Instantiate(Lineprefab);
lins = newline.GetComponent<LineRenderer>();
//lins.SetPosition(0, m_HitTransform.position);
//lins.SetPosition(1, obj.m_camera.transform.position);
}
private void LateUpdate()
{
lins.SetPosition(0,obj.m_camera.transform.position );
lins.SetPosition(1,m_HitTransform.position );
}
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine.SceneManagement;
public static class TransformSaver
{
[System.Serializable]
public class TransformInfo
{
public string sceneName;
public string name;
public Transform parent;
public Vector3 pos;
public Quaternion rot;
public Vector3 scale;
}
//Save Transform
public static void SaveTransform(Transform[] tranformToSave)
{
TransformInfo[] trnfrm = new TransformInfo[tranformToSave.Length];
for (int i = 0; i < trnfrm.Length; i++)
{
trnfrm[i] = new TransformInfo();
trnfrm[i].sceneName = tranformToSave[i].gameObject.scene.name;
trnfrm[i].name = tranformToSave[i].name;
trnfrm[i].parent = tranformToSave[i].parent;
trnfrm[i].pos = tranformToSave[i].localPosition;
trnfrm[i].rot = tranformToSave[i].localRotation;
trnfrm[i].scale = tranformToSave[i].localScale;
}
string jsonTransform = JsonHelper.ToJson(trnfrm, true);
File.WriteAllText(#"d:\json\json.txt", jsonTransform);
}
//Load Transform
public static Transform[] LoadTransform()
{
string jsonTransform = File.ReadAllText(#"d:\json\json.txt");
if (jsonTransform == null)
{
return null;
}
TransformInfo[] savedTransforms = JsonHelper.FromJson<TransformInfo>(jsonTransform);
GameObject[] gameObjects = new GameObject[savedTransforms.Length];
Transform[] loadedTransforms = new Transform[savedTransforms.Length];
for (int i = 0; i < gameObjects.Length; i++)
{
SceneManager.SetActiveScene(SceneManager.GetSceneByName(savedTransforms[i].sceneName));
gameObjects[i] = new GameObject();
loadedTransforms[i] = gameObjects[i].transform;
loadedTransforms[i].name = savedTransforms[i].name;
loadedTransforms[i].parent = savedTransforms[i].parent;
loadedTransforms[i].localPosition = savedTransforms[i].pos;
loadedTransforms[i].localRotation = savedTransforms[i].rot;
loadedTransforms[i].localScale = savedTransforms[i].scale;
}
return loadedTransforms;
}
}
The problem is that the method LoadTransform will return array of Transforms but also will create new GameObjects in the Editor in the Hierarchy.
What I want to do is to add something like a boolean flag or maybe other way so I can select if toe return the array of transforms with or without creating new gameobjects so I tried something like that:
//Load Transform
public static Transform[] LoadTransform(bool returnInfo)
{
string jsonTransform = File.ReadAllText(#"d:\json\json.txt");
if (jsonTransform == null)
{
return null;
}
TransformInfo[] savedTransforms = JsonHelper.FromJson<TransformInfo>(jsonTransform);
GameObject[] gameObjects = new GameObject[savedTransforms.Length];
Transform[] loadedTransforms = new Transform[savedTransforms.Length];
for (int i = 0; i < gameObjects.Length; i++)
{
SceneManager.SetActiveScene(SceneManager.GetSceneByName(savedTransforms[i].sceneName));
if (returnInfo == true)
{
gameObjects[i] = new GameObject();
loadedTransforms[i] = gameObjects[i].transform;
}
loadedTransforms[i].name = savedTransforms[i].name;
loadedTransforms[i].parent = savedTransforms[i].parent;
loadedTransforms[i].localPosition = savedTransforms[i].pos;
loadedTransforms[i].localRotation = savedTransforms[i].rot;
loadedTransforms[i].localScale = savedTransforms[i].scale;
}
return loadedTransforms;
}
I added a bool flag returnInfo but now loadedTransforms is null.
But the main goal is to decide if to return array of transforms with or without making instances for new gameobjects.
The problem is when I'm using Editorwindow type script and inside OnGUI to save and load the objects:
List<GameObject> selections = Selection.objects.OfType<GameObject>().ToList();
if (selections.Count > 0)
{
GUI.enabled = true;
}
else
{
GUI.enabled = false;
}
if (GUILayout.Button("Save selected objects data"))
{
if (selections.Count > 0)
{
tempTransformSelection = selections;
for (var i = selections.Count - 1; i >= 0; --i)
{
var selected = selections[i];
transformSelection.Add(selected.transform);
}
TransformSaver.SaveTransform(transformSelection.ToArray());
transformSelection = new List<Transform>();
}
}
var file = #"d:\json\json.txt";
FileInfo fi = new FileInfo(file);
// By default asume you don't want to show the button
// it will than only be enabled if the later conditions match
bool showButton = false;
// you can check this already here not in the loop
// if no file -> nothing to do
if (!File.Exists(#"d:\json\json.txt") || fi.Length <= 0) return;
// This is only reached if the file exists and is not empty
// check for null transforms
for (int i = 0; i < tempTransformSelection.Count(); i++)
{
// if not null do nothing
if (tempTransformSelection[i] != null)
continue;
// otherwise enable the button and leave the loop
showButton = true;
break;
}
// if not true then button won't be shown
if (showButton == true)
{
GUI.enabled = true;
}
else
{
GUI.enabled = false;
}
if (GUILayout.Button("Instantiate back deleted selected bojects"))
{
TransformSaver.LoadTransform(true);
showButton = false;
}
}
private void OnInspectorUpdate()
{
Repaint();
}
The main goal is to select objects in the hierachy in the editor. Then to click on "Save selected objects data" to save the selected object to a json file.
Then I want to make that only if one of the saved objects to the file is null in the hierarchy fro example if I deleted one or more of the objects in the saved file ! only then enable true the button "Instantiate back deleted selected bojects"
And then when clicking on the button "Instantiate back deleted selected bojects" set the button back to enabled false !
But the important thing is to check for null against the saved list of objects in the json file ! But once again I'm stuck with the tempTransformSelection and with how to enable false/true the button.
I'm making a menu for an Android 2d app, I have a bunch of UI panels in multiple menu's and when I press the next right or previous left button the script should set the next panel active and deactive the previous panel, I've tried doing this with a public class with gameobjects but that didn't work and thought a list should work.
In the Unity editor I've set the size to 4 and dragged 4 panels into the script
and I'm getting this error:
ArgumentOutOfRangeException: Argument is out of range.
Parameter name: index
Here is the relevant part of the script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MenuControl : MonoBehaviour
{
//Buttons
public GameObject ShipUpgradeRight;
public GameObject ShipUpgradeLeft;
//Ships
private int shipUpgradeSelected = 0;
List<GameObject> ShipList = new List<GameObject>();
public void Keyword (string keyword)
{
if (keyword == "ShipUpgradeLeft") {
shipUpgradeSelected--;
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected+1].SetActive (false);
}
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected--;
CheckShip ();
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected-1].SetActive (false);
}
}
}
Based on your comments and the actual question I see one possible problem.
The value of shipUpgradeSelected never gets increased. Moreover, shipUpgradeSelected has zero as initial value.
public void Keyword (string keyword)
{
if (keyword == "ShipUpgradeLeft") {
shipUpgradeSelected--;
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected+1].SetActive (false);
}
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected--;
CheckShip ();
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected-1].SetActive (false);
}
}
When keyword equals to ShipUpgradeRight or ShipUpgradeLeft the value of shipUpgradeSelected is decreased (so it's less than zero). And then you try to access the item of list at index that is less than zero.
But this is first problem.
Also you don't clamp (or don't cycle) value of shipUpgradeSelected. So for example you have
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected++;
CheckShip ();
ShipList[shipUpgradeSelected].SetActive (true);
ShipList[shipUpgradeSelected-1].SetActive (false);
}
If call Keyword("ShipUpgradeRight"); five times (for example), the value of shipUpgradeSelected is 5. And again it's out of range. So you need to decide how to clamp value of this variable.
This code works perfect:
public void Keyword(string keyword) {
if (keyword == "ShipUpgradeLeft") {
shipUpgradeSelected--;
if (shipUpgradeSelected < 0) {
shipUpgradeSelected = 0;
return;
}
ShipList[shipUpgradeSelected].SetActive(true);
if (shipUpgradeSelected + 1 < ShipList.Count) ShipList[shipUpgradeSelected + 1].SetActive(false);
else ShipList[0].SetActive(false);
}
if (keyword == "ShipUpgradeRight") {
shipUpgradeSelected++;
if (shipUpgradeSelected >= ShipList.Count) {
shipUpgradeSelected = ShipList.Count - 1;
return;
}
ShipList[shipUpgradeSelected].SetActive(true);
if (shipUpgradeSelected > 0) ShipList[shipUpgradeSelected - 1].SetActive(false);
else ShipList[ShipList.Count-1].SetActive(false);
}
}
but if i would start over i'd do it like this:
private void Start()
{
ShipUpgradeLeft.GetComponent<Button>().onClick.AddListener(() => { Previous(); });
ShipUpgradeRight.GetComponent<Button>().onClick.AddListener(() => { Next(); });
}
public void Next()
{
ShipList[shipUpgradeSelected].SetActive(false);
shipUpgradeSelected = Mathf.Clamp(shipUpgradeSelected++, 0, ShipList.Count - 1);
ShipList[shipUpgradeSelected].SetActive(true);
}
public void Previous()
{
ShipList[shipUpgradeSelected].SetActive(false);
shipUpgradeSelected = Mathf.Clamp(shipUpgradeSelected--, 0, ShipList.Count - 1);
ShipList[shipUpgradeSelected].SetActive(true);
}
Thanks to walther and d12frosted for helping me solve the issue