Flashlight turns off on trigger but not back on when exiting trigger - c#

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()}

Related

Parameter 'Animator' does not exist

I'm new in unity so I need some help with calling the animations. I'm trying to call an animation on a third collision and I have no errors except this one. I have no idea what to do.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Lose_Collider : MonoBehaviour
{
int count = 0;
public int score = 0;
public Animator boom;
void Start() {
boom = GetComponent<Animator>();
}
private void OnTriggerEnter2D(Collider2D collision){
if(collision.gameObject.name.Contains("UFO")){
Destroy(collision.gameObject);
count++;
score -= 500;
if(count == 1){
Destroy(GameObject.Find("HP 3"));
} else if (count == 2){
Destroy(GameObject.Find("HP 2"));
} else {
Destroy(GameObject.Find("HP 1"));
boom.SetTrigger("ExpAnimator");
//boom.SetTrigger(collision.gameObject.name.Contains("UFO").ToString());
//Destroy(gameObject);
//SceneManager.LoadScene("Main Menu");
}
}
else if(collision.gameObject.name.Contains("Star")) {
score += 100;
Destroy(collision.gameObject);
}
}
}
Firstly, that is not an error, it is a warning. The difference being that with warnings, the game is able to still run. Warnings are helpful tips or reminders that something is not exactly right, but there is built-in error handling to quietly deal with the issue. I would never leave warnings as they exist to let you know that you have most likely missed something in your code, created unintended functionality, or have created a bug. Your particular warning is stating that your Animation Tree does not contain an Animation Parameter called ExpAnimato.
I am going to make an assumption and say you do not have an Animation Paramater named ExpAnimator but simply want to play the animation or a state in it. If you want to play an Animator, simply call boom.Play. If you want to play a specific state inside of the animation on the animator, call boom.Play("YourStateNameHere"). There are other parameters to this function call that can alter how the animator handles the state update.
The other issue I am seeing with your code is you have not assigned the Boom reference. As the field is already exposed and serialized in the inspector, assign it by dragging the gameObject from the scene into the field. Right now you are also probably getting a null reference exception when you start the game about how boom is un-initialized.
If you want to use a parameter to change the state from say the entry state of Idle to your ExpAnimation, you need to add a new parameter to your animation state machine. I could try to explain it, but I find it is easier if you watch someone do it. There are no code examples in this tutorial, just the setup of the actual Animation State Machine which I think is what you are not familiar with.

How to make a trigger only for one of objects?

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&rightarrow;ProjectSettings&rightarrow;Physics&rightarrow; 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
}

How do I make the program do something when an object is destroyed?

I have plane(as in air plane) objects in my program, they get destroyed when bullets hit them but they also get destroyed after 5 seconds, when they exit the screen.
I also have a health script that resets the whole thing when it goes down to 0, and I want to remove a point every time the object is destroyed, but only when off screen. So I keep the scripts separate.
I use this in the ships spawn script to destroy them after 5 seconds, simple enough.
Destroy(spawnedPlane, 5f);
It would be perfect if I could just have some code that does "Destroy this object after X seconds AND add this to this value". Because as I understand it, "destroy" only accepts 2 parameters and nothing else.
Surely it is possible but I am at a loss. Still very new to this. Sorry if this is very unclear but I barely know what I'm doing myself.
You can use events to cleanly achieve what you are after. Below is an example of an event you might find useful. Other objects can listen to the event and once it is triggered, they will be notified.
[Serializable]
public class PlaneEvent : UnityEvent<Plane> { }
Once you have defined your event, you can then add it as a field in your Plane. Once your plane has been destroyed, you can fire the event and it will in turn notify anyone who is listening!
public class Plane : MonoBehaviour {
public PlaneEvent OnDestroyed;
public void Destroy () {
Destroy(gameObject);
OnDestroyed.Invoke(this);
OnDestroyed.RemoveAllListeners();
}
}
Now in our score class, we add a method that will be called once the OnDestroyed plane event is triggered.
public class Score : MonoBehaviour {
public void AddPointsFor (Plane plane) {
Debug.Log("A Plane was destroyed!");
//Tick a counter, add points, do whatever you want!
}
}
Once we have these pieces, it is trivial to make them work together. We take the plane and we add the score as a listener to the OnDestroyed event. Then once the plane is destroyed, the event is fired and score is told to add points.
public class Game : MonoBehaviour {
[SerializeField]
private Score _score;
[SerializeField]
private Plane _plane;
public void Start () {
// When you are destroyed let me know so I can add some points.
_plane.OnDestroyed.AddListener(_score.AddPointsFor);
_plane.Destroy();
}
}
Another big advantage in using events is your plane has no idea that a score even exists, it will let anyone who cares know that it has been destroyed. In the same way this event could also be used to trigger particle effects, animations and sound effects when the plane is destroyed and all you need to do is add more listeners.
Just use a coroutine to wait and then subtract a point and destroy the object at the same time.
void Start()
{
// your startup script
StartCoroutine(DestroyAfterSeconds(5f));
}
IEnumerator DestroyAfterSeconds(float seconds)
{
// wait for X amount of seconds before continuing on
yield return new WaitForSeconds(seconds);
/*
* this runs after the wait.
* if the coroutine is on the same gameobject that you are
* destroying, it will stop after you run Destroy(), so subtract
* the point first.
* */
points--;
Destroy(spawnedPlane);
}
If it was me I would surely go with events as suggested by CaTs.
Coroutine are another way to do that, but events are better in general at least in this case. Also using a Coroutine for just one Invoke is a bit an overkill (and unity Coroutines are a bit not performant.) Also the coroutine must be outside of the object you want to destroy because Unity Coroutines die when their MonoBehaviour is destroyed.
If you are still uncomfortable with events you...
well you should overcome it and try them anyway.
You could take a shortcut you can use More Effective Coroutine - Free.
And launch this code:
Timing.CallDelayed(5f, DestroyAndRemoveHP());
Basically this will run your logic with the delay you want to apply.
DestroyAndRemoveHP will be your method to destroy the platform and do anything else you like.
Full method description.
On the plus side you will start using MEC that are better than unity coroutine, but learning events makes you also a better programmer. You might do both.

How to queue up actions and animations in Unity for turn-based combat?

I'm working on a turn-based combat sequence in Unity on C# and I currently have turn switching working and inputs and AI. But I can't quite figure out how to queue it up with animations anf stuff, so that one happens after another in ExecuteTurnActions();
So my question is basically, how do I structure ExecuteTurnActions()?
I need it to go through all Entities and play their animations according to what's going on, like:
// PlayAnimation is simply Animator.SetTrigger(string)
Entities[0].PlayAnimation("Attack") or Entities[0].PlayAnimation("ReceiveDamage")
I need to make sure that when one Entity attacks, right when the attack happens, the other Entity receives damage and plays its animation at that moment. I know there are animation events, but I'm not sure how to make it flow from one place and make sure each entity knows which entity to trigger for animation next (when attacked for example). Any suggestions?
My structure looks something like this in pseudocode:
ENTITIES_TO_CREATE = MatchMaker.GetNumberOfPlayersAndEnemies();
void Start() {
InitializeAllThatsNeeded();
Entities[] = new Entity[ENTITIES_TO_CREATE];
// In a for loop, load up stuff and populate Entities
Entities[0].Name = MatchMaker.GetName(0);
Entities[0].Strength = MatchMaker.GetStrength(0); // etc etc etc
}
void Update() {
bool HaveAllEntitiesSelectedTurnAction = new bool[Entities.Length];
// Check every frame if all Entities have selected a turn action
for (int i = 0; i <= Entities.Length - 1; i++) {
HaveAllEntitiesSelectedTurnAction[i] = Entities[i].isTurnActionSelected;
}
// If the Entity that goes first has its action selected, then let the rest select theirs
if(Entities[EntityHasFirstTurn].TurnActionSelected) {
//All logic happens here, if Entity happens to be player then the player
//is allowed input, if enity is NPC then generate hit value etc.
// isTurnActionSelected set in this part
// Now if all have selected their action, execute them in order
if(HaveAllEntitiesSelectedTurnAction.All(x => x) {
ExecuteTurnActions();
}
}
}
To prioritize events I would suggest using a priority queue data structure.
As for ExecuteTurnActions(), it should only set appropriate flags of an Animator Component (based on the queue, most likely). You might want each entity to have its own event queue which interacts with its own Animator.
Building a state machine for all your animations is what you need to do first. Setting certain states will allow Unity to handle all the transitions. To learn more about the Animator and handling its states look here.

Is it possible randomize data that has been serialized using System.Serializable

A made a quiz game using Serializable method. As I call data from there it is always in same sequence. What I want to do is serialize questions and answers. And later I want to call data in random order.
Sorry about my previous question. Actually I'm new here that is why made the mistake. Really SORRY
Thank you guys :)
I am giving a link to the training session in case you need anything not specified here (all codes of the Project given there)
https://unity3d.com/learn/tutorials/topics/scripting/intro-and-setup
Try to be more specific in what you are asking.
You have both 2d and 3d tags for unity up pick the one you are using.
If you are working in one persistent scene, that means you will have to manipulate everything manually to remove it or reset it.
Another option is that you save the data you need from that round in a don't destroy on load object and reload your scene.
I would suggest you make 2 scenes, a menu scene, and a play-scene.
Read up on scenemanager and place a button in the menu scene that lets you move to the play-scene.
make a game object that holds information you want keep from every round.
for example; this object will hold the coins when you leave the scene.
public class GameControl : MonoBehaviour
{
public int coins;
public static GameControl gamecontrol;
void Awake()
{
if (gamecontrol == null)
{
DontDestroyOnLoad(gameObject);
gamecontrol = this;
}
else if (gamecontrol != this)
{
Destroy(gameObject);
}
}
}
After you added the coins to this object at the end of the round.
Leave the scene at end of round and go to the menu scene.
Now you can open new round in menu and you can keep the coins.

Categories