is there such a way to run a method in all scenes in unity without passing data from one screen to another? What I want to do is assume that I have a method which counts the time like stopwatch. When I open the game it starts counting on main screen like 1,2,3... and when I go another screen it should keep running the method and continue counting 4,5,6... and it should continue like this when I switch to other screens.
I thought that it can be done using a static variable in a script and using the same script in all scenes in a game object. But I wonder if there is an easier approach as I said in above like running one global method in all screens once game is launched.
Here is an example of class, that logs value every second. You can change ShowCurrentValue function to one you need. This will work, regardless of changing scene. You can start and stop it with corresponding fucntions from any place in project.
using UnityEngine;
using System.Threading;
public class Counter
{
public static ulong CurrentValue { get; set; } = 0;
private static Thread cThread = null;
public static void Start()
{
if (cThread == null)
cThread = new Thread(ShowCurrentValue);
cThread.Start();
}
public static void Pause()
{
if (cThread != null)
{
cThread.Abort();
CurrentValue++;
}
cThread = null;
}
private static void ShowCurrentValue()
{
while (true)
{
Debug.Log(CurrentValue);
Thread.Sleep(1000);
CurrentValue++;
}
}
}
You are looking LoadAdditive I believe. Also check the docs once LoadAdditive
SceneManager.LoadScene("YourScene", LoadSceneMode.Additive);
Related
I am creating a game where the first scene will have a generated map saved as a 2D array, then the next scene takes care of all the combat. Once that's done, user needs to go back to the first scene and see the same map. I have followed Unity's tutorial on Data persistence, and as you can see in the code below I am checking twice if an Instance is not null and destroying the object if its not.
The problem is, that every time I go back from combat scene to the map scene, it creates another instance of WorldMapManager, and generates another map on top of the existing one.
Where am I going wrong to stop creation of unnecessary extra copies of WorldMapManager object?
public class WorldMapManager : MonoBehaviour
{
public static WorldMapManager Instance { get; private set; }
public static int _mapSizeX = 4;
public static int _mapSizeY = 4;
public static int _playerScore;
public static int _playerCells;
public static int _enemyScore;
public static int _enemyCells;
public static GameObject[,] _map;
public static GameObject _startingPoint;
public static Vector2Int _playerBase;
// Awake is called before Start
void Awake()
{
if (WorldMapManager.Instance != null)
{
Destroy(gameObject);
}
else
{
DontDestroyOnLoad(gameObject);
}
SceneManager.sceneLoaded += OnLevelFinishedLoading;
}
// Initialize the map
public void InitMap()
{
// Map Generation happens here
}
// OnSceneLoaded is called when a scene is loaded
void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode)
{
if (scene.name == "WorldMap")
{
if (WorldMapManager.Instance != null)
{
Destroy(this);
} else
{
InitMap();
}
}
}
}
I have been stuck on this for several days trying different approaches, but I'm all out of ideas, so thank you very much for any help.
By the looks of your code it seems you never ever set the WorldMapManager.Instance. So it will always be null and always go on to DontDestroyOnLoad(gameObject);.
So add the assignment to Instance too.
Instance = this;
DontDestroyOnLoad(gameObject);
For the same reason in void OnLevelFinishedLoading(Scene scene, LoadSceneMode mode) the InitMap() will be executed. No need to set anything to Instance here ofcourse.
Right now, whenever the player goes on the quest, and walks back on himself, the UI window pops up again that says to accept the quest again, when the player already has done so. I also don't want the accept quest window popping up once the player returns to the NPC to collect their reward, this is why I only want the UI to only be able to appear once.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class QuestGiver : MonoBehaviour
{
public Quest quest;
public MovementTest player;
public GameObject questWindow;
public Text titleText;
public Text descriptionText;
public void OpenQuestWindow()
{
if (isQuestAccepted)
return;
questWindow.SetActive(true);
titleText.text = quest.title;
descriptionText.text = quest.description;
}
public void AcceptQuest()
{
questWindow.SetActive(false);
quest.isActive = true;
player.quest = quest;
}
void Start()
{
questWindow = GameObject.Find("QuestWindow");
questWindow.SetActive(false);
}
}
Based solely on the provided code, isQuestAccepted is not being set to true when accepting the quest.
Try to add it in the AcceptQuest method:
public void AcceptQuest()
{
isQuestAccepted = true;
questWindow.SetActive(false);
quest.isActive = true;
player.quest = quest;
}
To make sure, please provide more details about the isQuestAccepted flag and the triggers for calling OpenQuestWindow
Generraly speaking, some things to consider:
By the looks of it, the execution of the method is limited once per the lifetime of the QuestGiver. It is recommended for quest models to have a persistent value between executions.
is it possible questWindow.SetActive being called outside the scope of provided code?
If the quest is already accepted then you should not execute OpenQuestWindow in the first place.
I'm making a game in Unity3D with C# for mobile devices and can't figure out how to check which scene was loaded before the current scene. I need to check this to change the spawn point from the player gameobject. First I added a simple script to my buttons (loadnextscene and loadprevscene)
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Application.LoadLevel(sceneNumber);
}
}
A second scripts handles the touch input from the user and changes the movement of the player object.
So, for example: If the player clicks on the "load previous scene" button in the second Level to switch to the first level again, I want to set the spawn point of the player object on the right half on the screen and not on the left side like when the game was started the first time.
I tried it with Singleton and PlayerPrefs, but it did not work out.
You need to save the scene number to some variable before LoadScene, then check it after the scene loaded.
The only problem is that this variable will be destroyed after the new scene is loaded. So, to prevent it, you can use DontDestroyOnLoad. Here is what you do:
First, create a new empty game object, and attach the following script to it:
using UnityEngine;
using System.Collections;
public class Indestructable : MonoBehaviour {
public static Indestructable instance = null;
// For sake of example, assume -1 indicates first scene
public int prevScene = -1;
void Awake() {
// If we don't have an instance set - set it now
if(!instance )
instance = this;
// Otherwise, its a double, we dont need it - destroy
else {
Destroy(this.gameObject) ;
return;
}
DontDestroyOnLoad(this.gameObject) ;
}
}
And now, before you load, save the scene number in the Indestructable object:
public class SwitchScene : MonoBehaviour {
public int sceneNumber;
public void LoadScene(int sceneNumber) {
Indestructable.instance.prevScene = Application.loadedLevel;
Application.LoadLevel(sceneNumber);
}
}
And last, in your scene Start() check Indestructable.instance.prevScene and do your magic accordingly.
More info here:
http://docs.unity3d.com/ScriptReference/Object.DontDestroyOnLoad.html
*I did not compile the code, so there may be some errors, but this is the general idea.
Why did the PlayerPrefs approach did not work?
I think its the easiest way to solve your problem.
public class FirstLevel : MonoBehaviour {
public void Start() {
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
}
And then in the second scene simply read the saved PlayerPrefs
public class SecondLevel : MonoBehaviour {
string PrevScene;
public void Start() {
PrevScene = PlayerPrefs.GetString("SceneNumber");
// if there will be a third scene, etc.
PlayerPrefs.SetString("SceneNumber", SceneManager.GetActiveScene().name);
}
public void GoToPrevScene() {
SceneManager.LoadScene(PrevScene);
}
}
You can solve this problem with a single static member variable in the SwitchScene class. No need for the singleton pattern or DontDestroyOnLoad.
public class SwitchScene : MonoBehaviour
{
public int sceneNumber;
private static int previousScene;
private int oldPreviousScene;
void Start()
{
oldPreviousScene = previousScene;
previousScene = sceneNumber;
}
public void HandleLoadPrevButtonClick()
{
SceneManager.LoadScene(oldPreviousScene);
}
}
I need to stop/resume the rotation of a fan when a certain key is pressed, so I wrote this C# code:
public bool rotationFlag = false;
void Update()
{
if(rotationFlag)
{
fan.transform.Rotate(Vector3.up, rotationAngle);
}
}
public void commuteFan()
{
rotationFlag = !rotationFlag;
}
cummuteFan() method is called when I press the button.
the variable starts on false and the fan correctly doesn't ratate, when I hit the button, the method is called, the variable values changes and the starts to rotate, but if I want to stop it, it doesn't work anymore. debug tells me that the value is correctly changed to false in commuteFan() but update() continues to read the old value (true) and the fan doesn't stop.
[SOLVED] I don't know why, but I created a class with only the bool along with getter/setter methods in it and it works know
So you had your variable as public, which means that any other part of the project could easily edit it. In your case you were changing it via the editor.
To avoid this kind of problems in the future try using protection.
public class Test : MonoBehaviour
{
private bool isRotating = false;
public void setIsRotating(bool status)
{
isRotating = status;
}
public bool getIsRotating()
{
return isRotating;
}
}
Coding like this will save you a lot of headaches later on.
Recently I've made the switch from Unity to a bright & shiny OpenGl/Freeglut solution using Mono in Xamarin Studio. I figured this was a wise move because I wasn't learning what I wanted to learn with Unity's handholding. Apparently this wasn't the wisest of moves but I am committed now. There are two things I miss, very much: Awake() & Update().
It was magic. Any object I wanted could extend monobehaviour & I could run some code every frame. But as a neophyte csharper, I'm not entirely sure how to replicate this outside of unity.
Basically I have my main program; the trimmed down version is this:
using System;
using Tao.FreeGlut;
using OpenGL;
namespace Project
{
class Program
{
private static int width = 1280, height = 720;
public static MyPlayerObj player = new MyPlayerObj();
public static MyMouseListenerObj mouseE = new MyMouseListenerObj();
public static MyKeyboardListenerObj keyboardE = new MyKeyboardListenerObj();
public static MyEnemyObj e1 = new MyEnemyObj();
public static MyEnemyObj e2 = new MyEnemyObj();
public static MyEnemyObj e3 = new MyEnemyObj();
public static void Main(string[] args)
{
Glut.glutInit();
Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
Glut.glutInitWindowSize(width, height);
Glut.glutCreateWindow("Project");
Glut.glutIdleFunc(Update);
Glut.glutDisplayFunc(DisplayFunc);
Awake();
Glut.glutMainLoop();
}
public static void Awake()
{
// Run all Awake Methods
}
private static void DisplayFunc()
{
}
public static void Update()
{
Gl.Viewport(0, 0, width, height);
Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
// Run All Update Methods
// Then run all LateUpdate methods
Glut.glutSwapBuffers();
}
}
}
In this example, I have some objects such as player, keyboard & mouse listeners, and a bunch of enemies. Now, what I want to do is be able to call each objects Awake method if it has one, or ignore it if it doesn't. This might be something like (pseudocode, forgive me):
public static void Update()
{
interfacedObjects = assembly().findAllObjectsUsingInterface(IUpdateable);
foreach (var item in interfacedObjects)
{
if(item.hasMethod('Update')
item.call('Update');
}
}
Essentially, what I'm trying to do is keep my objects chained to the parent "Monobehaviour". I want to keep my class structure as simple as possible.
public class MyPlayerObj : MyMonoBehavior
{
public void Update()
{
// Do stuff
}
}
public class MyMonoBehavior : IUpdateable
{
public virtual void Update()
{
}
}
Does anyone have any suggestions for me? I know its possible, but I just don't know what this design pattern is called, nor how to execute it.
I should mention that I would prefer to keep this solution within the native codebase, in the interest of learning.
Interesting question.
I don't know how Unity does this behind the scenes, but would love to find out. I think the simplest way for you to implement this is to look at the Observer Design Pattern. The basic idea that you are looking for is to have a MonoBehavior interface or abstract class that everyone inherits from. Then you would have a class that handles the MonoBehaviors by running a loop on every MonoBehavior that exists.