I'm trying to create a apply a fairly simple buff to my character for a short duration, but it seems that whatever method I try to use it does not want to apply.
I've tried creating a manual timer, making use of coroutine and now making use of invoke with a delay, but in each case it applies the increase in speed on collision, but then never does anything after the delay (also doesn't debug log after delay), see the screenshot below for the code.
Image of code
Any help would be greatly appreciated! Thanks
You destroy the gameobject allong with the script, that's why it never get's executed.
I'm not sure why you destroy the gameobject but you can remove the Destroy(this.gameObject);
If the Destory() method is necessary, you can use it inside your TimerBuff() method like this.
public void TimerBuff()
{
Debug.Log("timerstop");
PlayerMovement.runSpeed = 5f;
Destroy(gameObject);
}
Related
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.
I'm trying to set an animator's playback time. (or, start an animation at a specific time) I haven't had success with either approach.
Note: I am setting the Animator (an) in the Start().
Code I've tried:
Public Animator an;
public void SetTime(float time)
{
an.playbackTime = time;
}
Oops, I guess this one was pretty easy!
I didn't see the constructor options for the Play() method!
The answer:
an.Play("YourAnimation", 0, 0.4f);
However, I am still currious why my original code didn't work. So I figured out how to make an animation play/start at a specific time... Does anyone know how to basically "rewind" an animation to a specific point? (while it's playing)
i'm making my first enemy AI in unity. I'm trying to make a finished state machine with the animator controller to do it.
I just discovered the StateMachineBehaviour script which is called when the AI is in a state. It has multiple methods, including the OnStateEnter. It is called everytime the AI enter the state.
My problem is only about optimization, my AI need to get the GameObject "Player" in order to attack it. So i'm getting it in my OnStateEnter method for the moment, which i feel is bad, because i'm getting it every time the animation is called, i would like to get it only once, at the start.
I basicly need a start function but it's not working, i have made research and found nothing. I tried to watch video about people making a finished state machine but they are just getting the same GameObject multiple time ( example here : https://youtu.be/dYi-i83sq5g?t=409 ).
So, is there a way to have a start function or to get an element only once ?
I could make a bool that is called only the first time and that get the GameObject, but again that would be an "useless" if running in my function.
Any suggestions ? Thanks
No, unlike a MonoBehaviour a StateMachineBehaviour has no Start message only OnStateEnter, OnStateExit, OnStateIK, OnStateMove and OnStateUpdate.
There are also Awake and OnEnable but I'm pretty sure they are not used in the StateMachine and might not behave as expected.
You can however either use
OnStateMachineEnter
Called on the first Update frame when making a transition to a StateMachine. This is not called when making a transition into a StateMachine sub-state.
Or use a simple bool flag like
bool alreadyExecuted = false;
OnStateEnter()
{
if(alreadyExecuted) return;
// Do your stuff
alreadyExecuted = true;
}
(Just a guess)
In the Inspector you actually can enable and disable StateMachineBehaviours like components. So it might be able to do this also in script maybe the same way using
enabled = false;
but I didn't find anything about it in the API and since I'm currently on my Smartphone I can't test it.
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.
I Need to apply DontDestroyOnLoad on Scene.is it possible?
I Need to Do not disturb the scene when going in to another scenes also.here i'm sending mail,when ever clicking send button its going to authentication in mail server in this time my scene idle means not responding anything until come back to the response from mail server,so on that time i show one loading bar in my scene.this is not do process.the entire scene is hang until came response from mail server,so how to solve this?
void Awake()
{
DontDestroyOnLoad(this.gameObject);
}
After reading so many non-answers I finally found the answer in a Unity forum. DontDestroyOnLoad ONLY works if the game object in question is at a "root level" meaning right under the scene, not nested under any other object. This is not mentioned anywhere in the documentation.
When loading a new level, scene, all Game Objects of the previous scene are destroyed by Unity.
If you want to protect a Game Object you can use the function.
DontDestroyOnLoad(gameObject);
It is important to note that when you say: this.gameObject you are pointing to pretty much the same thing, it just happens that this points directly to the script attached to that gameObject. So you don't need the this part, just gameObject will do.
Ideally you could protect that gameObject inside void Awake()
void Awake()
{
DontDestroyOnLoad(gameObject);
}
The above code will prevent Unity from destroying that gameObject unless your game closes completely or at a later point you call Destroy() on it. That means you can change from scene to scene and the gameObject will survive. However, if you make it back to the scene that creates that gameObject you are protecting you may run into problems if you do not have the logic implemented that prevents you from protecting a second, third, or many of that gameObject.
Your second question, if I understand it correctly:
You want to send mail when you change scenes, but your progress bar wont progress while changing scenes, it just stays there, static.
If that is the case then your problem is in Application.LoadLevel(sceneName); If you have the free version of Unity, then you need to come up with your own creative way of showing that progress bar, because Application.LoadLevel() will halt everything until it takes you to the new scene.
I don't completely understand what you are saying.
But because in your context, this in represents most probably a Monobehaviour, try the following:
void Awake() {
DontDestroyOnLoad(this.gameObject);
}
or
void Awake() {
DontDestroyOnLoad(gameObject);
}
See http://docs.unity3d.com/Documentation/ScriptReference/Object.DontDestroyOnLoad.html
I recommend you use a coroutine, with the 'yield' statement
check out this documentation of the WWW class, which likewise involves writing code to cope with waiting for a response from the web, without hanging your Unity3d program
coroutines are pretty powerful if you're working with tasks that take more than a frame or two. Richard Fine (AltDevBlog) has posted a really detailed description of what they are and how to use them, which I thoroughly recommend.