- Home /
Causing damage at intervals/returning a value. C#
You're going to have to excuse what is most likely going to be a dumb question but I need a bit of help here. I'm dealing with a script where I want the player to suffer damage at a set interval.
Parts of the code I'm using important to this question:
public float DamDelay = 2.0f;
private PlayerHealth_Test playerHealth;...
playerHealth = Target.GetComponent<PlayerHealth_Test>();...
void Update(){
if (parenting == true)
{
Invoke ("Damage", DamDelay);
}
}
void damage(){
playerHealth.CurrentHealth -= 1.0f;
}
I looked around the answers forum but the stuff I came upon (yield, WaitForSeconds and such) are for Javascript. Apparently Invoke is supposed to be close to that (and I've actually used Invoke before) so I ended up using that. The problem being, I don't actually have a clue how to set up a return function in C# having never had to deal with such a thing before. It doesn't help that the value I'm modifying is from another script. I know that by giving damage the void prefix it's not going to return something by definition but again, no real idea how to return a value.
So if you'll excuse the stupidity I could you some help figuring this out.
A search for "Unity Coroutines C#" should set you on your way. Yield and WaitForSeconds etc are part of the Coroutine setup and definitely do work for C#.
But you may want to do something even simpler if you want to apply constant damage... you could easily set up a set of 'damageToApply' and 'damagePerSecond' variables, then apply the damage proportionally each FixedUpdate().
Btw. to return use 'return'... and find some coding tutorials ;)
I look for tutorials when I can but I try and look for very specific tutorials, I don't have the time between classes to look for the basics as much as I would like. I tend to either find tutorials that give me just what I'm looking for at the time or head over here if I run into a wall (which I am prone to do). Learning a lot either way though. (There's also the fact that I rarely know exactly what my problem is.)
Also, I tried using return (I assumed that would, you know, return the variable but when I tried it all I got was an error.
I'll be taking a look at Coroutines when I get the chance though, that seems like it'll be useful.
Answer by Tomer-Barkan · Nov 07, 2013 at 08:12 PM
There are a few ways to go about this. One would be to use invoke, but then you need to use it only once, not every Update(), as it will call it every frame (with a starting delay of 2 seconds):
private bool invoked = false;
void Update() {
if (!invoked) {
Invoke("Damage", DamDelay);
invoked = true;
}
}
void Damage(){
playerHealth.CurrentHealth -= 1.0f;
invoked = false;
}
Another would be to use coroutines like @Jix suggested.
The third, and my personal favorite, is simple, no magic, you understand exactly what happens. Simply set the time in which you want the damage to happen (current time + DamDelay), and when the time comes, do the damage and reset the timer.
private nextDamage;
void Start() {
nextDamage = Time.time + DamDelay;
}
void Update() {
if (nextDamage <= Time.time) {
nextDamage = Time.time + DamDelay;
playerHealth.CurrentHealth -= 1.0f;
}
}
Sorry for taking so long to get back to this, I was having computer troubles.
Ah, so that why the health is dropping at a ridiculous rate, I thought it had something to do with the update but I wasn't sure.
I like your suggestion, the less hoops and such I have to jump through and the more straightforward the better. I give that a shot when I get the chance but that looks like just what I needed.
Answer by Jix · Nov 07, 2013 at 05:44 PM
Please put in mind that the string in Invoke() is case sensitive, you wrote there "Damage" but you method name is "damage".
Also you are mistaken,(yield, WaitForSeconds and such) are not for Javascript only, they work for C# as well. You just need to know how use them, I'll give you an example:
void someMethod()
{
StartCoroutine(damage());
}
IEnumerator damage()
{
yield return new WaitForSeconds(1);
playerHealth.CurrentHealth -= 1.0f;
}
but when you use coroutines you should know that if the script gone inactive for any reason it will stop.
I don't know if you want the damage to happen every 2 seconds or you want to delay it 2 sec. if you want it to keep calling damage() then use InvokeRepeating() instead
Apologies for taking so long to get back to this, I had some computer trouble.
I realized that I messed up the string in Invoke(). I fixed that but forgot to change it in this question. It does damage but it does it much faster than I want ( I do want it do do damage every 2 seconds, or however many seconds I choose, while parenting is active).
Also, good to know about yield and such, looks like I'm going to have to look up some tutorials on that.
Answer by Dracorat · Nov 07, 2013 at 05:42 PM
You should never modify variables of another class. While the language may allow it, it is bad practice.
So what you should do instead, is inside the Player_Health component, have a method like this:
public void ApplyDamage(float howMuch){
this.CurrentHealth -= howMuch;
}
Then, use the method when you need it:
playerHealth.ApplyDamage(1);
Then, if you need to add stuff like invincibility timers, etc, you can add them in the ApplyDamage routine.
As for the delay, if it's because of an environmental effect, just start a couroutine and every time the coroutine comes up for execution again, just ApplyDamage
again.
Sorry for taking so long to get back to this, I was having computer troubles.
So have the ApplyDamage method within the player health script and then have playerHeath.ApplyDamage(1); in the other script if I'm understanding that correctly?
That seems like it could be very useful, thank you very much.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Urgent help for Unity Game with deadline tomorrow 0 Answers
C# Grenade Explosion in Radius 1 Answer
Creating laser gun effect. 1 Answer