I am trying to make next level availble when the glass it's full. For now the next level will unlock only when you click on the button "next level", and if you repeat the level, the next level wont be unblocked.
here is pictures for reference :
This is the locked levels script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
[ExecuteInEditMode]
public class LockedLevels : MonoBehaviour {
void Awake()
{
transform.GetChild(1).localScale = Vector3.one;
PlayerPrefs.SetInt("1", 1);
for (int i = 0; i < transform.GetChild(1).childCount; i++)
{
transform.GetChild(1).GetChild(i).gameObject.SetActive(false);
}
UnLockLevels();
}
void Update()
{
transform.GetChild(0).gameObject.GetComponent<Text>().text = transform.name;
transform.GetChild(0).gameObject.GetComponent<Text>().fontSize = 75;
if (Input.GetKeyDown(KeyCode.Delete))
{
PlayerPrefs.DeleteAll();
}
}
public void UnLockLevels()
{
if (PlayerPrefs.GetInt(gameObject.name) == 1)
{
transform.GetChild(0).gameObject.GetComponent<Text>().color = new Color(1,1,1,1) ;
GetComponent<Button>().interactable = true;
if (PlayerPrefs.GetInt("Star" + gameObject.name) == 3)
{
for (int i = 0; i < transform.GetChild(1).childCount; i++)
{
transform.GetChild(1).GetChild(i).gameObject.SetActive(true);
}
}
else if (PlayerPrefs.GetInt("Star" + gameObject.name) == 2)
{
for (int i = 0; i < transform.GetChild(1).childCount-1; i++)
{
transform.GetChild(1).GetChild(i).gameObject.SetActive(true);
}
}
else if (PlayerPrefs.GetInt("Star" + gameObject.name) == 1)
{
transform.GetChild(1).GetChild(0).gameObject.SetActive(true);
}
else if (PlayerPrefs.GetInt("Star" + gameObject.name) == 0)
{
for (int i = 0; i < transform.GetChild(1).childCount; i++)
{
transform.GetChild(1).GetChild(i).gameObject.SetActive(false);
}
}
}
else
{
GetComponent<Button>().interactable = false;
transform.GetChild(0).gameObject.GetComponent<Text>().color = new Color(1, 1, 1, .5f);
}
}
public void LevelMenu()
{
SceneManager.LoadScene(transform.name);
}
}
And this is the glassFill script :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GlassFill : MonoBehaviour {
int trigCont;
GameManager gm;
int Star;
// Use this for initialization
void Start () {
gm = FindObjectOfType<GameManager>();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "DynamicParticle")
{
if (trigCont == 0)
{
transform.parent.GetChild(0).GetComponent<SpriteRenderer>().sprite = gm.SurpriseGlass;
}
col.gameObject.tag = "InGlassWater";
col.gameObject.GetComponent<Rigidbody2D>().gravityScale = .3f;
col.gameObject.GetComponent<Rigidbody2D>().velocity = col.gameObject.GetComponent<Rigidbody2D>().velocity /4;
trigCont++;
if (trigCont > 50)
{
if (trigCont == 51)
{
if (Mathf.FloorToInt(gm.PenCapacity.value * 100) > 75)
{
Star = 3;
}
else if (Mathf.FloorToInt(gm.PenCapacity.value * 100) > 50)
{
Star = 2;
}
else if (Mathf.FloorToInt(gm.PenCapacity.value * 100) > 25)
{
Star = 1;
}
print(Star + "star");
transform.parent.GetChild(0).GetComponent<SpriteRenderer>().sprite = gm.HappyGlass;
Camera.main.GetComponent<AudioSource>().Play();
Invoke("nextScene", 2);
CancelInvoke("Check");
for (int i = 0; i < Camera.main.transform.childCount; i++)
{
if (Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>() != null)
{
Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>().Play();
}
}
}
}
else
{
CancelInvoke("Check");
Invoke("Check",5);
}
if (trigCont > 60)
{ //You can write a function over here if you want to give a star according to glass fill
print("two star");
}
if (trigCont > 70)
{
print("three star");
}
}
}
void Check()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
void nextScene()
{
PlayerPrefs.SetInt((SceneManager.GetActiveScene().buildIndex).ToString(), 1);
PlayerPrefs.SetInt("Star" + SceneManager.GetActiveScene().name, Star);
gm.LevComp.SetActive(true);
if (Star > 2)
{
gm.LevComp.transform.GetChild(0).gameObject.SetActive(true);
gm.LevComp.transform.GetChild(1).gameObject.SetActive(true);
gm.LevComp.transform.GetChild(2).gameObject.SetActive(true);
}
else if (Star > 1)
{
gm.LevComp.transform.GetChild(0).gameObject.SetActive(true);
gm.LevComp.transform.GetChild(1).gameObject.SetActive(true);
}
else if (Star>0)
{
gm.LevComp.transform.GetChild(0).gameObject.SetActive(true);
}
}
}
Let's assume you have an empty gameobject named levelManagerGO in your scene which contains the script LockedLevels. I believe the method which needs to be invoked is UnLockLevels(). So you should create a reference inside your script GlassFill to the empty gameobject containing LockedLevels, so you can invoke UnLockLevels().
levelManagerGO.Invoke("UnLockLevels", 0f);
https://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html
One way to check if the glass is full, could be to make many small child objects of the glass. Each of them having a collider. If all, or a certain percentage of, the child objects then are in contact with some kind of water. Then you will know that the glass is full and you can proceed to the next level. You can run this check maybe once per second.
Just have a list of each of those childobjects and check their status once per second or so.
Related
I have a script to instantiate a gameobject when the agent reaches its position, when instantiated it will randomly choose any of those 2, then 3, etc... this gameobjects belong to a parent (I use the random with childcount and getChild), however my agent won't move to the instances, just the original one. I've tried using it's position and it's localPosition and none of them works, actually if I use the local position it won't even do the set destination to the original one. I can't guess if its a navmesh problem or if there is an error with my scripting. I can add some images so if anyone can help me.
Script part:
if (plant_gameobject_father.transform.childCount != 0)
{
chosen_child = Random.Range(0, plant_gameobject_father.transform.childCount - 1);
plant_target = plant_gameobject_father.transform.GetChild(chosen_child);
Debug.Log(plant_target.transform.position);
agent_.SetDestination(plant_target.position);
Debug.Log(agent_.pathStatus);
}
Video Sample:
Navmesh working just on the original gameobject
EDIT: When using agent.remainingDistance to check how it's doing it: right after assigning the destination the remaining distance is 0, and when it "arrives" to the target it's remaining distance it's bigger than it should (I have a coroutine using yield return wait until agent.remainingDistance < 3.5f) and still it thinks it has reached destination.
I will upload full script for context understanding(it's a long one)
Could it be that the distances are too big? Mi terrain is larger that 2000 units in lenght.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class insect_IA : MonoBehaviour
{
public ciclo_dia_noche info_horas; //Programado para que haga 3 ciclos de actividad al dia y inactividad de noche.
public GameObject plant_type_small;
public GameObject plant_type_medium;
public GameObject plant_type_big;
Transform plant_target;
GameObject plant_gameobject_father;
public GameObject colmena;
public int objetivo_diario_recoleccion;
public int segundos_recoleccion_polen;
public int segundos_depositado_polen;
public int plant_selector;
public NavMeshAgent agent_;
int selector_accion;
public bool wander_is_happening;
public GameObject colmena_wander_childs;
public Transform wander_target;
public int is_performing_routine_insect;
public bool its_a_new_day;
public birth_controller puedo_reproducir;
public Collider tree_spawner1, tree_spawner2, tree_spawner3, selected_collider;
public Vector3 bounds_max, bounds_min;
public int random_number;
public float spawn_point_x, spawnpoint_z, spawnpoint_y;
public Vector3 spawn_point_tree;
public GameObject tree_big_prefab, tree_med_prefab, tree_peq_prefab;
public int chosen_child;
// Start is called before the first frame update
void Start()
{
}
private void Awake()
{
info_horas = GameObject.Find("Directional_Light").GetComponent<ciclo_dia_noche>();
plant_type_big = GameObject.Find("PLANTAS_GRAND");
plant_type_medium = GameObject.Find("PLANTAS_MED");
plant_type_small = GameObject.Find("PLANTAS_PEQ");
colmena = GameObject.Find("colmena");
puedo_reproducir = GameObject.Find("birth_controlator").GetComponent<birth_controller>();
tree_spawner1 = GameObject.Find("spawn_area1").GetComponent<Collider>();
tree_spawner2 = GameObject.Find("spawn_area2").GetComponent<Collider>();
tree_spawner3 = GameObject.Find("spawn_area3").GetComponent<Collider>();
tree_big_prefab = GameObject.Find("PLANTAS_GRAND/planta_grand");
tree_med_prefab = GameObject.Find("PLANTAS_MED/planta_med");
tree_peq_prefab = GameObject.Find("PLANTAS_PEQ/planta_peq");
agent_ = GetComponent<NavMeshAgent>();
colmena_wander_childs = colmena;
selector_accion = 0;
segundos_recoleccion_polen = 5;
segundos_depositado_polen = 5;
objetivo_diario_recoleccion = 3;
is_performing_routine_insect = 0;
its_a_new_day = true;
random_number = -1;
}
// Update is called once per frame
void Update()
{
if ((puedo_reproducir.plant_big_type.transform.childCount < puedo_reproducir.max_plant_big || puedo_reproducir.plant_med_type.transform.childCount < puedo_reproducir.max_plant_med || puedo_reproducir.plant_peq_type.transform.childCount < puedo_reproducir.max_plant_peq) && info_horas.segundos_globales < info_horas.duracion_dia)
{
insect_state();
}
if (wander_is_happening == false && puedo_reproducir.plant_big_type.transform.childCount > puedo_reproducir.max_plant_big && puedo_reproducir.plant_med_type.transform.childCount > puedo_reproducir.max_plant_med && puedo_reproducir.plant_peq_type.transform.childCount > puedo_reproducir.max_plant_peq)
{
wander_is_happening = true;
is_performing_routine_insect = 4;
StartCoroutine("regular_wander");
}
}
public void insect_state()
{
if (selector_accion == 0)
{
//Debug.Log("buscar padre arbol");
is_performing_routine_insect = 1;
selector_accion = -1;
cojo_un_padre_arbol();
selector_accion = 1;
}
if (selector_accion == 1)
{
//Debug.Log("elegir destino");
selector_accion = -2;
elijo_destino();
selector_accion = 2;
}
if (selector_accion == 2)
{
//Debug.Log("esperar a que llegue");
selector_accion = -3;
check_path();
}
if (selector_accion == 3)
{
//Debug.Log("cogiendo polen");
is_performing_routine_insect = 2;
StartCoroutine("cogiendo_polen");
}
if (selector_accion == 4)
{
//Debug.Log("de vuelta a la colmena");
selector_accion = -5;
volver_colmena();
check_path();
}
if (selector_accion == 5)
{
//Debug.Log("guardo polen");
is_performing_routine_insect = 3;
StartCoroutine("guardando_polen");
}
if (selector_accion == 6)
{
//Debug.Log("reinicio insecto");
is_performing_routine_insect = 4;
StartCoroutine("esperar_proxima_recoleccion");
}
}
public void cojo_un_padre_arbol()
{
if (puedo_reproducir.plant_big_type.transform.childCount < puedo_reproducir.max_plant_big)
{
plant_selector = 2;
}
else if (puedo_reproducir.plant_med_type.transform.childCount < puedo_reproducir.max_plant_med)
{
plant_selector = 1;
}
else if (puedo_reproducir.plant_peq_type.transform.childCount < puedo_reproducir.max_plant_peq)
{
plant_selector = 0;
}
if (plant_selector == 0)
{
plant_gameobject_father = plant_type_small;
}
if (plant_selector == 1)
{
plant_gameobject_father = plant_type_medium;
}
if (plant_selector == 2)
{
plant_gameobject_father = plant_type_big;
}
//Debug.Log("padre elegido:" + plant_gameobject_father);
}
public void elijo_destino()
{
if (plant_gameobject_father.transform.childCount != 0)
{
chosen_child = Random.Range(0, plant_gameobject_father.transform.childCount - 1);
plant_target = plant_gameobject_father.transform.GetChild(chosen_child);
Debug.Log(plant_target.transform.position);
agent_.SetDestination(plant_target.position);
Debug.Log(agent_.pathStatus);
}
else if(plant_gameobject_father.transform.childCount == 0)
{
wander_is_happening = true;
is_performing_routine_insect = 4;
StartCoroutine("regular_wander");
}
//Debug.Log(this.transform.position);
//Debug.Log("planta seleccionada: " + plant_target);
//Debug.Log(agent_.remainingDistance);
}
public void check_path()
{
StartCoroutine("esperar_destino");
}
public void volver_colmena()
{
agent_.SetDestination(colmena.transform.position);
create_plant();
}
public IEnumerator cogiendo_polen()
{
selector_accion = -4;
yield return new WaitForSeconds(segundos_recoleccion_polen);
selector_accion = 4;
}
public IEnumerator guardando_polen()
{
selector_accion = -6;
yield return new WaitForSeconds(segundos_depositado_polen);
selector_accion = 6;
}
public IEnumerator esperar_destino()
{
if (plant_target.tag == "planta_peq")
{
//Debug.Log(agent_.remainingDistance);
yield return new WaitUntil(() => agent_.remainingDistance < 1.7f);
//Debug.Log(agent_.remainingDistance);
agent_.isStopped = true;
agent_.ResetPath();
if (selector_accion == -3)
{
selector_accion = 3;
}
if (selector_accion == -5)
{
selector_accion = 5;
}
}
if (plant_target.tag == "planta_med")
{
//Debug.Log(agent_.remainingDistance);
yield return new WaitUntil(() => agent_.remainingDistance < 3.0f);
//Debug.Log(agent_.remainingDistance);
agent_.isStopped = true;
agent_.ResetPath();
if (selector_accion == -3)
{
selector_accion = 3;
}
if (selector_accion == -5)
{
selector_accion = 5;
}
}
if (plant_target.tag == "planta_grand")
{
Debug.Log(agent_.remainingDistance);
yield return new WaitUntil(() => agent_.remainingDistance < 3.5f);
Debug.Log(agent_.remainingDistance);
agent_.isStopped = true;
agent_.ResetPath();
if (selector_accion == -3)
{
selector_accion = 3;
}
if (selector_accion == -5)
{
selector_accion = 5;
}
}
}
public IEnumerator esperar_proxima_recoleccion()
{
selector_accion = -7;
yield return new WaitForSeconds(1);
selector_accion = 0;
}
public IEnumerator regular_wander()
{
wander_target = colmena_wander_childs.transform.GetChild(Random.Range(0, colmena_wander_childs.transform.childCount - 1));
agent_.SetDestination(wander_target.position);
yield return new WaitUntil(() => agent_.remainingDistance < 0.1f);
agent_.isStopped = true;
agent_.ResetPath();
yield return new WaitForSeconds(5);
wander_is_happening = false;
}
public void create_plant()
{
//Debug.Log("entro a crear una planta");
random_number = Random.Range(0, 3);
if (random_number == 0)
{
selected_collider = tree_spawner1;
}
if (random_number == 1)
{
selected_collider = tree_spawner2;
}
if (random_number == 2)
{
selected_collider = tree_spawner3;
}
bounds_max = selected_collider.bounds.max;
bounds_min = selected_collider.bounds.min;
spawn_point_x = Random.Range(bounds_min.x, bounds_max.x);
spawnpoint_z = Random.Range(bounds_min.z, bounds_max.z);
spawnpoint_y = bounds_max.y;
spawn_point_tree = new Vector3(spawn_point_x, spawnpoint_y, spawnpoint_z);
if (plant_target.tag == "planta_peq")
{
Instantiate(tree_peq_prefab, spawn_point_tree, Quaternion.identity, plant_type_big.transform);
}
if (plant_target.tag == "planta_med")
{
Instantiate(tree_med_prefab, spawn_point_tree, Quaternion.identity, plant_type_medium.transform);
}
if (plant_target.tag == "planta_grand")
{
Instantiate(tree_big_prefab, spawn_point_tree, Quaternion.identity, plant_type_big.transform);
}
Debug.Log(puedo_reproducir.plant_big_type.transform.childCount);
}
}
´´´´
There's a lot going on in your script. I'm going to put some calculated guesses here on what might help.
Your birth_controller object seems to have a separate list of all the small/medium/big plants. Are you 100% sure these reference the same as the ones in your Insect_IA object?
You are also using a lot of logic that seems very framerate dependant. Your update function itself calls insect_state() which functions as a state machine that runs through one step per frame, one frame at a time. At the same time, you start coroutines that work alongside that during all that. selector_accion is edited in both insect_state and a lot of those coroutines. Are you sure you're not deadlocking yourself out of certain values of selector_accion which are necessary for the navmesh to work?
Also: Random.Range(int minInclusive, int maxExclusive) is, for the int overload, EXCLUSIVE on the upper bound, so you can remove the -1 from plant_gameobject_father.transform.childCount - 1.
EDIT:
As discussed in the comments and in edits to the original post, the scale of your scene might be causing issues as well. If your navmesh agent cannot physically get as close as your yield WaitUntil statements are waiting for, that's probably deadlocking your logic.
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
public class GetChildsEditorWindow : EditorWindow
{
public Transform transform;
int levelsMin = 0, levelsMax = 50;
static int currentLevel;
List<Transform> allChildren = new List<Transform>();
static int oldLevel = 0;
// Add menu named "My Window" to the Window menu
[MenuItem("Get Childs/Get")]
static void Init()
{
oldLevel = currentLevel;
// Get existing open window or if none, make a new one:
GetChildsEditorWindow window = (GetChildsEditorWindow)EditorWindow.GetWindow(typeof(GetChildsEditorWindow), false, "Get Childs");
window.Show();
}
private void OnGUI()
{
GUILayout.Space(20);
transform = EditorGUILayout.ObjectField("Transform to get childs", transform, typeof(Transform), true) as Transform;
EditorGUI.BeginDisabledGroup(transform == null);
currentLevel = (int)EditorGUILayout.Slider("Slider", currentLevel, levelsMin, levelsMax);
EditorGUI.EndDisabledGroup();
if (allChildren != null && allChildren.Count > 0)
{
for (int i = 0; i < allChildren.Count; i++)
{
allChildren[i] = EditorGUILayout.ObjectField("Transform " + i.ToString(), allChildren[i], typeof(Transform), true) as Transform;
}
}
if (oldLevel != currentLevel)
{
if (transform != null)
{
allChildren = new List<Transform>();
IterateOverChild(transform, currentLevel, levelsMax);
oldLevel = currentLevel;
}
}
}
public void IterateOverChild(Transform original, int currentLevel, int maxLevel)
{
if (currentLevel > maxLevel) return;
for (var i = 0; i < original.childCount; i++)
{
Debug.Log($"{original.GetChild(i)}"); //Do with child what you need
allChildren.Add(original.GetChild(i));
IterateOverChild(original.GetChild(i), currentLevel + 1, maxLevel);
}
}
}
The script is working as i wanted , the question is if calling the loop inside the OnGUI is a bad practice performance ? because it's working fine i just wonder if it's wrong to have a loop inside the OnGUI.
So I made a game like Happy Glass and it's working fine, but sometimes when the level is completed, the screen to go to the next level appears and then immediately dissapears and u cant press next level
Here it's a picture for reference:
This screen appears and dissapears in a fraction of a second so you cant click to go to the next level.
I have a function that invokes the next level in a particular time, i tried to change the time but didnt work.
The finish line has this code attached to it ( line that makes you go to next level):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GlassFill : MonoBehaviour {
int trigCont;
GameManager gm;
int Star;
// Use this for initialization
void Start () {
gm = FindObjectOfType<GameManager>();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.tag == "DynamicParticle")
{
if (trigCont == 0)
{
transform.parent.GetChild(0).GetComponent<SpriteRenderer>().sprite = gm.SurpriseGlass;
}
col.gameObject.tag = "InGlassWater";
col.gameObject.GetComponent<Rigidbody2D>().gravityScale = .3f;
col.gameObject.GetComponent<Rigidbody2D>().velocity = col.gameObject.GetComponent<Rigidbody2D>().velocity /4;
trigCont++;
if (trigCont > 50)
{
if (trigCont == 51)
{
if (Mathf.FloorToInt(gm.PenCapacity.value * 100) > 75)
{
Star = 3;
}
else if (Mathf.FloorToInt(gm.PenCapacity.value * 100) > 50)
{
Star = 2;
}
else if (Mathf.FloorToInt(gm.PenCapacity.value * 100) > 25)
{
Star = 1;
}
print(Star + "star");
transform.parent.GetChild(0).GetComponent<SpriteRenderer>().sprite = gm.HappyGlass;
Camera.main.GetComponent<AudioSource>().Play();
Invoke("nextScene", 0);
CancelInvoke("Check");
for (int i = 0; i < Camera.main.transform.childCount; i++)
{
if (Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>() != null)
{
Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>().Play();
}
}
}
}
else
{
CancelInvoke("Check");
Invoke("Check",5);
}
if (trigCont > 60)
{ //You can write a function over here if you want to give a star according to glass fill
print("two star");
}
if (trigCont > 70)
{
print("three star");
}
}
}
void Check()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
void nextScene()
{
PlayerPrefs.SetInt((SceneManager.GetActiveScene().buildIndex).ToString(), 1);
PlayerPrefs.SetInt("Star" + SceneManager.GetActiveScene().name, Star);
gm.LevComp.SetActive(true);
if (Star > 2)
{
gm.LevComp.transform.GetChild(0).gameObject.SetActive(true);
gm.LevComp.transform.GetChild(1).gameObject.SetActive(true);
gm.LevComp.transform.GetChild(2).gameObject.SetActive(true);
}
else if (Star > 1)
{
gm.LevComp.transform.GetChild(0).gameObject.SetActive(true);
gm.LevComp.transform.GetChild(1).gameObject.SetActive(true);
}
else if (Star>0)
{
gm.LevComp.transform.GetChild(0).gameObject.SetActive(true);
}
}
}
As per your code, I believe the level is completed once trigCont > 50, and in that moment you display a menu with the number of starts and with the buttons to repeat the level or move to the next one.
If that is the case you should move Invoke("nextScene", 0); to the end of that condition. Something like
if (trigCont > 50)
{
if (trigCont == 51)
{
//...
for (int i = 0; i < Camera.main.transform.childCount; i++)
{
if (Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>() != null)
{
Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>().Play();
}
}
CancelInvoke("Check");
Invoke("nextScene", 0);
}
}
Also since that suppose to be the end of the level, I would add a flag just at the beginning of void OnTriggerEnter2D(Collider2D col) to ignore anything else happening in the scene. The best would be to stop/disable/destroy anything else in the scene. But I don't have information about what other elements may be interacting in your scene. So you can do:
int trigCont;
GameManager gm;
int Star;
bool sceneIsOver = false;
...
And the inside OnTriggerEnter2D:
void OnTriggerEnter2D(Collider2D col)
{
if(!sceneIsOver)
if (col.gameObject.tag == "DynamicParticle")
{
//...
if (trigCont > 50)
{
if (trigCont == 51)
{
//...
for (int i = 0; i < Camera.main.transform.childCount; i++)
{
if (Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>() != null)
{
Camera.main.transform.GetChild(i).GetComponent<ParticleSystem>().Play();
}
}
CancelInvoke("Check");
sceneIsOver = true;
Invoke("nextScene", 0);
}
}
//...
}
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
public class PrefabReplace : EditorWindow
{
[SerializeField] private GameObject prefab;
private bool selectionChanged;
private string objectsToSearch = "";
private List<GameObject> foundObjects = new List<GameObject>();
private List<GameObject> duplicatedObjects = new List<GameObject>();
private bool searched = false;
private int count = 0;
private int countChilds = 0;
private bool countChildren = false;
[MenuItem("Tools/Prefab Replace")]
static void CreateReplaceWithPrefab()
{
int width = 340;
int height = 300;
int x = (Screen.currentResolution.width - width) / 2;
int y = (Screen.currentResolution.height - height) / 2;
GetWindow<PrefabReplace>().position = new Rect(x, y, width, height);
}
private void OnGUI()
{
Searching();
GUILayout.Space(50);
Replacing();
}
private void Searching()
{
GUI.Label(new Rect(10, 20, 150, 20), "Search by name");
objectsToSearch = GUI.TextField(new Rect(90, 60, 150, 20), objectsToSearch, 25);
if (objectsToSearch != "")
{
GUI.enabled = true;
}
else
{
GUI.enabled = false;
}
GUILayout.Space(40);
if (GUILayout.Button("Search"))
{
foundObjects = new List<GameObject>();
duplicatedObjects = new List<GameObject>();
countChildren = true;
countChilds = 0;
count = 0;
foreach (GameObject gameObj in GameObject.FindObjectsOfType<GameObject>())
{
if (gameObj.name == objectsToSearch)
{
count += 1;
foundObjects.Add(gameObj);
}
}
if (foundObjects.Count > 0)
{
searched = true;
}
else
{
searched = false;
}
}
GUI.enabled = true;
if (count > 0)
GUI.TextField(new Rect(90, 85, 60, 15), count.ToString(), 25);
if (foundObjects.Count > 0 && countChildren == true)
{
for (int i = 0; i < foundObjects.Count; i++)
{
if (foundObjects[i].transform.childCount > 0)
{
countChilds += foundObjects[i].transform.childCount;
//GameObject duplicate = Instantiate(foundObjects[i]);
//duplicate.name = foundObjects[i].name;
//duplicatedObjects.Add(duplicate);
}
}
countChildren = false;
}
GUI.enabled = true;
if (countChilds > 0)
GUI.TextField(new Rect(90, 105, 60, 15), countChilds.ToString(), 25);
GUILayout.Space(100);
if (foundObjects.Count > 0)
EditorGUILayout.LabelField("Test");
}
private void Replacing()
{
GUILayout.Space(20);
GUILayout.BeginVertical(GUI.skin.box);
GUILayout.Label("Replacing");
GUILayout.Space(20);
prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
var selection = Selection.objects.OfType<GameObject>().ToList();
if (selectionChanged)
{
if (selection.Count == 0)
GUI.enabled = false;
for (var i = selection.Count - 1; i >= 0; --i)
{
var selectedObject = selection[i];
if (prefab != null && selection.Count > 0 &&
selectedObject.scene.name != null
&& prefab != PrefabUtility
.GetCorrespondingObjectFromSource(selectedObject))
{
GUI.enabled = true;
}
else
{
GUI.enabled = false;
}
}
}
else
{
GUI.enabled = false;
}
if (GUILayout.Button("Replace"))
{
InstantiatePrefab(selection);
selectionChanged = false;
}
GUILayout.Space(10);
GUI.enabled = true;
EditorGUILayout.LabelField("Selection count: " + Selection.objects.OfType<GameObject>().Count());
GUILayout.EndVertical();
}
private void OnInspectorUpdate()
{
Repaint();
}
private void OnSelectionChange()
{
selectionChanged = true;
}
private void InstantiatePrefab(List<GameObject> selection)
{
if (prefab != null && selection.Count > 0)
{
for (var i = selection.Count - 1; i >= 0; --i)
{
var selected = selection[i];
SceneManager.SetActiveScene(SceneManager.GetSceneByName(selected.scene.name));
var prefabType = PrefabUtility.GetPrefabType(prefab);
GameObject newObject;
if (prefabType == PrefabType.Prefab)
{
newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
}
else
{
newObject = Instantiate(prefab);
newObject.name = prefab.name;
}
if (newObject == null)
{
Debug.LogError("Error instantiating prefab");
break;
}
Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
newObject.transform.parent = selected.transform.parent;
newObject.transform.localPosition = selected.transform.localPosition;
newObject.transform.localRotation = selected.transform.localRotation;
newObject.transform.localScale = selected.transform.localScale;
newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
Undo.DestroyObjectImmediate(selected);
}
}
}
}
The searching part find object/s in the hierarchy and if there are any childs it's counting them too.
The replacing part replace a prefab with selection of objects. If for example I selected 20 Cubes and clicked the Replace button it will replace the selected Cubes with the prefab with the same position,rotation,scaling the cubes was.
But it's not replacing childs if there are any.
I need somehow when searching to add to a List/s the parent and childs and keep the hierarchy of each parent and his childs and then when clicking the replace button to replace it will the searching results objects and not with the selection like now and including the childs.
Example if my Hierarchy looks like this:
Cube1
Cube1
Cube1
Cube1
Cube1
Cube1
If I'm searching for Cube1 I shold find 6 Cubes and two of them childs.
And if for example I will replace them with Sphere prefab the Hierarchy should looks like:
Sphere
Sphere
Sphere
Sphere
Sphere
Sphere
What I need to do is to combine the searching part with the replacing part and make that the replacing will include also childs.
You could try something like this:
void ChangeObjectRecursively(Transform t)
{
for (int i = 0; i < t.childCount; i++)
{
ChangeObjectRecursively(t.getChild(i));
}
ChangeObject(t.gameObject);
}
I'm making a Balloon popping game, and I want to get a prize for some amount of score for example if you made a score of 10 you get a sticker or if you made a score of 20 you get a keyholder, and if you have score 0 you get a try again text so the problem is that when I finish the game it displays the try again text then when you open a different program (like going to a folder or anything outside of unity the text refresh and then I get the right text. I have tried using update, LateUpdate and FixedUpdate but nothing changes.
Here is the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class CountDownTimer : MonoBehaviour
{
//public string levelToLoad;
public float timer = 60f;
public Text timerSeconds;
public GameObject panelWin, score, time, pausa;
public int _playerScore;
public Text premio;
// Use this for initialization
void Start ()
{
timerSeconds = GetComponent<Text>();
time.SetActive(true);
panelWin.SetActive(false);
Time.timeScale = 1;
}
// Update is called once per frame
void LateUpdate ()
{
timer -= Time.deltaTime;
timerSeconds.text = timer.ToString("f0");
if (timer <=0)
{
if (PlayerPrefs.HasKey("Points"))
{
_playerScore = PlayerPrefs.GetInt("Points");
if (_playerScore == 0)
{
premio.text = "Intenta de nuevo!";
}
else
{
if (_playerScore >= 1 && _playerScore <= 10)
{
premio.text = "Tu premio es: una calco Bebé a bordo";
}
else
{
if (_playerScore >= 11 && _playerScore <= 20)
{
premio.text = "Tu premio es: un llavero Huggies";
}
else
{
if (_playerScore >= 21 && _playerScore <= 30)
{
premio.text = "Tu premio es: un pack de toallitas";
}
else
{
if (_playerScore >= 31 && _playerScore <= 40)
{
premio.text = "Tu premio es: un pack de
pañales";
}
else
{
if (_playerScore >= 41 && _playerScore >= 50)
{
premio.text = "Tu premio es: un bolso
Huggies";
}
}
}
}
}
}
}
panelWin.SetActive(true);
score.SetActive(false);
//time.SetActive(false);
pausa.SetActive(false);
if (panelWin == true)
{
Time.timeScale = 0;
}
}
}
public void DoARestart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
public void Menu()
{
SceneManager.LoadScene("TitleScreen");
}
}
This is the GameController Script:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class GameControllerScript : MonoBehaviour {
public Transform balloonPrefab;
public Text scoreDisplay;
public Text scoreDisplayWin;
public int _playerScore = 0;
//private int _multiplier = 1;
private float _timeSinceLastSpawn = 0.0f;
private float _timeToSpawn = 0.0f;
private List<Transform> _balloons;
private const int BALLOON_POOL = 30;
void Start () {
PlayerPrefs.SetInt("Points", 0);
_balloons = new List<Transform>();
for (int i = 0; i < BALLOON_POOL; i++) {
Transform balloon = Instantiate(balloonPrefab) as Transform;
balloon.parent = this.transform;
_balloons.Add(balloon);
}
SpawnBalloon();
GameStart();
}
/*void InitMultiplier() {
if (PlayerPrefs.HasKey("Multiplier")) {
_multiplier = Mathf.Max (1, PlayerPrefs.GetInt ("Multiplier"));
}
}*/
void InitPoints() {
if (PlayerPrefs.HasKey("Points"))
{
_playerScore = PlayerPrefs.GetInt("Points");
}
}
// Update is called once per frame
void Update () {
_timeSinceLastSpawn += Time.deltaTime;
if (_timeSinceLastSpawn >= _timeToSpawn)
{
SpawnBalloon();
}
}
void SpawnBalloon() {
_timeSinceLastSpawn = 0.0f;
_timeToSpawn = Random.Range (0.0f, 2.0f);
foreach (Transform b in _balloons) {
BalloonScript bs = b.GetComponent<BalloonScript>();
if (bs && !bs.isActive) {
bs.Activate();
break;
}
}
}
public void AddPoints(int points=1) {
_playerScore += points;
UpdateScoreDisplay();
}
public void GameOver() {
SavePoints();
SceneManager.LoadScene("TitleScreen");
}
void UpdateScoreDisplay() {
scoreDisplay.text = "Puntaje: " + _playerScore.ToString();// + "(x" +
_multiplier.ToString() + ")";
scoreDisplayWin.text = "Tu puntaje es: " + _playerScore.ToString();
}
public void GameStart() {
InitPoints();
//InitMultiplier();
UpdateScoreDisplay();
}
void OnApplicationPause() {
SavePoints();
}
void OnApplicationQuit() {
SavePoints();
}
void SavePoints() {
PlayerPrefs.SetInt("Points", _playerScore);
}
}
I dont have any errors on the console, would be very glad if anyone can help! Thanks!
Yep. You're not updating Points properly before it's used in CountDownTimer's LateUpdate()... Here is how your program flows:
In the GameController script, you set Points to 0 at Start().
In the CountDownTimer script, on every LateUpdate() (every frame), you check if playerPrefs.HasKey("Points"), which, from the first frame where GameController is enabled (runs Start()), which is probably the first game frame overall too, will result in true.
Right after that, you set _playerScore to Points (0), and selects a value for premio.text based on that.
Since...
Your GameController.GameOver() is probably not called in the first frame of the script/game, in fact, probably not called for several frames.
And since in the CountDownTimer.LateUpdate() (called every frame, including the first), from the first frame where GameControler.enabled == true (which is probably the first frame overall), Points will be there and equal 0.
In CountDownTimer.LateUpdate(), you will get "Intenta de nuevo!" from the first frame where GameControler.enabled == true (which is probably the first frame overall), for several frames, until GameControler.GameOver() is called.