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);
}
Related
I'm using Unity's new input system and I'm trying to set up an input that places a shield in front of you as long as you hold the key down.
At the moment I can make the shield appear in the world but it's fixed in the world and locked to one direction.
Right now this is the code.
private void ShieldUp() {
GameObject shield = GameObject.Instantiate(shieldPrefab, playerFront.position, Quaternion.identity, bulletParent);
}
I created a prefab for the "shield", playerFront being the location where I want it spawn. I think all I've done is make it so every time I hit the shield key it just makes a prefab.
But, like stated before, I want it to only appear while the key is held and deleted when the key is released.
I'd also want it to face the same direction as the character, but one step at a time.
Now the problem with the new input system is there so many ways that you can use it.
so to actually help we need a lot more information about how you use the new input system.
about the code you were showing you are instantiated entire new game object each time you click the Shield button, I would recommend using a GameObject that is a child of the player GameObject and simply activating and deactivating it.
I can give you a example with the old input system.
public class PlayerShield : MonoBehaviour
{
[SerializeField] private GameObject shield;
private void Awake()
{
shield.SetActive(false);
}
void Update()
{
UseShield();
}
private void UseShield()
{
if (Input.GetKeyDown(KeyCode.E))
{
shield.SetActive(true);
}
if (Input.GetKeyUp(KeyCode.E))
{
shield.SetActive(false);
}
}
}
I have written a C# script in Unity to play a sequence of 360-degree videos of one-min duration each. The script works as expected, thanks to the support received on stackoverflow. I would now like to add a delimiter of a few seconds between each video playback, something like a blank screen which would help differentiate between the beginning and end of each video.
I tried using a GameObject with an Image on a Canvas and then setting it active after each video is played. However, it does not work as expected.
private GameObject gameobject;
gameobject = GameObject.FindGameObjectWithTag("Delimiter");
gameObject.SetActive(true);
Unfortunately, GameObject.FindWithTag(string tag) only returns active GameObjects. You cannot find an object that is disabled with this method. There are a few solutions:
Set the GameObject reference to public or add the [SerializeField] attribute, allowing you to configure it in the editor.
Start the GameObject as active and cache a reference to it before it becomes inactive. (in the awake method, or elsewhere)
Update edit for more clarification on #2:
All GameObjects run Awake() and Start() before they perform any other logic.
You could move your
private GameObject canvasObject;
to a class-level variable (instead of inside a method), and inside of the Awake() method, like this:
void Awake()
{
canvasObject = GameObject.FindWithTag("Delimiter");
}
Now you have a cached reference to your canvasObject, so you don't need to perform a GameObject.FindWithTag every time. Now you can have this method:
public void TurnOnImage()
{
canvasObject.SetActive(true);
}
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 :)
A game object has force applied to it in the positive direction, then after some time it has a force applied to it in the negative direction.
If the force is applied in the negative direction, this means game over and I want to display a totally different gameObject which is the game over gameObject called icetextureONfile. My method is not working I get error "type 'UnityEngine.GameObject' does not contain a definition for icetextureONfile". I am having a hard time refe
public void FixedUpdate() {
// No action happened yet
gameObject.icetextureONfile.SetActive (false);
// Increase the kick timer
kickTimer += Time.fixedDeltaTime;
// If the next kick time has came
if (nextKick < kickTimer) {
// Schedule the kick back corresponding to the current kick
nextKickBacks.Enqueue (nextKick + 100f);
// Apply the kick force
rb.AddForce (transform.up * thrust, ForceMode.Impulse);
// Plan the next kick
nextKick = kickTimer + Random.Range (MinKickTime, MaxKickTime);
}
// If there are more kick backs to go, and the time of the closest one has came
if (0 < nextKickBacks.Count) {
if (nextKickBacks.Peek () < kickTimer) {
// Apply the kick back force
rb.AddForce (-transform.up * thrust, ForceMode.Impulse);
// Game object was kicked down, set active game over object
gameObject.icetextureONfile.SetActive (true);
// Dequeue the used kick back time
nextKickBacks.Dequeue ();
}
}
}
If your wanting to deactivate one and then activate the other you could just add this to the class make sure its not inside the function
public GameObject iceTexture;
then drag and drop that object into the spot shown in the script in unity called iceTexture. Then just make sure you deactivate the object that the script is attached to and activate the iceTexture object.
gameObject.SetActive(false);
iceTexture.SetActive(true);
This page might help you.
This syntax worked for me
GameObject.Find ("icetextureONfile").SetActive(false);
As opposed to what is found in the Unity docs
gameObject.SetActive(false);
The first worked for me, the second did not. I am not a great programmer, so maybe it is just a matter of context.
Edit
It is commonly known that it is difficult to SetActive(true) after the object has already been SetActive(false). This is because the attached script becomes deactivated too. See Unity forums for details on why this is a nightmare.
To overcome this I have chosen a different route that accomplishes the same thing.
I set the size of the object to 0 until I needed it.
GameObject.Find ("icetextureONfile").transform.localScale = new Vector3(0, 0, 0);
GameObject.Find ("icetextureONfile").transform.localScale = new Vector3(0.02f, 0.02f, 0.02f);
Note that 0.02 is the size of my object in particular and may not be the exact same size as yours.
I'm writing a game with some animations, and use those animations when the user clicks on a button. I would like to show the user the animation, and not "just" call a new level with Application.loadLevel. I thought I could use the Time.DeltaTime in the onMouseUp method and add it to a predefined 0f value, then check if it is bigger than (for example) 1f, but it just won't work as the onMouseUp method adds just "it's own time" as the delta time.
My script looks like this now:
public class ClickScriptAnim : MonoBehaviour {
public Sprite pressedBtn;
public Sprite btn;
public GameObject target;
public string message;
public Transform mesh;
private bool inAnim = true;
private Animator animator;
private float inGameTime = 0f;
// Use this for initialization
void Start () {
animator = mesh.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
}
void OnMouseDown() {
animator.SetBool("callAnim", true);
}
void OnMouseUp() {
animator.SetBool("callAnim", false);
animator.SetBool("callGoAway", true);
float animTime = Time.deltaTime;
Debug.Log(inGameTime.ToString());
// I would like to put here something to wait some seconds
target.SendMessage(message, SendMessageOptions.RequireReceiver);
}
}
}
Im not entirely sure what your trying to do by using Time.deltaTime in onMouseUp. This is just the time in seconds since the last frame was rendered, and should act the same no matter where you try to access it. Normally it is used in a function that is called every frame, not one-off events like onMouseUp.
Despite not being certain what you are trying to achieve, it sounds like you should be using Invoke:
http://docs.unity3d.com/ScriptReference/MonoBehaviour.Invoke.html
Just put the code you wish to be delayed into a separate function, and then invoke that function with a delay in onMouseUp.
EDIT: To backup what some others have said here I would not use Thread.Sleep() in this instance.
You want to do this (and all waiting functions that do not appear to make the game "freeze") by blocking the Update loop by using a Coroutine.
Here is a sample of what you are probably looking for.
void OnMouseUp()
{
animator.SetBool("callAnim", false);
animator.SetBool("callGoAway", true);
//Removed the assignement of Time.deltaTime as it did nothing for you...
StartCoroutine(DelayedCoroutine());
}
IEnumerator DoSomethingAfterDelay()
{
yield return new WaitForSeconds(1f); // The parameter is the number of seconds to wait
target.SendMessage(message, SendMessageOptions.RequireReceiver);
}
Based on your example it is difficult to determine exactly what you want to accomplish but the above example is the "correct" way to do something after a delay in Unity 3D. If you wanted to delay your animation, simply place the calling code in the Coroutine as I did the SendMessage invocation.
The coroutine is launched on it's own special game loop that is somewhat concurrent to your game's Update loop. These are very useful for many different things and offer a type of "threading" (albeit not real threading).
NOTE:
Do NOT use Thread.Sleep() in Unity, it will literally freeze the game loop and could cause a crash if done at a bad time. Unity games run on a single thread that handles all of the lifecycle events (Awake(), Start(), Update(), etc...). Calling Thread.Sleep() will stop the execution of these events until it returns and is most likely NOT what you're looking for as it will appear that the game has frozen and cause a bad user experience.