I am trying to load different levels in my puzzle game, but when I hide the levels that aren't being used, GameObject.Find(); does not work. Is there a way to substitute this function for one that can find objects that are hidden?
Well, it's pretty dirty but if you don't have a previous reference to the object, you can use this method under Resources class: public static T[] FindObjectsOfTypeAll();
From the docs example:
Contrary to Object.FindObjectsOfType this function will also list
disabled objects.
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class ExampleScript : MonoBehaviour
{
List<GameObject> GetAllObjectsOnlyInScene()
{
List<GameObject> objectsInScene = new List<GameObject>();
foreach (GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[])
{
if (!EditorUtility.IsPersistent(go.transform.root.gameObject) && !(go.hideFlags == HideFlags.NotEditable || go.hideFlags == HideFlags.HideAndDontSave))
objectsInScene.Add(go);
}
return objectsInScene;
}
}
Related
So I have a 2D platformer parkour game which holds a timer when player starts level. I have 5 levels and at the end of each level, I want to keep the last time value and display them at the end of the game.
So far, I tried to hold the last time value when player triggers the End portal and store them in an array in the code below. Here are the scripts:
Time Data Manager Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
void Start(){
}
void Update(){
Debug.Log(timeDataArr[SceneManager.GetActiveScene().buildIndex-1]);
}
public void AddTimeData(string timeData, int levelBuildIndex){
timeDataArr[levelBuildIndex-1] = timeData.ToString();
}
}
End Portal Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class EndPortal : MonoBehaviour
{
public AudioSource aSrc;
private int sceneNumber;
public GameObject bgAudio;
public Text scoreText;
string textData;
public timeDataManager tDManager;
void Start(){
sceneNumber = SceneManager.GetActiveScene().buildIndex;
tDManager = GameObject.FindGameObjectWithTag("TimeDataManager").GetComponent<timeDataManager>();
}
void OnTriggerEnter2D(Collider2D col){
if (col.gameObject.tag == "Player"){
aSrc.Play();
Destroy(bgAudio);
textData = scoreText.text;
Debug.Log(textData);
Debug.Log(sceneNumber);
tDManager.AddTimeData(textData,sceneNumber);
SceneManager.LoadScene(sceneBuildIndex:sceneNumber+1);
}
}
}
As I said before, I tried to keep all timer values at the end of each level and store them in an array in my timeDataManager script. But it's not working.
Any ideas on how to fix? Or do you have any other ideas? Thanks a lot for your time.
Issylin's answer is a better solution for your needs but i want to mention couple of things about your code.
One thing about your timeDataArr. If you don't touch it in inspector, you need to initialize it first. So let's say, if you want to hold 5 levels of time data, you need to do something like;
public string[] timeDataArr = new string[5];
or
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
public int sceneAmount_TO_HoldTimeData = 5;
void Start()
{
timeDataArr = new string[sceneAmount_TO_HoldTimeData];
}
}
or
public class timeDataManager : MonoBehaviour
{
public string[] timeDataArr;
public int sceneAmount_NOT_ToHoldTimeData = 1;
void Start()
{
timeDataArr = new string[SceneManager.sceneCountInBuildSettings - sceneAmount_NOT_ToHoldTimeData];
}
}
Another thing is you need to be careful about levelBuildIndex-1. If you call that in first scene,
SceneManager.GetActiveScene().buildIndex
will be 0 and levelBuildIndex-1 will be -1 or in Debug part it will be timeDataArr[-1] but array indexes must start with 0. So it will throw an error.
One more thing, this is not an error or problem. Instead of this part
tDManager = GameObject.FindGameObjectWithTag("TimeDataManager").GetComponent<timeDataManager>();
you can do
tDManager = FindObjectOfType<timeDataManager>();
There are several way to achieve what you're trying to do.
The easier would be to use a static class for such a simple data like the one you're carrying through your game.
using System.Collections.Generic;
public class Time_Data
{
/// TODO
/// Add the members
/// e.g. your time format as string or whatever,
/// the scene index, etc
}
public static class Time_Manager
{
private static List<Time_Data> _times;
public static void Add_Time(in Time_Data new_time)
{
_times.Add(new_time);
}
public static List<Time_Data> Get_Times()
{
return _times;
}
public static void Clear_Data()
{
_times.Clear();
}
}
Use it like any other static methods within your OnTriggerEnter2D call.
Time_Manager.Add( /* your new data here */ );
The other way, if you intend to stay with a game object within your scenes, would be to use the DontDestroyOnLoad method from Unity so your game object which has your script timeDataManager would remain.
Note that in your code, using string[] might be unsafe. For your use of it, consider using a List<string>.
I'm trying to synchronize text in a unit between players, but I'm getting an error.
I just need to sync the text
[1]: https://i.stack.imgur.com/0l98U.png
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using UnityEngine.UIElements;
public class Sync : MonoBehaviourPunCallbacks
{
private PhotonView view;
public Text textGame;
public Text copied;
void Start()
{
view = GetComponent<PhotonView>();
}
public void sync()
{
if(view.IsMine)
view.RPC("ViewAll", RpcTarget.AllBuffered, textGame.text);
}
[PunRPC]
public void ViewAll(string tG)
{
tG = copied.text;
Debug.Log(tG);
}
}```
пппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппппп
The error is telling you that the "view" variable has not been assigned and is therefore null.
To assign it you can make that field public, and in the inspector you
assign the photonView you want, I guess that of the player.
Alternatively you can assign "view" not from the inspector but in a
Start() or Awake() method. If the photonView you want to associate is
on the same GameObject as the script, you can write like this:
void Awake()
{
view = GetComponent();
}
However, the easiest answer is to replace "view" with "photonView".
It will have the same result as the solutions described above, but it will be very simple.
enter code here
public void sync()
{
if(photonView.IsMine)
view.RPC("ViewAll", RpcTarget.AllBuffered, textGame.text);
}
I have not directly given you the simple slogan to make you fully understand the problem and to help you solve it.
In my game I have coins, in my coin script I have an OnDestroy() function but I get this error "NullReferenceException: Object reference not set to an instance of an object
coinscript.OnDestroy () (at Assets/Scrips/coinscript.cs:9)"
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class coinscript : MonoBehaviour
{ public gamemanager GameManager;
void OnDestroy()
{
GameManager.plusScore(10);// FindObjectOfType<gamemanager>().pluseScore(10); gets the same error
}
}
fixed it thanks to help from KiynL
using System.Collections.Generic;
using UnityEngine;
public class coinscript : MonoBehaviour
{ public gamemanager GameManager;
bool destroyed = false;
void OnDestroy()
{
if (destroyed = false)
{
GameManager.plusScore(10);
destroyed = true;
}
}
}
This is because the object may be destroyed multiple times in one frame. Fix it.
void OnDestroy()
{
if (gameObject) GameManager.plusScore(10);
}
You need to go into the properties of whatever object you attached that script to, and assign Game Manager an object that has a gamemanager script attached to it.
As ted said its probably because you haven't set GameManager from inspector. you need to drag a gameObject that has gamemanager component on it.
but I recommand making plusScore function static and calling it without an object, if you make it statis you also have to make varible that stores score static as well, some thing like this:
public class gamemanager : MonoBehaviour
{
static int Score = 0;
public static void plusScore(int score)
{
Score += score;
}
}
then calling it like this:
gamemanager.plusScore(10);
Suppose I have this ScriptableObject to represent a list of cards:
using UnityEngine;
using System.Collections;
[CreateAssetMenu(fileName = "CardList", menuName = "Inventory/List", order = 1)]
public class CardList : ScriptableObject {
public string[] cardName;
public Sprite[] cardSprite;
}
Then I create the ScriptableObject and fill it with all my cards information.
Is there a way to modify this code so that any script have access to it statically? For example, is it possible to give CardList a singleton behaviour?
I don't want to create another class, it would be easy to create a ScriptableObjectManager that could reference CardList. I'd rather call something like CardList.instance.cardName[i] directly.
Definitely, you can create it as singleton so for this.
Suppose that we have Unity Project that has file hierarchy like
UnityProject
- Assets (directory)
Scripts
SampleScriptableObject.cs
- Resources (directory)
SampleScriptableObject.asset
- Project
- ..etc
in "SampleScriptableObject" class will be like
public class SampleScriptableObject<T> : ScriptableObject where T : ScriptableObject
{
private static T _instance;
public T GetInstance()
{
if (_instance == null)
{
_instance = Resources.Load(typeof(T).Name) as T;
}
return _instance;
}
}
you can use scriptable object as singleton as you want.
I have project, inside there is background.cs class and game1.cs class,
thats my background.cs class code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace Rocket
{
class Backgrounds
{
public Texture2D texture;
public Rectangle rectangle;
public void Draw(SpriteBatch spriteBatch){
spriteBatch.Draw(texture, rectangle, Color.White);
}
class Scrolling : Backgrounds{
public Scrolling(Texture2D newTexture, Rectangle newRectangle){
texture = newTexture;
rectangle = newRectangle;
}
public void Update(){
rectangle.X -= 3;
}
}
}
}
and thats game1.cs class code (starting where I get error):
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace Rocket
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Scrolling scrolling1;
Scrolling scrolling2;
'
So, Scrolling scrolling1; is underlined, (as second one), it says that class Scrolling could not be found, but it exists! I am noob in XNA and I cant find why it isn't working. any help will be ok!
Why do you have your Scrolling class nested into Backgrounds class in background.cs? The default visibility for nested classes in C# is private and therefore it is not visible to the Game1 class.
You should put this
class Scrolling : Backgrounds{
public Scrolling(Texture2D newTexture, Rectangle newRectangle){
texture = newTexture;
rectangle = newRectangle;
}
public void Update(){
rectangle.X -= 3;
}
}
into a file scrolling.cs. This gives Scrolling and Background the default visibility for classes (internal) which should work for your example.
You should to specify the visibility of classes explicitly. Have a look at: https://msdn.microsoft.com/en-us/library/ms173121.aspx