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.
Related
The post is a bit long but the scripts are connected to each other.
When the game start first time it's saving after 3 seconds and fading for 3 seconds.
but in the game later when it's saving again it's showing the save text fading only once.
In this script I'm making the save and also set the time to start the saving and the time it will fade in/out :
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class SaveLoad : MonoBehaviour
{
public FadeInOutSaveGameText fadeInOutSaveGame;
public float timeToStartSaving;
public float savingFadeInOutTime;
private List<GameObject> objectsToSave = new List<GameObject>();
private void Awake()
{
SaveSystem.Init();
var objectsWithGenerateGuid = GameObject.FindObjectsOfType<GenerateGuid>().ToList();
if (objectsWithGenerateGuid.Count > 0)
{
for (int i = 0; i < objectsWithGenerateGuid.Count; i++)
{
objectsToSave.Add(objectsWithGenerateGuid[i].gameObject);
}
}
Debug.Log("Start");
for (int i = 0; i < objectsToSave.Count; i++)
{
Debug.Log($"{i}");
Debug.Log($"{objectsToSave[i].name}");
}
Debug.Log("End Init");
}
public void Save()
{
SaveGame saveGame = new SaveGame();
saveGame.saveObjects = new List<SaveObject>();
for (int i = 0; i < objectsToSave.Count; i++)
{
SaveObject saveObject = new SaveObject();
saveObject.transformSaver = new TransformSaver();
Debug.Log($"{i}");
Debug.Log($"{objectsToSave[i].name}");
saveObject.gameObjectUniqueID = objectsToSave[i].GetComponent<GenerateGuid>().uniqueGuidID;
var x = objectsToSave[i].GetComponents<Component>();
var stateQueryComponent = x.Where(component => component is IStateQuery).ToList();
List<KeyToValue> componentsState = new List<KeyToValue>();
foreach (var z in stateQueryComponent)
{
var w = z as IStateQuery;
componentsState.Add(new KeyToValue(w.UniqueId.ToString(), w.GetState()));
}
saveObject.transformSaver.position = objectsToSave[i].transform.position;
saveObject.transformSaver.rotation = objectsToSave[i].transform.rotation;
saveObject.transformSaver.scaling = objectsToSave[i].transform.localScale;
saveObject.componentsState = componentsState;
saveGame.saveObjects.Add(saveObject);
}
string json = JsonUtility.ToJson(saveGame);
SaveSystem.Save(json);
}
public void Load()
{
Dictionary<string, GameObject> uniqueIdToObject = objectsToSave
.ToDictionary(o => o.GetComponent<GenerateGuid>().uniqueGuidID, o => o);
var saveString = SaveSystem.Load();
if (saveString != null)
{
SaveGame saveGame = JsonUtility.FromJson<SaveGame>(saveString);
foreach (var saveObject in saveGame.saveObjects)
{
List<KeyToValue> loadedComponents = saveObject.componentsState;
var objectToSetState = uniqueIdToObject[saveObject.gameObjectUniqueID];
objectToSetState.transform.position = saveObject.transformSaver.position;
objectToSetState.transform.rotation = saveObject.transformSaver.rotation;
objectToSetState.transform.localScale = saveObject.transformSaver.scaling;
var y = objectToSetState.GetComponents<Component>();
var z = y.Where(component => component is IStateQuery).ToList();
Dictionary<string, IStateQuery> zz = z.ToDictionary(sq => (sq as IStateQuery).UniqueId.ToString(), sq => sq as IStateQuery);
foreach (KeyToValue keyvalue in loadedComponents)
{
zz[keyvalue.Key].SetState(keyvalue.Value);
}
}
}
}
public IEnumerator SaveWithTime()
{
yield return new WaitForSeconds(timeToStartSaving);
Save();
StartCoroutine(fadeInOutSaveGame.OverAllTime(savingFadeInOutTime));
}
}
At the bottom I created the to save with time :
public IEnumerator SaveWithTime()
{
yield return new WaitForSeconds(timeToStartSaving);
Save();
StartCoroutine(fadeInOutSaveGame.OverAllTime(savingFadeInOutTime));
}
The method OverAllTime make the fading depending on the time I set in this case 3 seconds :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FadeInOutSaveGameText : MonoBehaviour
{
public Canvas canvas;
public float fadingSpeed;
private bool stopFading = false;
private const float THRESHOLD = 0.01F;
// Start is called before the first frame update
void Start()
{
}
IEnumerator CanvasAlphaChangeOverTime(Canvas canvas, float duration)
{
float alphaColor = canvas.GetComponent<CanvasGroup>().alpha;
while (true)
{
alphaColor = (Mathf.Sin(Time.time * duration) + 1.0f) / 2.0f;
canvas.GetComponent<CanvasGroup>().alpha = alphaColor;
// only break, if current alpha value is close to 0 or 1
if (stopFading && Mathf.Abs(alphaColor) <= THRESHOLD)//if (stopFading && (Mathf.Abs(alphaColor) <= THRESHOLD || Mathf.Abs(alphaColor - 1) <= THRESHOLD))
{
break;
}
yield return null;
}
}
public IEnumerator OverAllTime(float time)
{
StartCoroutine(CanvasAlphaChangeOverTime(canvas, fadingSpeed));
yield return new WaitForSeconds(time);
stopFading = true;
}
}
And in this script at the bottom I'm starting the save :
private void Update()
{
if(dimLights.lightsDimmed == true && lightsDim == false && unlockCarte.HasOpened() == true
&& MenuController.LoadSceneForSavedGame == false)
{
m_state.naviLightsIntensity = dimLights.lightsToDim[0].intensity;
lightsDim = true;
var brainBlendTime = Camera.main.GetComponent<CinemachineBrain>();
saveLoad.timeToStartSaving = brainBlendTime.m_DefaultBlend.m_Time;
StartCoroutine(saveLoad.SaveWithTime());
}
}
I'm setting the timeToStartSaving to the time it takes to blend from one cinemachine camera to another camera in this case 5 seconds.
I used break points and it's getting to the SaveWithTime method when the value of timeToStartSaving is 5 and the value of savingFadeInOutTime stay 3 as before. Only the timeToStartSaving variable vlaue was 3 and changed to 5.
but ion the game the fading happens only once one time instead 3 times.
in the start of the game first time saving it does fading 3 times for 3 seconds. but on the second saving for some reason it's fading only one time even if the value of savingFadeInOutTime is 3.
You have to reset stopFading, otherwise your loop will always break after the first time reaching the zero threshold.
public IEnumerator OverAllTime(float time)
{
stopFading = false; // reset this, otherwise it stays true, after the first run
StartCoroutine(CanvasAlphaChangeOverTime(canvas, fadingSpeed));
yield return new WaitForSeconds(time);
stopFading = true;
}
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);
}
}
//...
}
}
}
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.
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);
}
So Im making tetris and I dont know how to draw the blocks( L,I,Z etc) I have one block as Texture2D and every class for the blocks look like this:
namespace Tetris
{
public class ZBlock
{
Color Color;
const int x = 4;
const int y = 4;
bool[,] vorm;
public bool[,] zblock()
{
vorm = new bool[x, y];
for(int i=0; i< x; i++)
for (int j=0; j<y; j++)
{
vorm[i, j] = false;
vorm[0, 0] = true;
vorm[1, 0] = true;
vorm[1, 1] = true;
vorm[2, 1] = true;
}
Color = Color.Purple;
return vorm;
}
}
and this is the block class:
namespace Tetris
{
public class Block
{
Texture2D block;
Vector2 BlockPosition = new Vector2(30, 30);
float FallTimer;
Random Random = new Random();
ZBlock zBlock = new ZBlock();
TBlock tBlock = new TBlock();
SBlock sBlock = new SBlock();
OBlock oBlock = new OBlock();
JBlock jBlock = new JBlock();
LBlock lBlock = new LBlock();
IBlock iblock = new IBlock();
public bool[,] blockvorm()
{
bool[,] vorm;
vorm = new bool[4, 4];
vorm[3, 3] = false;
int r = Random.Next(7);
if (r == 0)
{
ZBlock.zblock();
}
else if (r == 1)
{
TBlock.tblock();
}
else if (r == 2)
{
SBlock.sblock();
}
else if (r == 3)
{
OBlock.oblock();
}
else if (r == 4)
{
JBlock.jblock();
}
else if (r == 5)
{
LBlock.lblock();
}
else if (r == 6)
{
IBlock.iblock();
}
return vorm;
}
public TBlock TBlock
{
get { return tBlock; }
}
public ZBlock ZBlock
{
get { return zBlock; }
}
public SBlock SBlock
{
get { return sBlock; }
}
public OBlock OBlock
{
get { return oBlock; }
}
public JBlock JBlock
{
get { return jBlock; }
}
public LBlock LBlock
{
get { return lBlock; }
}
public IBlock IBlock
{
get { return iblock; }
}
public void Draw(GameTime gameTime, SpriteBatch spriteBatch, ContentManager Content)
{
block = Content.Load<Texture2D>("Block");
int[,] Grid = Tetris.GameWorld.TetrisGrid;
spriteBatch.Begin();
spriteBatch.Draw(?????????????);
spriteBatch.End();
}
So the problem is: I dont know how to draw those blocks (I know how to draw one block but I want the complete ones). I thought maybe ZBlock.vorm or ZBLock.zblock but both give errors.
Does anyone know how to draw the blocks?
Ok so here is a partial answer. What you want to do is basically just draw each block with a certain offset from the next block equal to: blockWidth / 2 in pixels. This means that the blocks will be correctly orientated without overlap.
Here is what you should put in the draw statement:
public void Draw(int theXPosition, int theYPosition, Color theColor, SpriteBatch theSpriteBatch, Texture2D theBlockTexture)
{
int aTextureStartX = Color * Convert.ToInt32(mBlockSize);
for (int aBlock = 0; aBlock < mNumberOfBlocks; aBlock++)
{
int aXPosition = (int)(theXPosition + (CurrentShape[Rotation, aBlock, 0] * mBlockSize));
int aYPosition = (int)(theYPosition + (CurrentShape[Rotation, aBlock, 1] * mBlockSize));
theSpriteBatch.Draw(theBlockTexture, new Rectangle(aXPosition, aYPosition, mBlockSize, mBlockSize), new Rectangle(aTextureStartX, 0, mBlockSize, mBlockSize),
}
}
This is from a blog: http://www.xnadevelopment.com/tutorials/fallingblocksyoumovetomakelines/fallingblocksyoumovetomakelines.shtml
The source code is at the top of the page.