I have a car in my game with 4 wheels(Unity3D):
Also i have a trigger of EndLevel:
But after when im going throght the trigger its trying to work 4th times
How can i change it?
I tried to add my "Player(car)" inside EndGame object but its didnt fix my problem.
using UnityEngine;
public class EndTrigger : MonoBehaviour
{
public GameManager gameManager;
void OnTriggerEnter()
{
gameManager.CompleteLevel();
}
}
First of all note that OnTriggerEnter(Collider other) requires a parameter of type Collider otherwise it wouldn't get called at all.
Flag
The simplest solution might be adding a bool flag as already mentioned by Eric Warburton's answer.
Layers
I would prefer to rather tackle the origin of the issue and suggest using different Layers and then configure the Layer-based collision detection via the Edit→ProjectSettings→Physics→ Layer Collision Matrix.
Create a Layer e.g. END and assign it to your goal collider object. Make this object not Is Trigger and rather attach your script checking for OnTriggerEnter here.
Create a Layer e.g. Player create a new dedicated invisible object with a collider and enable Is Trigger here. This object has the only purpose of colliding with the goal collider nothing else. Assign the Player layer here.
Configure the collision matrix thus that END only collides with Player and nothing else. And Player only collides with END and nothing else - or maybe later another effect layer like e.g. PowerUps ;)
You can create up to 24 custom layers and make use of the already existing ones so this should hold up a while
Tags
Another alternative to the Layers is using Tags
As previously I would make the END object not a trigger but rather use one on the Player.
Then you can simply compare the tag using CompareTag
void OnTriggerEnter(Collider other)
{
if (!other.CompareTag("Player")) return;
gameManager.CompleteLevel();
}
in very very complex games this might be sometimes better since you can create a lot more Tags than Layers.
Well there are a few things that I can think of trying.
You can make sure that only one of your colliders is a trigger. There should be a bool check in the properties to uncheck for your wheels.
You can also do something like creating a counter or a bool that prevents the OnTriggerEnter() from firing multiple times if you only want it to fire once. You can reset it at the start of levels if needs be.
Something like
void OnTriggerEnter()
{
if (!gameManager.IsLevelComplete)
gameManager.CompleteLevel();
}
Inside the gameManager script
public bool IsLevelComplete { get; set; }
public void CompleteLevel()
{
IsLevelComplete = true;
//Do stuff
}
I have 2 different scripts attached to 2 different game objects.
One instantiates a bunch of game obejcts and I want the second one to destroy them.
code1:
public static volatile GameObject newObj;
public GameObject go;
newObj = GameObject.Instantiate(go);
newObj.tag = "mytag";
Code 2:
GameObject[] all_cloned_prefabs = GameObject.FindGameObjectsWithTag("mytag");
foreach (var AllPrefabs in all_cloned_prefabs)
{
Destroy(AllPrefabs);
}
When I run code 2 (let's say by pressing a button on GUI, it doesn't destroy the objects I created on the screen.What am I doing wrong?
It's hard to understand what you are trying to do in the first code with public static volatile GameObject newObj;, it's not used in the other part of the code you shown.
The second code looks fine, what could be wrong is:
The objects you want to destroy are inactive (FindGameObjectsWithTag will not return inactive GameObjects).
You didn't created the tag "mytag" in the Tag Manager.
Try to Debug.Log the content of the all_cloned_prefabs array to see if it actually contains anything.
I put all the objects inside a list, made the list public static volatile prefab1. accessed it from second script. then destroyed them
It worked perfect.
foreach (GameObject obj1 in script1.prefab1)
{
Destroy(obj1);
}
I don't really understand this?
What seems to happen is when I enter the trigger zone the flashlight turns off, but when exiting the trigger zone the flashlight doesn't turn on again. If i reverse the effect i.e the flash light is off when the scene starts and then when entering the trigger zone the flashlight doesn't turn? This is the same (minor changes with name) script I used for the main room light (which works)
So with the below code the flashlight is off and i would like to turn it on when entering the trigger zone?
public class TurnFlashLightOn : MonoBehaviour
{
void Start()
{
GameObject[] allLights = GameObject.FindGameObjectsWithTag("flashLight");
foreach (GameObject i in allLights)
{
i.SetActive(true);
}
}
void OnTriggerEnter()
{
GameObject[] allLights = GameObject.FindGameObjectsWithTag("flashLight");
foreach (GameObject i in allLights)
{
i.SetActive(false);
}
}
void OnTriggerExit()
{
GameObject[] allLights = GameObject.FindGameObjectsWithTag("flashLight");
foreach (GameObject i in allLights)
{
i.SetActive(true);
}
}
}
Any ideas why it would switch off but not on?
Thanks
Subtle but important detail: GameObject.FindGameObjectsWithTag only searches through active objects. Once you turn off a flashlight, it won't show up in that search anymore.
You'll need to cache a list of flashlight objects.
If the list is never going to change (you never create or destroy flashlights), then you can populate the list once during Start, then refer to the list any time you need it.
If the list is dynamic, you could start with an empty list, then add any flashlight to the list as it gets deactivated. When it's time to turn lights back on, activate every light in the list and then clear the list.
There are plenty of ways you could do this; the basic issue is just that you need some other way to keep track of those inactive objects.
Based on your code and what you are telling me, You have an event for when an object passes a threshold the lights will turn off. This threshold contains the Event OnTriggerEnter();
The Threshold or Zone() cannot contain two triggers at once and know which one it is supposed to fire. I can only propose you have an If-Else statement which helps define the logic to which trigger should fire. for instance
(This is Pseudo Code)
If (EnteringZoneFromStart() = true)
{OnTriggerEnter()}
Else If (ExitingZone() = true)
{OnTriggerExit()}
Else
{OnTriggerEnter()}
I'm making simple game manager. I have a script, which will be accessible from all scenes in the game. And I need to check values of its variables after loading new scene. But my code runs only once after starting the simulation while an object with this script exists in all scenes. What is wrong? Why doesn't it work after loading a new scene?
In every Unity project you must have A PRELOAD SCENE.
It is quite confusing that Unity does not have a preload scene "built-in".
They will add this concept in the future.
Fort now you have to click to add a preload scene yourself.
This is the SINGLE GREATEST MISUNDERSTANDING for new programmers trying Unity!
Fortunately, it is extremely easy to have a preload scene.
Step 1.
Make a scene named "preload". It must be scene 0 in Build Manager.
Step 2.
In the "preload" scene make an empty GameObject called, say, "__app".
Simply, put DontDestroyOnLoad on '__app'.
Note:
This is the only place in the whole project you use DontDestroyOnLoad.
It's that simple.
In the example: the developers have made a one-line DDOL script.
Put that script on the "__app" object.
You never have to think about DDOL again.
Step 3
Your app will have (many) "general behaviors". So, things like database connectivity, sound effects, scoring, and so on.
You must, and can only, put your general behaviors on "_app".
It's really that simple.
The general behaviors are then - of course - available everywhere in the project, at all times, and in all scenes.
How else could you do it?
In the image example above, notice "Iap" ("in-app purchase") and the others.
All of your "generally-needed behaviors" - sound effects, scoring, and so on - are right there on that object.
Important...
This means that - of course, naturally -
...your general behaviors will have ordinary Inspectors, just like everything else in Unity.
You can use all the usual features of Unity, which you use on every other game object. Inspector variables, drag to connect, settings, and so on.
(Indeed: say you've been hired to work on an existing project. The first thing you will do, is glance at the preload scene. You will see all the "general behaviors" in the preload scene - sound effects, scoring, AI, etc etc. You will instantly see all the settings for those things as Inspector variables ... speech volume, playstore ID, etc etc.)
Here's an example "Sound effects" general behavior:
Looks like there's also a "voice over" general behavior, and a "music" general behavior".
To repeat. Regarding your "general behaviors". (Sound effects, scoring, social, etc etc.) These CAN ONLY GO on a game object in the preload scene.
This is not optional: there's no alternative!
It's that easy.
Sometimes engineers coming from other environments get caught up on this, because it seems like "it can't be that easy".
To repeat, Unity just plain forgot to "build-in" a preload scene. So, you simply click to add your preload scene. Don't forget to add the DDOL.
So, during development:
Always start your game from Preload scene.
It's that simple.
Important: Your app will certainly have "early" scenes. Examples:
"splash screen"
"menu"
Note. Tou CAN NOT use splash or menu as the preload scene. You have to literally have a separate preload scene.
The preload scene will then load your splash or menu or other early scene.
The central issue: "finding" those from other scripts:
So you have a preload scene.
All of your "general behaviors" are simply on the preload scene.
You next have the problem of, quite simply, finding say "SoundEffects".
You have to be able to find them easily, from, any script, on any game object, in any of your scenes.
Fortunately it is dead easy, it is one line of code.
Sound sound = Object.FindObjectOfType<Sound>();
Game game = Object.FindObjectOfType<Game>();
Do that in Awake, for any script that needs it.
It's honestly that simple. That's all there is to it.
Sound sound = Object.FindObjectOfType<Sound>();
Tremendous confusion arises because of the 100s of absolutely wrong code examples seen online.
It really is that easy - honest!
It's bizarre that Unity forgot to add a built-in "preload scene" - somewhere to attach your systems like SoundEffects, GameManager, etc. It's just one of those weird thing about Unity. So, the first thing you do in any Unity project is just click once to make a preload scene.
That's it!
A Detail...
Note that, if you really want to type even less (!) lines of code, it's remarkably easy - you can just use a global for each of these things!
This is explained in detail here , many folks now use something like this, a Grid.cs script ...
using Assets.scripts.network;
using UnityEngine;
static class Grid
{
public static Comms comms;
public static State state;
public static Launch launch;
public static INetworkCommunicator iNetworkCommunicator;
public static Sfx sfx;
static Grid()
{
GameObject g = GameObject.Find("_app");
comms = g.GetComponent<Comms>();
state = g.GetComponent<State>();
launch = g.GetComponent<Launch>();
iNetworkCommunicator = g.GetComponent<INetworkCommunicator>();
sfx = g.GetComponent<Sfx>();
}
}
Then, anywhere in the project you can say
Grid.sfx.Explosions();
It's just that easy, that's the whole thing.
Don't forget that each of those "general systems" is on, and can only be on, the DDOL game object in the preload scene.
DylanB asks: "During development it's quite annoying that you have to click to the preload scene every time before you click "Play". Can this be automated?"
Sure, every team has a different way to do this. Here's a trivial example:
// this should run absolutely first; use script-execution-order to do so.
// (of course, normally never use the script-execution-order feature,
// this is an unusual case, just for development.)
...
public class DevPreload:MonoBehaviour
{
void Awake()
{
GameObject check = GameObject.Find("__app");
if (check==null)
{ UnityEngine.SceneManagement.SceneManager.LoadScene("_preload"); }
}
}
But don't forget: what else can you do? Games have to start from a preload scene. What else can you do, other than click to go to the preload scene, to start the game? One may as well ask "it's annoying launching Unity to run Unity - how to avoid launching Unity?!" Games simply, of course, absolutely have to start from a preload scene - how else could it be? So sure, you have to "click to the preload scene before you click Play" when working in Unity - how else could it be?
#Fattie: Thanks for elaborating all this, it's great! There is a point though that people are trying to get through to you, and I'll just give it a go as well:
We do not want every instantiation of everything in our mobile games to do a "FindObjectOfType" for each and every every "global class"!
Instead you can just have it use an Instantiation of a static / a Singleton right away, without looking for it!
And it's as simple as this:
Write this in what class you want to access from anywhere, where XXXXX is the name of the class, for example "Sound"
public static XXXXX Instance { get; private set; }
void Awake()
{
if (Instance == null) { Instance = this; } else { Debug.Log("Warning: multiple " + this + " in scene!"); }
}
Now instead of your example
Sound sound = Object.FindObjectOfType<Sound>();
Just simply use it, without looking, and no extra variables, simply like this, right off from anywhere:
Sound.Instance.someWickedFunction();
Alternately (technically identical), just use one global class, usually called Grid, to "hold" each of those. Howto. So,
Grid.sound.someWickedFunction();
Grid.networking.blah();
Grid.ai.blah();
Here is how you can start whatever scene you like and be sure to reintegrate your _preload scene every time you hit play button in unity editor. There is new attribute available since Unity 2017 RuntimeInitializeOnLoadMethod, more about it here.
Basically you have a simple plane c# class and a static method with RuntimeInitializeOnLoadMethod on it. Now every time you start the game, this method will load the preload scene for you.
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadingSceneIntegration {
#if UNITY_EDITOR
public static int otherScene = -2;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void InitLoadingScene()
{
Debug.Log("InitLoadingScene()");
int sceneIndex = SceneManager.GetActiveScene().buildIndex;
if (sceneIndex == 0) return;
Debug.Log("Loading _preload scene");
otherScene = sceneIndex;
//make sure your _preload scene is the first in scene build list
SceneManager.LoadScene(0);
}
#endif
}
Then in your _preload scene you have another script who will load back desired scene (from where you have started):
...
#if UNITY_EDITOR
private void Awake()
{
if (LoadingSceneIntegration.otherScene > 0)
{
Debug.Log("Returning again to the scene: " + LoadingSceneIntegration.otherScene);
SceneManager.LoadScene(LoadingSceneIntegration.otherScene);
}
}
#endif
...
An alternate solution from May 2019 without _preload:
https://low-scope.com/unity-tips-1-dont-use-your-first-scene-for-global-script-initialization/
I've paraphrased from the above blog to a how-to for it below:
Loading a Static Resource Prefab for all Scenes
In Project > Assets create a folder called Resources.
Create a Main Prefab from an empty GameObject and place in the Resources folder.
Create a Main.cs C# script in your Assets > Scripts or wherever.
using UnityEngine;
public class Main : MonoBehaviour
{
// Runs before a scene gets loaded
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void LoadMain()
{
GameObject main = GameObject.Instantiate(Resources.Load("Main")) as GameObject;
GameObject.DontDestroyOnLoad(main);
}
// You can choose to add any "Service" component to the Main prefab.
// Examples are: Input, Saving, Sound, Config, Asset Bundles, Advertisements
}
Add Main.cs to the Main Prefab in your Resources folder.
Note how it uses RuntimeInitializeOnLoadMethod along with Resources.Load("Main") and DontDestroyOnLoad.
Attach any other scripts that need to be global across scenes to this prefab.
Note that if you link to other scene game objects to those scripts you probably want to use something like this in the Start function for those scripts:
if(score == null)
score = FindObjectOfType<Score>();
if(playerDamage == null)
playerDamage = GameObject.Find("Player").GetComponent<HitDamage>();
Or better yet, use an Asset management system like Addressable Assets or the Asset Bundles.
actually as a programmer who comes to unity world I see none of these approaches
standard
the most simplest and standard way: create a prefab, according to unity docs:
Unity’s Prefab system allows you to create, configure, and store a GameObject complete with all its components, property values, and child GameObjects
as a reusable Asset. The Prefab Asset acts as a template from which you can create new Prefab instances in the Scene.
Details:
Create a prefab within your Resources folder:
if you don't know how to create a prefab study this unity document
if you don't have resources directory create a folder and name it exactly Resources because it is a unity Special folder name
create a script with contents like below:
using UnityEngine;
public class Globals : MonoBehaviour // change Globals (it should be the same name of your script)
{
// loads before any other scene:
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
public static void LoadMain()
{
Debug.Log("i am before everything else");
}
}
assign it to your prefab
and you can make it even better:
use prefab and namespaces together:
in your prefab script:
using UnityEngine;
namespace Globals {
public class UserSettings
{
static string language = "per";
public static string GetLanguage()
{
return language;
}
public static void SetLanguage (string inputLang)
{
language = inputLang;
}
}
}
in your other scripts:
using Globals;
public class ManageInGameScene : MonoBehaviour
{
void Start()
{
string language = UserSettings.GetLanguage();
}
void Update()
{
}
}
What would be the best way to tally objects that are tagged under a specific name? What am i doing wrong? My current goal is to use a box collider to identify and tally up specific objects in a room. Any response to a solution or an alternative way of achieving this goal will be appreciated.
My attempt:
using UnityEngine;
using System.Collections;
public class roomColliders : MonoBehavior {
public int numberOfTargets;
void Start (){
numberOfTargets = 0;
}
void OnCollisionEnter(Collision col){
if(col.gameObject.tag == "Target"){
numberOfTargets += 1;
}
}
}
Additionally, I tried assigning with Box Colliders and Rigidbody in a myriad of ways with the objects and I had no success. I have three objects with a tag of "Target" assigned to them but in my inspector, the numberOfTargets tallies up only one object. I have come under the conclusion, that maybe I need to use a statement such as this "foreach(ContactPoint contact in col.contacts)". I could be wrong, tell me if so. If this is near the answer. Is it anyway I can assign 'col.contacts.tag = "Target"'? I get an error if I do so if I used it with 'foreach'.
If only you haven't do it intentionally, using OnCollisionEnter is wrong. You must use OnTriggerEnter instead. And do not forget to toggle on Is Trigger property on box collider attached to the object with roomColliders script.
And note that your script does not actually calculate number of objects currently intersected the trigger. It calculates number of times when objects of interest were start to intersect the trigger. But since the trigger may be moved to and fro, the same object of interest may intersect it more than once.