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.
Related
I've tried a few ways of doing it. I've asked a few friends but, nothing seems to work so far. I have changed the script several times so I don't have the other ways that I have tried anymore. However, this is the one that gave me the least errors. Others I had to continuously change it to a recommended way by Unity but ended at a dead end and nothing worked.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LightActivator : MonoBehaviour
{
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
gameObject.SetActive(false);
}
else if (Input.GetKeyDown(KeyCode.Space))
{
gameObject.SetActive(true);
}
}
}
I want to be able to turn on and off the ambient/directional light with just 1 button. Is that not possible?
two little flaws here
after you do
gameObject.SetActive(false);
this very same object is now inactive -> this component as well -> Update is no longer being called at all ;)
You always will ever only treat the first case .. the second one is never called at all since the condition will always match already with the first block!
Instead separate the logic from the target object and do e.g.
// This class should go to a different object that is always active in your scene
public class LightActivator : MonoBehaviour
{
// Here you reference the object you want to (de)activate via drag&drop in the Inspector
public GameObject theLight;
void Update()
{
// You only need one condition check
if (Input.GetKeyDown(KeyCode.Space))
{
// INVERT the active state of the light object whatever it currently is
theLight.SetActive(!theLight.activeSelf);
}
}
}
In order to keep things together you could e.g. simply make the according light object a child of the LightActivator object ;)
My Problem:
I cant get it to work, that every Building has its own SpawnPoint.
I'm working on an RTS like build mechanism. I have set it up that after pressing a key I can place buildings in the scene. The buildings get instantiated from a prefab and after they get instantiated they get a script called "BuildingScript" attached to them. Now i want to implement, so that i get a individual spawn point for every building (for now just next to it). I got a UI set up with a button, which by pressing spawns a unit at the building.
I had the "BuildingScript" attached to the prefab, but when i set the spawn point for one Building, it set it for every Building in the Scene. So a Unit was Spawned always at the same Buidling.
I want to set it up, that every Building has its own spawn point. Thats why I want to give every Building the script "BuildingScript" when Instatiated, because I hope, that this way every script gets handled individually. Is that right? Or will it still set the same point for every building, because the script is still the same?
Also I wanna reference the current placed building to the button, so when its clicked, it will run only the code of the last placed building (for now). I think I cant do this by using "On Click()" Of the Button, because my clone isnt Instatiated yet, so I have to reference the clone to the button somehow via Script, so the button works with the clone.So my problem is, that I need to set a reference from my cloned Building to the Button, after I placed the clone.
I googled a lot on how to do this, but didnt found any answers to my problem besides this https://forum.unity.com/threads/controlling-instantiated-game-objects-from-ui-buttons.332005/.
But I cant get it to work and I think it will not work because my clone is an Object and not a GameObject, so I could never set reference to it to call the funktion SpawnUnit(), because GetComponent only works for a GameObject.
Now I'm really at a point where I just don't know how Unity handles these kind of things.
BuildingScript on the Instantiated Building
public class BuildingScript : MonoBehaviour
{
public bool SavePos = false;
public Vector3 SpawnPoint;
public Vector3 BuildingPos;
public GameObject Unit;
void Start()
{
FindObjectOfType<SpawnButtonReference>().GiveReference(this);
}
public void SpawnUnit()
{
//I did this because if a building gets instatiated i wanted it to save its
Position to Spawn Units from it (doesnt really work though).
"MousePos" ist the last Position of the Mouse in the PlacementScript, before klicking to place the building.
if (SavePos == false)
{
BuildingPos = GameObject.FindObjectOfType<GroundPlacementController>().GetComponent<GroundPlacementController>().MousePos;
Debug.Log(BuildingPos);
SavePos = true;
}
float PosX = BuildingPos.x + 2;
float PosZ = BuildingPos.z + 2;
SpawnPoint = new Vector3(PosX, 0, PosZ);
Debug.Log("Spawn" + SpawnPoint);
Instantiate(Unit, SpawnPoint, Quaternion.identity);
}
}
Script on the Button
public class SpawnButtonReference : MonoBehaviour
{
public GameObject objectReference = null;
internal void GiveReference(BuildingScript Object)
{
objectReference = Object;
}
void OnButtonPress()
{
if (objectReference != null)
{
objectReference.GetComponent<BuildingScript>().SpawnUnit();
}
}
}
So I solved it myself with a little workaround. Instead of trying to reference the clone, I wrote a script on the Spawn Button which searches all Objects with the "BildingScript" then if they are Selected (which can only be one Building) it spawns a Unit at its Spawn point.
The Building itself saves his spawn point when being placed (so when Input.GetMouseButtonUp(0))
works very well for me :)
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()}
Heres my first attempt at loading the next level upon reaching "Goal"
public int CurrentLevel = 0;
public static int maxlevel = 3;
public void CompleteLevel()
{
if (CurrentLevel < maxlevel)
{
CurrentLevel += 1;
SceneManager.LoadScene(CurrentLevel);
}
else
print("you win");
}
This is in another class...
void OnTriggerEnter(Collider other)
{
if (other.transform.tag == "DeathObject")
Die();
if (other.transform.tag == "Goal")
Manager.CompleteLevel();
}
It ended up loading the first level, went to the second, then it would repeat the second map when i reached goal. Another thing it would do is skip to the last level from the first or second level.. not sure whats going on there. Heres the second thing i tried:
public void LevelPassTest()
{
if (Application.loadedLevel > 4)
Application.LoadLevel(Application.loadedLevel + 1);
else
print("win");
}
This is in another class....
void OnTriggerEnter(Collider other)
{
if (other.transform.tag == "DeathObject")
Die();
if (other.transform.tag == "Goal")
Manager.LevelPassTest();
}
I'm not sure why, but sometimes it doesn't load the next level, it worked for a while then stopped, after I reset unity it works again, so I'm not sure if it's my code or unity... I get a warning message that says "Warning CS0618 'Application.loadedLevel' is obsolete: 'Use SceneManager to determine what scenes have been loaded'" and "Warning CS0618 'Application.LoadLevel(int)' is obsolete: 'Use SceneManager.LoadScene'" I'm new to coding and completely lost on this. spent 4 hours trying to fix it. What are these warnings? can they be effecting the loading? I was also wanting to be able to save the value of the level so i can use it in game saves, and attach high scores to it. I tried using this in my first attempt, but it didn't work how i was hoping. (CurrentLevel)
Application.LoadLevel and the rest are obsolete as of Unity 5. You have to use SceneManager instead.
So Application.LoadLevel() is now SceneManager.LoadScene().
You must also include using UnityEngine.SceneManagement;
See here: http://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
All it takes is a quick Google.
Are your scenes correctly added to the Build Settings?
Go to File > Build Settings... and check in "Scenes In Build" whether all your scenes from scene #0 to scene #3 are added the way you need them.
The first example you gave should work, however you have to make sure, that your first script (containing CurrentLevel) is not destroyed on loading the next scene. Do this by calling GameObject.DontDestroyOnLoad(gameObject) in its void Start(). Alternatively you can make CurrentLevel a static member.
This is necessary so the value of CurrentLevel is not lost when loading the next scene. This would explain why you kept loading the same level over and over.
In your second example, in LevelPassTest() you check if Application.loadedLevel > 4, this of course has to be Application.loadedLevel < 4. If you fix this, the second example should work just fine, too.
And yes, you are partially working on obsolete API, but that does not explain why it is not working.
using UnityEngine.SceneManagement;
and then use SceneManager.LoadScene() the same way we used to use Application.LoadLevel(), in unity 5.x.x Application.LoadLevel is obsolete - meaning it will be removed in the future and should not be used, and it is not guaranteed that it will work properly.
I recommend you read Unity's documentation on Scene and SceneManager classes so you can get familiar with the changes unity 5 introduced.
how can I display 3D text after certain time then hide it after certain time
My tries
public Text text_tap;
GameObject.Find("3dtext").active = true; // first try but it dosnt work
if (Time.time > 5) {
// second try but it I cant attach my 3d text to my script
text_tap.gameObject.SetActive(true);
}
I cant find any thing in 3D documentation
I don't know the exactly problem, but there you have some hints:
If you search in the scene for a GameObject that is deactivated it won't find it. The Gameobject MUST be active for the GameObject.Find() function to work. The easiest thing you can do is to keep the GameObject activated, and if the initial state is for it to stay hidden just hide it in the Awake().
Secondly, seems that you are trying to access a TextMesh object
but you reference in your code a Text object.
If you find a GameObject and request a Component that the GO does not contains, it returns null.
Finally The api to Activate/Deactivate a GameObject (GO) is
myGameobject.SetActive(true)
The one you are using (myGameobject.active = true) is deprecated
Try this example, it should work:
public YourMonoBehaviour : MonoBehaviour
{
public TextMesh text_tap;
float awakeTime;
void Awake()
{
// Remember to activate the GO 3dtext in the scene!
text_tap = GameObject.Find("3dtext").GetComponent<TextMesh>():
awakeTime = Time.time
}
void Update()
{
if ((Time.time - awakeTime) > 5)
{
// second try but it I cant attach my 3d text to my script
text_tap.gameObject.SetActive(true);
}
}
}
If you need to "do something after a delay" you're talking about Coroutines.
Checking Time.time will only check if the game has been running for x time, and using Thread.Sleep in Unity will cause it to delay since you're causing an Update or similar to lock and not return.
Instead, use
yield return WaitForSeconds(5);
text_tap.gameObject.SetActive(false);
As another warning, this code assumes that the target object is not the same gameObject as the one hosting this script, since coroutines do not execute on inactive objects. Similarly, disabling an ancestor (via the scene hierarchy, or transofrm.parent) of a gameObject disables the gameObject itself.
If this is the case, get the component that renders 3d text and disable it instead of the whole gameObject via the enabled field.
you can also use Invoke() to achieve. as explained above note that the text would have to be set by other means than Find cause if it is not active it will not find it.
void Start() //or any event
{
Invoke("ShowTextTap", 5f);//invoke after 5 seconds
}
void ShowTextTap()
{
text_tap.gameObject.SetActive(true);
//then remove it
Invoke("DisableTextTap", 5f);
}
void DisableTextTap()
{
text_tap.gameObject.SetActive(false);
}