As stated in the title unity does not see the animation attached to it through the code, which in turn, this animation I put in the inspector
My player has a BoxCollider2D with IsTrigger ticked, so that it takes the value and runs
I put a check (already in the code) for the presence of animation, but he says exactly that he does not see
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CrackedPlatformScript : MonoBehaviour
{
public AnimationClip destroyed;
private void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.tag == "Player")
{
if(destroyed != null)
{
GetComponent<Animation>().Play(destroyed.name);
gameObject.GetComponent<BoxCollider2D>().enabled = false;
Destroy(gameObject,0.4f);
}
else
{
Debug.Log(destroyed.name);
}
}
}
}
Related
I created a script that lets the player open a door with the button E when the camera's box collider collides with the door's rigid body. When I test it, the door doesn't close, and I get this error:
Coroutine couldn't be started because the the game object 'Door
(Closed)' is inactive!
Here is the code for the Door script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Door : MonoBehaviour
{
public GameObject door_closed, door_opened, intDot;
public AudioSource open, close;
public bool opened;
void OnTriggerStay(Collider other)
{
if (other.CompareTag("MainCamera"))
{
if (opened == false)
{
intDot.SetActive(true);
if (Input.GetKeyDown(KeyCode.E))
{
door_closed.SetActive(false);
door_opened.SetActive(true);
intDot.SetActive(false);
//open.Play();
StartCoroutine(repeat());
opened = true;
}
}
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("MainCamera"))
{
intDot.SetActive(false);
}
}
IEnumerator repeat()
{
yield return new WaitForSeconds(4.0f);
opened = false;
door_closed.SetActive(true);
door_opened.SetActive(false);
//close.Play();
}
}
I tried activating the door at the start but still doesn't work. Everything looks perfect to me.
I have a game that is similar to "Flappy Bird" and I have main menu where I can start game and change skin of a pigeon. My skin collection is implemented with scroll rect and in the center there is a trigger which starts an animation of scaling a pigeon, it works fine until I click "start" and the scene changes to game and when I return to my main menu and click "skins" this trigger doesn't work anymore.
Script what is attached to all scroll rect elements to detect collisions with trigger:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ResizeFieldScript : MonoBehaviour
{
private Animator _anim;
private void Start()
{
_anim = GetComponent<Animator>();
}
public void OnTriggerEnter2D(Collider2D collider)
{
Debug.Log("Trigger is working");
if(collider.tag == "ResizeField")
{
Debug.Log("Condition is working");
_anim.SetBool("isInTrigger", true);
}
}
public void OnTriggerExit2D(Collider2D collider)
{
_anim.SetBool("isInTrigger", false);
}
}
Script what is attached to an empty object to change scenes:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.SceneManagement;
public class UIController : MonoBehaviour
{
[SerializeField] private List<string> sceneNameList;
private string sceneToFind;
private int index = 0;
public void SceneChanger()
{
sceneToFind = EventSystem.current.currentSelectedGameObject.name;
foreach(string str in sceneNameList)
{
if(str == sceneToFind)
{
SceneManager.LoadScene(index);
index = 0;
break;
}
index++;
}
}
public void Exit()
{
Application.Quit();
}
public void BackMenu()
{
SceneManager.LoadScene(4);
}
}
OnTriggerEnter2D doesn't work after switching scenes. We could use OnTriggerEnter2D to jump scenes.
code show as below:
private void Update() {
// If E is pressed
if (Input. GetKeyDown(KeyCode. E)) {
// scene switching
SceneManager.LoadScene(4);
}
}
private void OnTriggerEnter2D(Collider collision) {
if (collision. tag == "ResizeField") {
// The UI prompts the user to press E to jump
EnterDialog.SetActive(true);
Debug.Log("Condition is working");
// _anim.SetBool("isInTrigger", true);
}
}
Hope it helps you.
I've been trying to use this function to trigger an sound when entering a trigger but i can't make it work. I've read and read my code and nothing seems off, looks exactly like the documentation says so i just can't figure out my error.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class footsteps_script : MonoBehaviour
{
public GameObject soundObject;
public GameObject trigger;
private AudioClip clip;
public bool nextTrig;
void Start()
{
nextTrig = false;
clip = soundObject.GetComponent<AudioClip>();
}
void OnTriggerEnter ()
{
if (Bunny_script.nextTrig == true)
{
soundObject.GetComponent<AudioSource>().PlayOneShot(clip);
nextTrig = true;
trigger.SetActive(false);
}
}
}
The AudioSource is atached to another object. The trigger is supposed to play the sound after another event happens. The trigger part works fine because nextTrig is set to true like intended, but the sound doesn't play. Also, the sound itself works fine too and with a nice volume.
it does not work because, what is this ?
clip = soundObject.GetComponent<AudioClip>();
there is no component called AudioClip.
for audio clip get it from prefabs directly to the script or if you want to get it from the audio source that you have in the soundObject, then it will be like :
clip = soundObject.GetComponent<AudioSource>().clip;
and later you will play it with PlayOneShot which will be waste of time, because you are playing the same clip which is originally taken from this audio source. which actually need just this line to play it
soundObject.GetComponent<AudioSource>().Play();
finally if you are trying to get the audio clip in the script from the prefabs your code will be like :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class footsteps_script : MonoBehaviour
{
public GameObject soundObject;
public GameObject trigger;
public AudioClip clip;
public bool nextTrig;
void Start()
{
nextTrig = false;
//don't forget to assign the your audio clip to the script from the prefabs
}
void OnTriggerEnter ()
{
if (Bunny_script.nextTrig == true)
{
if (clip =! null)
soundObject.GetComponent<AudioSource>().PlayOneShot(clip);
nextTrig = true;
trigger.SetActive(false);
}
}
}
and if you already have the audio clip in audio source which is attached to the sound object then your code will be :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class footsteps_script : MonoBehaviour
{
public GameObject soundObject;
public GameObject trigger;
public bool nextTrig;
void Start()
{
nextTrig = false;
}
void OnTriggerEnter ()
{
if (Bunny_script.nextTrig == true)
{
soundObject.GetComponent<AudioSource>().Play();
nextTrig = true;
trigger.SetActive(false);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
Control control = (Control)target;
if (GUILayout.Toggle(control.isControl, "Control"))
{
control.ToControl();
}
}
}
And
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Control : MonoBehaviour
{
public Rigidbody rigidbody;
public bool isControl = false;
// Start is called before the first frame update
void Start()
{
}
public void ToControl()
{
if(isControl == false)
{
}
else
{
Destroy(rigidbody);
}
}
}
What I want to do is a guilayout.toggle or a button and to be able to destroy and to add a Rigidbody to the gameobject the Control script will be on.
How do I create back add the Rigidbody to the gameobject ?
And how do I use the isControl flag ? The idea is to use the guilayout.toggle in the editor script.
I want to destroy or add a new rigidbody while the game is running ! But using a guilayout.toggle or button in the inspector.
Actually you wouldn't need an inspector script for that at all. Simply add a repeadetly check for the bool like e.g. in LateUpdate and make the component [ExecuteInEditoMode] like
using UnityEngine;
[ExecuteInEditoMode]
public class Control : MonoBehaviour
{
public Rigidbody rigidbody;
public bool isControl;
// repeatedly check the bool
private void LateUpdate()
{
ToControl();
}
public void ToControl()
{
if (!isControl && rigidbody)
{
// in editmode use DestroyImmediate
if (Application.isEditor && !Application.isPlaying)
{
DestroyImmediate(rigidbody);
}
else
{
Destroy(rigidbody);
}
rigidbody = null;
}
else if(isControl && !rigidbody)
{
rigidbody = gameObject.AddComponent<Rigidbody>();
// adjust settings of rigidbody
}
}
}
This way LateUpdate is called both, in playmode and in editmode, and will simply react to the isControl value.
Ofcourse there is an overhead for calling this LateUpdate all the time so if you want to avoid it you can call it only from the editor. However, since you are using base.OnInspectorGUI(); you don't really need an additional Toggle since you already have the one of the default inspector.
So could simply do
using UnityEngine;
public class Control : MonoBehaviour
{
public Rigidbody rigidbody;
public bool isControl;
public void ToControl()
{
if (!isControl && rigidbody)
{
if (Application.isEditor && !Application.isPlaying)
{
DestroyImmediate(rigidbody);
}
else
{
Destroy(rigidbody);
}
rigidbody = null;
}
else if(isControl && !rigidbody)
{
rigidbody = gameObject.AddComponent<Rigidbody>();
}
}
}
and in the editor script simply do
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
private Control control;
// calle when the object gains focus
private void OnEnable()
{
control = (Control)target;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (!control.isControl && control.rigidbody)
{
control.ToControl();
Repaint();
}
else if (control.isControl && !control.rigidbody)
{
control.ToControl();
Repaint();
}
}
}
BUT you will already notice that this might affect how Undo/Redo works - in this case it would e.g. reset the isControl value but not remove along the RigidBody component leading to errors (see more below)
Or since you asked it you can add the ToggleField (currently you will have it twice since one also ships with base.OnInspectorGUI();)
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
private Control control;
// calle when the object gains focus
private void OnEnable()
{
control = (Control)target;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
control.isControl = EditorGUILayout.Toggle("additional isControl", control.isControl);
if (!control.isControl && control.rigidbody)
{
control.ToControl();
Repaint();
}
else if (control.isControl && !control.rigidbody)
{
control.ToControl();
Repaint();
}
}
}
BUT you will notice that this solution changing the value using the additional isControl lacks the possibility of using Undo/Redo completely and it will NOT mark your scene as "dirty" so Unity might not save those changes!
So if you really want to have your custom toggle field in an inspector script I would actually recommend strongly to use proper SerializedPropertys instead of directly making changes to the target (sometimes it can't be avoided like with the adding of the component though):
[CustomEditor(typeof(Control))]
public class ControlEditor : Editor
{
private SerializedProperty _isControl;
private SerializedProperty rigidbody;
private Control control;
// calle when the object gains focus
private void OnEnable()
{
control = (Control)target;
// link serialized property
_isControl = serializedObject.FindProperty("isControl");
rigidbody = serializedObject.FindProperty("rigidbody");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
// load current values into the serialized copy
serializedObject.Update();
if (!_isControl.boolValue && rigidbody.objectReferenceValue)
{
DestroyImmediate(rigidbody.objectReferenceValue);
rigidbody.objectReferenceValue = null;
}
else if (_isControl.boolValue && !rigidbody.objectReferenceValue)
{
var rb = control.gameObject.AddComponent<Rigidbody>();
rigidbody.objectReferenceValue = rb;
}
// write back changed serialized values to the actual values
serializedObject.ApplyModifiedProperties();
}
}
This looks more complicated and actually you have duplicate code but it gives you full Undo/Redo support and marks your objects and scenes dirty so Unity saves the changes.
I'm trying to add a coin to my game. If the coin isn't touched then the level won't be able to switch until the player touches the coin. My scripts are trying to set a value in a variable then when the value increases to 1 then it allowed the level to change.
How do I fix my scripts?
Coin script:
using UnityEngine;
using System.Collections;
public class Coin : MonoBehaviour {
public GameObject destroyCoin;
public static int coinWorth = 0;
void OnCollisionEnter(Collision other)
{
if (other.transform.tag == "Coin")
{
Destroy(destroyCoin);
coinWorth = 1;
}
}
}
GameManager script:
using UnityEngine;
using System.Collections;
public class GameManager4 : MonoBehaviour {
Coin coinValue = GetComponent<Coin>().coinWorth;
void Update ()
{
coinValue = Coin.coinWorth;
}
void OnCollisionEnter(Collision other){
if (other.transform.tag == "Complete" && coinValue > 0) {
Application.LoadLevel(1);
}
}
}
It might be simpler to have the Coin send its value directly to the GameManager upon collision.
Should your coin perhaps be searching for a 'Player' tag rather than a 'Coin' tag (I am assuming that the Coin.cs script will be attached to a coin object which will have the 'Coin' tag).
So in you scripts it would look like this:
using UnityEngine;
using System.Collections;
public class Coin : MonoBehaviour {
// Drag your Game Manager object into this slot in the inspector
public GameObject GameManager;
public static int coinWorth = 1;
void OnCollisionEnter(Collision other)
{
// If the coin is collided into by an object tagged 'player'
if (other.transform.tag == "Player")
{
// retrieve the gamemanager component from the game manager object and increment its value
GameManager.GetComponent<GameManager4>().coinValue++;
// Destroy this instance of the coin
Destroy(gameObject);
}
}
}
Then your second script
using UnityEngine;
using System.Collections;
public class GameManager4 : MonoBehaviour {
// Declare the coinValue as a public int so that it can be accessed from the coin script directly
public int coinValue = 0;
void Update ()
{
// This shouldn't be necessary to check on each update cycle
//coinValue = Coin.coinWorth;
}
void OnCollisionEnter(Collision other){
if (other.transform.tag == "Complete" && coinValue > 0) {
Application.LoadLevel(1);
}
}
}
Of course if you are instancing the coin from a prefab then you would need to do this differently as you wouldn't be able to drag the game menager in the inspector. If thats the case then it might be worthwhile to use a singleton class for the game manager. Let me know if that is the case and I'll show you how to do this :)