Figured it out eventually.
Turret not spawning fireball via instantiation in Unity 2d?
Hi folks!
I've been loosely following this tutorial series (https://www.youtube.com/watch?v=bMh4UDYVyGU), until recently finishing part 19 where it involves coding an enemy turret, however I have a major issue with it. Essentially a turret is supposed to pop up out of the ground and shoot a fireball at the player when they get close.
Problem is, when the player gets nearby, nothing happens. The player can walk near the enemy and they'll pop up out of the ground, but upon touching the two collision 'cones' on either side, the turret is supposed to instantiate a bullet that heads towards the player. Yet nothing happens at all! The strange thing is there are absolutely no errors in the console either, so in theory it should be working and I have no idea where the problem is to pinpoint it.
Anyways, I'll post the code here that's divided into two scripts (one that goes inside the turret and one that goes in the two colliders either side of it). Because I've been trying for hours to get this working and it's been an absolute nightmare! Thanks in advance for the help everyone!
Collider cone script:
//For when the Bird enters one of the two collision detection cones on both sides of the Dino, when the player touches it the Dinosaur will begin to shoot them
using UnityEngine;
using System.Collections;
public class AttackCone : MonoBehaviour {
//Variables
//Calling the Dino script
public DinoTurretAI dinoTurretAI;
//Boolean, starts false as it's to check which cone will be used (left or right)
public bool isLeft = false;
void Awake()
{
dinoTurretAI = gameObject.GetComponentInParent<DinoTurretAI> (); //When it wakes up call to the other Dino script
}
void OnTriggerEnter2D(Collider2D col) //Conditional statements to decide what to do when the player comes in range
{
if(col.gameObject.tag == "Player") //See if the trigger that collides with the cone is the Bird or not, since it's tagged with 'Player'
{
if(isLeft)
{
dinoTurretAI.Attack(false); //Player is in the left trigger, not right and isLeft defaults to false
}
else
{
dinoTurretAI.Attack(true);
}
}
}
}
Turret script:
//Script for the Dinosaur's AI, with Script attached to the Dino game object (sprite and animation spritesheet made by me). How it works: When the player enters a certain range of the Dino, it will play an animation of it popping out of the ground. And when they get even closer and reach the Dino's line of sight, it will shoot out fireballs that damage the player (while also using the AttackCone script). If they move far enough away the Dino will pop back into the ground again.
using UnityEngine;
using System.Collections;
public class DinoTurretAI : MonoBehaviour {
//Dino's variables
//Ints (For Turret health, as future-proofing incase I want it to take damage)
public int curHealth;
public int maxHealth;
//Floats (Numerical values for the distance between the Bird and Dino, when it should pop out of the ground, delay between each fireball shot, how fast each shot should go and a timer for a cooldown to not shoot too many at once.)
public float distance;
public float wakeRange;
public float shootInterval;
public float bulletSpeed = 100;
public float bulletTimer;
//Bools (Make it so the game starts with the Dino sleeping and looking away (if it's false the Dino looks left towards the player instead))
public bool awake = false;
public bool lookingRight = false;
//References (Referencing the Dino's projectile, the player, animation component of the Dino and the place it's going to shoot from (it's mouth) for both left and right (the comma is used to make more than one variable of the same type (so for this instance 'Transform'))
public GameObject bullet;
public Transform target;
public Animator anim;
public Transform shootPointLeft, shootPointRight;
void Awake() //When it's awake it gets the Animator componant attached to the Dino
{
anim = gameObject.GetComponent<Animator>();
}
void Start() //Similar to the Player script, the Dino spawns with max health
{
curHealth = maxHealth;
}
void Update()
{
anim.SetBool ("Awake", awake); //Set as an update method (so the Dino doesn't immediately pop-up), reference the awake and lookingRight boolean variables that are designed to make the Dino do just as the name implies
anim.SetBool ("LookingRight", lookingRight);
RangeCheck(); //Call the function (deployed further down) in every update, as the Dino has to constantly check to see if it has spotted the Bird
//Now it checks to see if the Bird is to the left or right of the Dino, and face that direction accordingly
if (target.transform.position.x > transform.position.x) //If the player position is bigger than the x position of the Dino (which is 0), then they're a positive number and to the right, so set lookingRight to true
{
lookingRight = true;
}
if (target.transform.position.x < transform.position.x) //If the player position is smaller than the x position of the Dino (less than 0), then they're a negative number and to the left, so set lookingRight to false. Also as a side note when the Dino flips between left and right, the animator has a small transition time to show it physically turning, rather than it instantly swapping directions
{
lookingRight = false;
}
}
void RangeCheck() //Determine how far away the Bird is from the Dino using Conditional Statements, essentially get the distance between the two objects in units. The 'target' is the player as assigned to the Dino game object
{
distance = Vector3.Distance(transform.position, target.transform.position);
if(distance < wakeRange) //If the distance (as a numerical value) to the Bird is smaller (closer) than the wakeRange value (set to 6 in the Dino's properties inside the Inspector View), then wake up the Dino
{
awake = true;
}
if(distance > wakeRange) //If the distance is bigger (further away) than the wakeRange, make the Dino continue to, or go back to, sleep
{
awake = false;
}
}
//Dino's attacking function to shoot out fireballs
public void Attack(bool attackingRight)
{
bulletTimer += Time.deltaTime; //Cooldown code, the timer increases by 1 every second. And if the timer is greater than or equals to the shoot interval, aim at the player
if (bulletTimer >= shootInterval)
{
Vector2 direction = target.transform.position - transform.position; //Direction the Dino will shoot (towards the player as they are the target), the code will return a direction
direction.Normalize();
if (!attackingRight) //Instantiation code for the left of the Dino, spawning the fireball into the game to hurt the player
{
GameObject bulletClone;
bulletClone = Instantiate(bullet, shootPointLeft.transform.position, shootPointLeft.transform.rotation) as GameObject; //Spawns the projectile to the left of the Dino (at the ShootPoint's position), and casts the fireball as a game object into the game world
bulletClone.GetComponent<Rigidbody2D>().velocity = direction * bulletSpeed; //Once the bullet clone (clone of the real object) is created, set the fireball's rigid body velocity in the direction of the player at the speed set by the variable (100)
bulletTimer = 0; //The code will loop, by counting up again and restarting the timer, and once it's reached the shoot interval, the Dino will spit out another fireball. Rinse and repeat, as the Dino shouldn't be able to shoot 100 bullets a second for example
}
if (attackingRight) //Same thing but for the right side of the Dino instead of lefr
{
GameObject bulletClone;
bulletClone = Instantiate(bullet, shootPointRight.transform.position, shootPointRight.transform.rotation) as GameObject;
bulletClone.GetComponent<Rigidbody2D>().velocity = direction * bulletSpeed;
bulletTimer = 0;
}
}
}
}