- Home /
Working projectile scripts do not work due to if condition
Hi there,
I've successfully managed to have my player shoot fireballs from his hands. However, this is done on a key press.
I now want my enemy to fire fireballs, and so I tried to use exactly the same script. However, the fireball stays in its position and does not move forward. The reason for this is because the firing of this fireball happens when the enemy is a certain distance away from my player. Therefore, I believe the fireball keeps instantiating itself, keeping each one from moving forward. I tested this by adding a sound, and the sound rapidly repeats multiple times, indicating that the fireballs are being instantiated far too often.
Here is a code snippet from my first script, which is attached to my enemy game object:
void PatrolAndChase()
{
// calculate the distance to the player
int distanceToPlayer = (int)Vector3.Distance (player.transform.position, transform.position);
// calculate vector direction to the player
Vector3 directionToPlayer = transform.position - player.transform.position;
// calculate the angle between AI forward vector and direction toward player
// we use Mathf.Abs to store the absolute value (i.e. always positive)
int angle = (int)Mathf.Abs (Vector3.Angle (transform.forward, directionToPlayer));
**if
(distanceToPlayer > 60) {
StartCoroutine (Shoot ());
}**
// if player is within 30m and angle is greater than 130 then begin chasing the player
else if (distanceToPlayer < 30 && angle > 130) {
// move towards the players position
//MoveTowards (player.transform.position);
// attack the player ONLY if not already attacking
if (!attacking && distanceToPlayer < 15) {
StartCoroutine (Attack ());
} else if (!attacking) {
// player is "out of sight"
MoveTowards (player.transform.position);
}
}
else {
// patrol
Patrol ();
// if attacking, then toggle to stop
}
}
The code surrounded by asterisks is what we're interested in. This calls the Shoot coroutine, which is in the same script and is as follows:
IEnumerator Shoot()
{
yield return new WaitForSeconds(2);
attacking = true;
StartCoroutine (BowserFireball.Instance.Fire());
attacking = false;
}
We can see here that this coroutine is calling yet another coroutine from my BowserFireball script. I've also added a WaitForSeconds clause to have the fireball sequence happen every 2 seconds. However, the routinely firing of the fireball does not work. Here is the BowserFireball script:
using System.Collections;
public class BowserFireball : MonoBehaviour {
public static BowserFireball Instance { get; private set; }
public Rigidbody projectile;
public AudioClip fireballSound;
public GameObject target;
void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
public IEnumerator Fire()
{
animation.CrossFade("fireball (1)", 0.2F);
audio.PlayOneShot (fireballSound);
Rigidbody instantiatedProjectile = Instantiate (projectile,
transform.position,
transform.rotation)
as Rigidbody;
instantiatedProjectile.velocity = transform.TransformDirection (new Vector3 (0, 0, 50));
yield return new WaitForSeconds(2);
Destroy (instantiatedProjectile.gameObject);
}
}
This script governs the firing of the fireball and how it destroys itself. It is attached to an empty game object called FireballSpawn, which is a child of my enemy.
As stated previously, these scripts (with a few tweaks) worked for my player, but not for my enemy (because of the condition that the enemy fires the fireball constantly if he's a certain distance away from my player, I'm assuming). I need my enemy to fire a fireball every 1.5-3 seconds or so, so that 1): it is more routine and not a constant flow of fireballs and 2) (and most importantly): my fireballs can actually move and the noise he makes happens once per fire.
Your time and support would be thoroughly appreciated,
Many thanks!
Answer by robertbu · May 04, 2014 at 02:36 PM
I'm guessing a bit because the code I need to see to nail down the problem is not here. I'm guessing that you are calling PatrolAndChase() frequently...perhaps every frame or FixedUpdate(). For each one of those calls, you are generating a new coroutine. So if your game is running at approximately 60 fps, in the 2 seconds that Shoot() waits before firing, you stack, your code will stack up 120 coroutines. At the end of 2 seconds, you will start to see calls to BowserFireball.Instance.Fire() at approximately one frame apart. So you are going to need to figure out some mechanism so that Shot() is not call while it is currently running. Something as simple as a boolean flag:
IEnumerator Shoot()
{
shooting = true;
yield return new WaitForSeconds(2);
attacking = true;
StartCoroutine (BowserFireball.Instance.Fire());
attacking = false;
shooting = false;
}
Then your check would become:
if (!shooting && distanceToPlayer > 60)
@robertbu Thanks very much for your time. Yes, PatrolAndChase() is happening very frequently as I forgot to mention that the Waypoint assigned to my enemy is on my player, which means he'll always be following him and so if he gets close PatrolAndChase() will run.
I will give your solution a try and let you know in due course. Once again, your help is much appreciated!
@robertbu After much, much rearranging of and experimenting with code, I still haven't managed to achieve my desired outcome. Here's my code in Shoot():
IEnumerator Shoot()
{
shooting = true;
animation.Play("fireball (1)");
audio.PlayOneShot (fireballSound);
StartCoroutine (BowserFireball.Instance.Fire());
yield return new WaitForSeconds(animation["fireball (1)"].length);
shooting = false;
}
What happens here is my enemy runs towards my player, attempts to do his fireball animation but then gets cut off and starts running again. The fireball also does not move forward and ins$$anonymous$$d freezes there (possibly because loads are instantiating?). However, the sound correctly plays once every couple of seconds (the animation's length of time), so that's a start! :-)
If I move animation.Play("fireball (1)"); and yield return new WaitForSeconds(animation["fireball (1)"].length); ABOVE shooting = true;, then the animation plays fully but then the sound rapidly plays at multiple times again, as well as the fireball continuing to remain still - almost back to square one! So both code attempts do a different part of what I want to achieve, but none get the fireball moving!
With this information, are you able to help me resolve this issue? This is the final puzzle piece to my game, and I really don't know what to do! In case you need it, here is my BowserFireball script:
using UnityEngine;
using System.Collections;
public class BowserFireball : $$anonymous$$onoBehaviour {
public static BowserFireball Instance { get; private set; }
public Rigidbody projectile;
public GameObject target;
public AudioClip fireballSound;
void Awake()
{
if (Instance == null)
{
Instance = this;
}
else
{
Destroy(gameObject);
}
}
public IEnumerator Fire()
{
Rigidbody instantiatedProjectile = Instantiate (projectile,
transform.position,
transform.rotation)
as Rigidbody;
instantiatedProjectile.velocity = transform.TransformDirection (new Vector3 (0, 0, 50));
yield return new WaitForSeconds(3);
Destroy (instantiatedProjectile.gameObject);
}
}
$$anonymous$$any thanks for all your time!
@robertbu Sorry to pester you, did you manage to look into my above comment? This is really starting to grate on me! Could anyone assist on this matter please?
$$anonymous$$any thanks for your time!
There are potentially multiple issues, but I spot one here:
IEnumerator Shoot()
{
yield return new WaitForSeconds(2);
attacking = true;
StartCoroutine (BowserFireball.Instance.Fire());
attacking = false;
}
You are setting 'attacking' to true after the two second wait. That means that during that two seconds, your coroutines are stacking up just like they did originally. You need to move the:
attacking = true;
...line to the first line of the 'Shoot' function. That way once a shoot has be instigated, no more shots will be taken.
Your answer
Follow this Question
Related Questions
Make multiple Projectiles move at the same Time... 0 Answers
Distribute terrain in zones 3 Answers
IEnumerator not looping correctly? 1 Answer
How to disable a script on a bunch of instantiated objects with tag ? 1 Answer
c# 2D top down, fire projectale which continuously move in a direction 3 Answers