I use two-button to set the index value, once I click it gave value to the index.
public class tabbar : MonoBehaviour
{
private int index = 0;
public int buttonindex;
public GameObject[] pannels;
// Update is called once per frame
void Update()
{
for (int i = 0; i < pannels.Length; i++)
{
if (i == index)
{
pannels[i].SetActive(true);
}
else
{
pannels[i].SetActive(false);
}
}
}
public void IWasClicked()
{
index = buttonindex;
}
}
the first one is ok to set 0,but the second one no work??
any ideas?
Try this and don't forget to update your buttonIndex:
public class tabbar : MonoBehaviour
{
public int buttonIndex;
public GameObject[] pannels;
private void UpdatePannels(int index)
{
for (int i = 0; i < pannels.Length; i++)
{
pannels[i].SetActive(i == index);
}
}
public void IWasClicked()
{
UpdatePannels(buttonIndex);
}
}
Related
I am trying to create an simple quiz game, and below is my source code. I'm unable to get user input for the question. So I have added home and back button to the scene. Now that's also not working. Please take a look.
public class Level2UI: MonoBehaviour {
private List < string > sceneHistory = new List < string > ();
[SerializeField] private Level2Manager gameManager;
[SerializeField] private TextMeshProUGUI questionText;
[SerializeField] private List < Button > options;
[SerializeField] private Color CorrColor,
WrongColor,
NormalColor;
private Question question;
private bool answered;
// Start is called before the first frame update
void setButton() {
for (int i = 0; i < options.Count; i++) {
Button localBtn = options[i];
localBtn.onClick.AddListener(delegate {
ClickedAnswer(localBtn);
});
Debug.Log("testclick");
}
}
public void SetQuestion(Question question) {
this.question = question;
questionText.text = question.questionInfo;
List < string > answerList = ShuffleList.ShuffleListItems < string > (question.options);
for (int i = 0; i < options.Count; i++) {
options[i].GetComponentInChildren < TextMeshProUGUI > ().text = answerList[i];
Debug.Log("check");
options[i].name = answerList[i];
options[i].image.color = NormalColor;
}
answered = false;
setButton();
}
public void ClickedAnswer(Button btn) {
print("txt");
if (!answered) {
answered = true;
bool val = gameManager.Answer(btn.name);
if (val) {
btn.image.color = CorrColor;
Debug.Log("test1");
}
else {
btn.image.color = WrongColor;
Debug.Log("test");
}
}
}
public void LoadScene(string newScene) {
sceneHistory.Add(newScene);
SceneManager.LoadScene(newScene);
}
public bool PreviousScene() {
bool returnValue = false;
if (sceneHistory.Count >= 2) {
returnValue = true;
sceneHistory.RemoveAt(sceneHistory.Count - 1);
}
}
}
Did you assign the button? You need to assign the button or initialize it. Then put listener to it in the code or attach the method directly to the gameObject itself in the editor.
To assign a button
Button btn = transform.Find("btn").getComponent<Button>();
btn.onClick.AddListener(()=>{
// perform your action
});
I hope I helped a little? If not, I'm sorry.
i want to use variables levelButtons and levelunlocked from the script below :-
public class LevelSelector : MonoBehaviour
{
public Button[] levelButtons;
private void Start()
{
int levelunlocked = 1;
int levelReached = PlayerPrefs.GetInt("levelReached", levelunlocked);
for (int i = 0; i < levelButtons.Length; i++)
{
if (i + 1 > levelReached)
{
levelButtons[i].interactable = false;
}
}
}
}
and use them in this script below. it would be a huge help.
public class Level : MonoBehaviour
{
[SerializeField] int breakableBlocks;
SceneLoader sceneloader;
private void Start()
{
sceneloader = FindObjectOfType<SceneLoader>();
}
public void CountBreakableBlocks()
{
breakableBlocks++;
}
public void BlockDestroyed()
{
breakableBlocks--;
if (breakableBlocks <= 0)
{
sceneloader.LoadWinScreen();
}
}
}
any ideas?? its unity c#.
You can declare levelunlocked and levelReached outside of the Start method and make them public, like this:
public class LevelSelector : MonoBehaviour
{
public Button[] levelButtons;
public int levelunlocked = 1;
public int levelReached;
private void Start()
{
levelReached = PlayerPrefs.GetInt("levelReached", levelunlocked);
for (int i = 0; i < levelButtons.Length; i++)
{
if (i + 1 > levelReached)
{
levelButtons[i].interactable = false;
}
}
}
}
Then to access levelunlocked and levelReached, get a reference to LevelSelector by using GetComponent, or make the fields static and access them by doing LevelSelector.levelunlocked or LevelSelector.levelReached.
I'm trying to do a thing on Unity and got caught up;
This may be a bit complex, but see if you can help me:
What I got and what I want (image)
This is the script I got now
public class ClasseTest : MonoBehaviour{
public enum TiposDeMissoes
{
TipoMatarGente,
TipoPegarItem,
};
public TiposDeMissoes TiposMissoes;
[Serializable]
public class MatarGente
{
public int IDmissao;
public GameObject[] ObjetosAtivarPraMissao;
public GameObject[] Checkpoints;
public GameObject[] InimigosPraMatar;
}
[Serializable]
public class PegarItem
{
public int IDmissao;
public GameObject[] ObjetosAtivarPraMissao;
public GameObject[] Checkpoints;
public GameObject[] ItemsEntregar;
}
[Serializable]
public class Missoes
{
public TiposDeMissoes TiposMissoes;
public PegarItem[] PegarItem;
public MatarGente[] MatarGente;
}
public Missoes[] MissoesJogasso;
}
I only what to show the class PegarItem if PegarItem was chosen in the enum.
There's only PegarItem and MatarGente right now, but there will be more classes.
I did some research and find out Im supposed to use the OnInspectorGUI if I want to be that specific (if there's other way round, pls tell me)
I got 0 experience on CustomEditor so what I got so far is
[CustomEditor(typeof(ClasseTest))]
public class TestCustomInspector : Editor
{
public int numMissoes;
public override void OnInspectorGUI()
{
ClasseTest script = (ClasseTest)target;
numMissoes = EditorGUILayout.IntField("Numero de Missoes", numMissoes);
EditorGUILayout.LabelField("Editante");
var serializedObject = new SerializedObject(target);
var property = serializedObject.FindProperty("MissoesJogasso");
serializedObject.Update();
EditorGUILayout.PropertyField(property, true);
serializedObject.ApplyModifiedProperties();
for (int i = 0; i < numMissoes; i++)
{
script.TiposMissoes = (ClasseTest.TiposDeMissoes)EditorGUILayout.EnumPopup("TIPO DE MISSAO", script.TiposMissoes);
if (script.TiposMissoes == ClasseTest.TiposDeMissoes.TipoMatarGente)
{
script.TiposMissoes = (ClasseTest.TiposDeMissoes)EditorGUILayout.EnumPopup("Matar Gentes", script.TiposMissoes);
}
if (script.TiposMissoes == ClasseTest.TiposDeMissoes.TipoPegarItem)
{
script.TiposMissoes = (ClasseTest.TiposDeMissoes)EditorGUILayout.EnumPopup("Pegar Item", script.TiposMissoes);
}
}
}
}
And that means, in the editor:
If I change the value of one enum, all the others copy it (image)
And That's exactly what I do not want.
And y'all, keep in mind when the editor chooses MatarGente or PegarItem I'd like to show all those possible variables that these classes hold. That includes arrays with non-specific lengths.
And also, if there's 2 'MatarGente' I'd like to be able to fill those arrays with different objects and retrieve that information later to use it somewhere else.
Tried to understand what you were doing. Your mistake was not modifying the array elements and few other issues.
This is your new ClasseTest:
using System;
using UnityEngine;
using System.Collections.Generic;
public class ClasseTest : MonoBehaviour
{
public enum TiposDeMissoes
{
TipoMatarGente,
TipoPegarItem,
}
[Serializable]
public class MatarGente
{
public int IDmissao;
public GameObject[] ObjetosAtivarPraMissao;
public GameObject[] Checkpoints;
public GameObject[] InimigosPraMatar;
}
[Serializable]
public class PegarItem
{
public int IDmissao;
public GameObject[] ObjetosAtivarPraMissao;
public GameObject[] Checkpoints;
public GameObject[] ItemsEntregar;
}
[Serializable]
public class Missoes
{
public TiposDeMissoes TiposMissoes;
public PegarItem[] PegarItem;
public MatarGente[] MatarGente;
}
public List<Missoes> MissoesJogasso;
public int NumMissoes;
}
This is your new TestCustomInspector class:
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
[CustomEditor(typeof(ClasseTest))]
public class TestCustomInspector : Editor
{
public override void OnInspectorGUI()
{
ClasseTest script = (ClasseTest)target;
script.NumMissoes = EditorGUILayout.IntField("Numero de Missoes", script.NumMissoes);
// Ensure it cannot go into negative numbers.
if (script.NumMissoes < 0) script.NumMissoes = 0;
// Create the list if it does not exist.
if(script.MissoesJogasso == null) script.MissoesJogasso = new List<ClasseTest.Missoes>();
// numMissoes being greater than the current count means we need to extend the list.
if (script.NumMissoes > script.MissoesJogasso.Count)
{
for (int i = 0; i < script.NumMissoes; i++)
{
script.MissoesJogasso.Add(new ClasseTest.Missoes());
}
}
// numMissoes being less than the current count means we need to decrease the list.
else if(script.NumMissoes < script.MissoesJogasso.Count)
{
int difference = script.MissoesJogasso.Count - script.NumMissoes;
// Remove the last element difference number of times.
for (int i = 0; i < difference; i++)
{
script.MissoesJogasso.RemoveAt(script.MissoesJogasso.Count - 1);
}
}
var serializedTarget = new SerializedObject(target);
for (int i = 0; i < script.MissoesJogasso.Count; i++)
{
var missoes = script.MissoesJogasso[i];
switch(missoes.TiposMissoes)
{
case ClasseTest.TiposDeMissoes.TipoMatarGente:
missoes.TiposMissoes = (ClasseTest.TiposDeMissoes)EditorGUILayout.EnumPopup("Matar Gentes", missoes.TiposMissoes);
DrawProperty(serializedTarget, string.Format("MissoesJogasso.Array.data[{0}].MatarGente", i));
break;
case ClasseTest.TiposDeMissoes.TipoPegarItem:
missoes.TiposMissoes = (ClasseTest.TiposDeMissoes)EditorGUILayout.EnumPopup("Pegar Item", missoes.TiposMissoes);
DrawProperty(serializedTarget, string.Format("MissoesJogasso.Array.data[{0}].PegarItem", i));
break;
}
}
}
private void DrawProperty(SerializedObject serializedObject, string propertyName)
{
var property = serializedObject.FindProperty(propertyName);
serializedObject.Update();
EditorGUILayout.PropertyField(property, true);
serializedObject.ApplyModifiedProperties();
}
}
In Unity:
Hope this works.
So in this game when the player picks up items from the scene I'm trying to have it draw the item in their inventory. The problem is whenever the player picks up an item the sprite is drawn in the wrong area. I'm calling additem from itemid class and sending it to the inventory class. when it is sent the id goes with it and that's how it knows which item to draw. I'm trying to draw it in the next empty slot in the inventory. in the inventory class if I comment in those AddItem(0) (or any number that has an item with it) it draws the sprite in the right location. any ideas on why it is drawing the sprite in the wrong location when it is called from the itemid class
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Inventory : MonoBehaviour {
ItemDataBase database;
GameObject inventoryPanel;
GameObject slotPanel;
public GameObject inventorySlot;
public GameObject inventoryItem;
int slotAmount;
public List<Item> items = new List<Item>();
public List<GameObject> slots = new List<GameObject>();
void Start()
{
database = GetComponent<ItemDataBase>();
slotAmount = 20;
inventoryPanel = GameObject.Find("Inventory Panel");
slotPanel = inventoryPanel.transform.FindChild("Slot Panel").gameObject;
for (int i = 0; i < slotAmount; i++)
{
items.Add(new Item());
// and empty slot
slots.Add(Instantiate(inventorySlot));
slots[i].GetComponent<Slot>().id = i;
//set parent to slot panel
slots[i].transform.SetParent(slotPanel.transform);
}
// AddItem(0);
// AddItem(1);
// AddItem(1);
// AddItem(1);
// Debug.Log(items[1].Title);
inventoryPanel.SetActive(false);
}
void Update()
{
if (Input.GetKeyDown("i") && inventoryPanel.activeSelf == false)
{
inventoryPanel.SetActive(true);
}
else if(Input.GetKeyDown("i") && inventoryPanel.activeSelf == true)
{
inventoryPanel.SetActive(false);
}
}
public void AddItem(int id)
{
inventoryPanel.SetActive(true);
Item itemToAdd = database.FetchItemByID(id);
if (itemToAdd.Stackable && checkIfItemIsInInventory(itemToAdd))
{
for (int i = 0; i < items.Count; i++)
{
if (items[i].ID == id)
{
ItemData data = slots[i].transform.GetChild(0).GetComponent<ItemData>();
data.amount++;
data.transform.GetChild(0).GetComponent<Text>().text = data.amount.ToString();
break;
}
}
}
else
{
for (int i = 0; i < items.Count; i++)
{
// in video had this set to -1
if (items[i].ID == -1)
{
items[i] = itemToAdd;
GameObject itemObj = Instantiate(inventoryItem);
itemObj.GetComponent<ItemData>().item=itemToAdd;
itemObj.GetComponent<ItemData>().amount = 1;
itemObj.GetComponent<ItemData>().slot = i;
itemObj.transform.SetParent(slots[i].transform);
itemObj.transform.position = Vector2.zero;
itemObj.GetComponent<Image>().sprite = itemToAdd.Sprite;
itemObj.name = itemToAdd.Title;
itemObj.name = itemToAdd.Title;
break;
}
}
}
}
bool checkIfItemIsInInventory(Item item)
{
for (int i = 0; i<items.Count; i++)
{
if (items[i].ID == item.ID)
{
return true;
}
}
return false;
}
void RemoveItem (int id)
{
for (int i = 0; i < items.Count; i++)
{
if (items[i].ID == id)
{
items[i] = new Item();
break;
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemId : MonoBehaviour {
public int id;
public Inventory additem;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter2D (Collider2D other)
{
if (other.gameObject.tag == "Player")
{
Debug.Log(id);
additem.AddItem(1);
Destroy(gameObject);
}
}
}
I was having trouble converting an object pool script from UnityScript to C#, which I got a lot of good help with here. Now I'm having an issue trying to actually get a game object from the pool. I have three scripts all interacting with one another, so I'm not quite sure where it's going wrong. Here are the two scripts for the object pool, which I believe are all squared away and they're not giving any errors:
public class EasyObjectPool : MonoBehaviour {
[System.Serializable]
public class PoolInfo{
[SerializeField]
public string poolName;
public GameObject prefab;
public int poolSize;
public bool canGrowPoolSize = true;
}
[System.Serializable]
public class Pool{
public List<PoolObject> list = new List<PoolObject>();
public bool canGrowPoolSize;
public void Add (PoolObject poolObject){
list.Add(poolObject);
}
public int Count (){
return list.Count;
}
public PoolObject ObjectAt ( int index ){
PoolObject result = null;
if(index < list.Count) {
result = list[index];
}
return result;
}
}
static public EasyObjectPool instance ;
[SerializeField]
PoolInfo[] poolInfo = null;
private Dictionary<string, Pool> poolDictionary = new Dictionary<string, Pool>();
void Start () {
instance = this;
CheckForDuplicatePoolNames();
CreatePools();
}
private void CheckForDuplicatePoolNames() {
for (int index = 0; index < poolInfo.Length; index++) {
string poolName= poolInfo[index].poolName;
if(poolName.Length == 0) {
Debug.LogError(string.Format("Pool {0} does not have a name!",index));
}
for (int internalIndex = index + 1; internalIndex < poolInfo.Length; internalIndex++) {
if(poolName == poolInfo[internalIndex].poolName) {
Debug.LogError(string.Format("Pool {0} & {1} have the same name. Assign different names.", index, internalIndex));
}
}
}
}
private void CreatePools() {
foreach(PoolInfo currentPoolInfo in poolInfo){
Pool pool = new Pool();
pool.canGrowPoolSize = currentPoolInfo.canGrowPoolSize;
for(int index = 0; index < currentPoolInfo.poolSize; index++) {
//instantiate
GameObject go = Instantiate(currentPoolInfo.prefab) as GameObject;
PoolObject poolObject = go.GetComponent<PoolObject>();
if(poolObject == null) {
Debug.LogError("Prefab must have PoolObject script attached!: " + currentPoolInfo.poolName);
} else {
//set state
poolObject.ReturnToPool();
//add to pool
pool.Add(poolObject);
}
}
Debug.Log("Adding pool for: " + currentPoolInfo.poolName);
poolDictionary[currentPoolInfo.poolName] = pool;
}
}
public PoolObject GetObjectFromPool ( string poolName ){
PoolObject poolObject = null;
if(poolDictionary.ContainsKey(poolName)) {
Pool pool = poolDictionary[poolName];
//get the available object
for (int index = 0; index < pool.Count(); index++) {
PoolObject currentObject = pool.ObjectAt(index);
if(currentObject.AvailableForReuse()) {
//found an available object in pool
poolObject = currentObject;
break;
}
}
if(poolObject == null) {
if(pool.canGrowPoolSize) {
Debug.Log("Increasing pool size by 1: " + poolName);
foreach (PoolInfo currentPoolInfo in poolInfo) {
if(poolName == currentPoolInfo.poolName) {
GameObject go = Instantiate(currentPoolInfo.prefab) as GameObject;
poolObject = go.GetComponent<PoolObject>();
//set state
poolObject.ReturnToPool();
//add to pool
pool.Add(poolObject);
break;
}
}
} else {
Debug.LogWarning("No object available in pool. Consider setting canGrowPoolSize to true.: " + poolName);
}
}
} else {
Debug.LogError("Invalid pool name specified: " + poolName);
}
return poolObject;
}
}
And:
public class PoolObject : MonoBehaviour {
[HideInInspector]
public bool availableForReuse = true;
void Activate () {
availableForReuse = false;
gameObject.SetActive(true);
}
public void ReturnToPool () {
gameObject.SetActive(false);
availableForReuse = true;
}
public bool AvailableForReuse () {
//true when isAvailableForReuse & inactive in hierarchy
return availableForReuse && (gameObject.activeInHierarchy == false);
}
}
The original UnityScript said to retrieve an object from the pool with this statement:
var poolObject : PoolObject = EasyObjectPool.instance.GetObjectFromPool(poolName);
This is how I tried to do that in my shooting script with it trying to fire a bullet prefab from the pool:
public class ShootScript : MonoBehaviour {
public PoolObject poolObject;
private Transform myTransform;
private Transform cameraTransform;
private Vector3 launchPosition = new Vector3();
public float fireRate = 0.2f;
public float nextFire = 0;
// Use this for initialization
void Start () {
myTransform = transform;
cameraTransform = myTransform.FindChild("BulletSpawn");
}
void Update () {
poolObject = EasyObjectPool.instance.GetObjectFromPool<poolName>();
if(Input.GetButton("Fire1") && Time.time > nextFire){
nextFire = Time.time + fireRate;
launchPosition = cameraTransform.TransformPoint(0, 0, 0.2f);
poolObject.Activate();
poolObject.transform.position = launchPosition;
poolObject.transform.rotation = Quaternion.Euler(cameraTransform.eulerAngles.x + 90, myTransform.eulerAngles.y, 0);
}
}
}
My shoot script is giving me two errors:
1. The type or namespace name 'poolName' could not be found. Are you missing a using directive or an assembly reference?
For the line:
poolObject = EasyObjectPool.instance.GetObjectFromPool<poolName>();
2. 'PoolObject.Activate()' is inaccessible due to its protection level
For the line:
poolObject.Activate();
Did I mis-translate the UnityScript or am I missing something else? Any input is greatly appreciated
I think your object pool is incorrectly programmed. When you have a method like CheckForDuplicatePoolNames() ask yourself if you need a different collection like dictionary.
Keep it simple.
I recently implemented one and I have tested. It works pretty well.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[System.Serializable]
public class PoolObject{
public GameObject prefab;
public int startNum;
public int allocateNum;
public Transform anchor;
}
public class ObjectPool<T> : MonoBehaviour where T:Component{
public PoolObject[] poolObjects;
public bool ______________;
public Dictionary<string,Queue<T>> pool = new Dictionary<string, Queue<T>> ();
public Dictionary<string, List<T>> spawned = new Dictionary<string, List<T>> ();
public Transform anchor;
public void Init(){
InitPool ();
StartAllocate ();
}
public T Spawn(string type){
if (pool [type].Count == 0) {
int i = FindPrefabPosition(type);
if(poolObjects[i].allocateNum == 0)
return null;
Allocate(poolObjects[i], poolObjects[i].allocateNum);
}
T t = pool [type].Dequeue ();
spawned[type].Add (t);
t.gameObject.SetActive (true);
return t;
}
public void Recycle(T t){
if (spawned [t.name].Remove (t)) {
pool[t.name].Enqueue(t);
t.gameObject.SetActive(false);
}
}
private void Allocate(PoolObject po, int number){
for (int i=0; i<number; i++) {
GameObject go = Instantiate (po.prefab) as GameObject;
go.name = po.prefab.name;
go.transform.parent = po.anchor != null? po.anchor : anchor;
T t = go.GetComponent<T>();
pool[t.name].Enqueue(t);
t.gameObject.SetActive(false);
}
}
private int FindPrefabPosition(string type){
int position = 0;
while (poolObjects[position].prefab.name != type) {
position++;
}
return position;
}
void InitPool(){
if(anchor == null)
anchor = new GameObject("AnchorPool").transform;
for (int i =0; i<poolObjects.Length; i++) {
T t = poolObjects[i].prefab.GetComponent<T>();
t.name = poolObjects[i].prefab.name;
pool[t.name] = new Queue<T>();
spawned[t.name] = new List<T>();
}
}
void StartAllocate(){
for (int i=0; i<poolObjects.Length; i++) {
Allocate(poolObjects[i], poolObjects[i].startNum );
}
}
}
Example:
public class CoinsPool : ObjectPool<CoinScript>{}
In the unity inspector configure the coin prefab, the startNum and the allocateNum.
Somewhere:
void Awake(){
coinsPool = GetComponent<CoinsPool>();
coinsPool.Init();
}
CoinScript cs = coinsPool.Spawn("Coin"); //Coin is the name of the coin prefab.
Later
coinsPool.Recycle(cs);
The thing you write within <> should be a class name like PoolObject if the function is generic, which it is not. So to solve this you simply need to change
poolObject = EasyObjectPool.instance.GetObjectFromPool<poolName>();
to
string poolName = "thePoolNameYouWant";
poolObject = EasyObjectPool.instance.GetObjectFromPool(poolName);
Function are private by default so to solve the "inaccessible due to its protection level" error you need to make the function public by changing this
void Activate () {
availableForReuse = false;
gameObject.SetActive(true);
}
to this
public void Activate () {
availableForReuse = false;
gameObject.SetActive(true);
}