- Home /
How do I "trickle" a function's effect over n seconds?
I'm trying to make a healing skill which yields results gradually over time: as long as you hold the skill button down, there is a random chance that you'll regain a few hitpoints every half second. However, I'm having a heck of a time with the "holding" part: right now pressing "1" calls my HealOverTime function, which reads as follows:
public void HealOverTime(){
while (Input.GetKeyDown(KeyCode.Alpha1)){
Debug.log("You are trying to heal");
}
I was hoping this would run continuously, but neither tapping nor holding "1" can get it to produce the debug message and prove it's firing. Am I missing something obvious, or is this plain the wrongheaded way to go about solving this problem?
Answer by AndyMartin458 · Jul 07, 2014 at 03:57 AM
GetKeyDown will only fire the first time the key is pressed. If you want some kind of auto-fire, you need to use GetKey. http://docs.unity3d.com/ScriptReference/Input.GetKey.html
Also you DO NOT want to detect the key press in a while loop. Detect it in the Update loop of a MonoBehaviour instead. That while loop will keep other scripts and functions from executing.
Hmm okay, is there any alternative to doing it in Update? I'm trying to structure this so my game can support an extremely large number of skills, so the way it's implemented right now, my action bar is nine NGUI buttons which are each connected to my alpha1-9. I have one script SkillsLibrary.cs which contains a short function for each attack, buff, heal, and so forth, and when I drag and drop any skill into any slot in the action bar, it configures that button to notify the method in SkillsLibrary corresponding to the skill I want.
What if I set up a coroutine with a bool finished, and do something like this:
while (finished==false){
//check if heals are applied and act accordingly
if(Get$$anonymous$$eyUp("ActionButton1"))
finished=true;
yield return new WaitForSeconds (0.5f);
}
Sorry for the obvious question, but my understanding of data structures is still really shakey and I know how easily I can mess myself up with a bad loop or coroutine ^^
@Sendatsu_Yoshimitsu It might work that way, but the problem with detecting key up in a coroutine is that it is not guaranteed to register the key up as you'd expect. $$anonymous$$eyDown and $$anonymous$$eyUp should essentially always be detected in an Update function (run exactly once per frame so that it can never be missed).
The good part for you though is that you can still do what you want with the coroutines. You can start and stop those coroutines from Update. Something like this:
void Update()
{
if(Get$$anonymous$$eyDown("ActionButton1")
StartCoroutine("ActionButton1Coroutine");
if(Get$$anonymous$$eyUp("ActionButton1"))
StopCoroutine("ActionButton1Coroutine");
if .....//You do the same thing for all of your buttons
}
Ooh that makes sense, thank you! One final clarification though, if each keypress sends me to a coroutine, what do you recommend as the most optimal way to get a reference to the right function? Not every skill needs a coroutine (attacks, for instance, should only execute once and only once), but I can't think of an efficient way to check whether or not I need one on a case-by-case basis, and on the flip side I'm not sure if it would be smart to run everything through coroutines, even the functions that didn't need one.
@Sendatsu_Yoshimitsu use functions ins$$anonymous$$d of coroutines where possible. Look into delegate functions but keep it simple.
Hm, maybe a silly question, but would InvokeRepeating have the same problems as While? Because wouldn't it be simpler than using delegates to simply go:
if (Input.GetButton("ActionSlot1"){
InvokeRepeating("Heal$$anonymous$$e", 0, 0.5f)
}
Answer by SirCrazyNugget · Jul 07, 2014 at 03:54 AM
Firstly, using while within a function will 'pause' and then overload the game, you could use a coroutine and return it at the end of each frame or just use Update and check the key's pressed.
//called every frame
void Update(){
//GetKey is checked every frame which is what you'll need
//GetKeyDown is only return true when the key is initially pressed
if(Input.GetKey(KeyCode.Alpha1)){
AttemptHeal();
}
}
From there just write a simple Heal function based on the Time.time
private float _prevHeal = 0;
void AttemptHeal(){
//make sure the time is greater than the previous heal time + 1/2 a second
if(Time.time > _prevHeal + 0.5f){
//do heal stuff here
_prevHeal = Time.time;
}
}
Your answer
Follow this Question
Related Questions
How to successfully apply force calling a function from another script 1 Answer
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Srcipting: how retrun struct in function , C#? 1 Answer
Problem setting up twin stick shooter for mobile device... 1 Answer
Access one function in multiple classes 2 Answers