- Home /
Assigning Waypoints to an instantiated enemy
Hi,
I have a 'Boss' that instantiates itself when all enemies are defeated. Here is the JS (attached to each enemy):
public static var enemyCount : int = 3;
function OnCollisionEnter( collision : Collision )
{
if(collision.gameObject.tag == "fireball")
{
animation.Play("dying");
audio.Play();
yield WaitForSeconds(0.2);
GameObject.Destroy ( gameObject ) ;
enemyCount -= 1;
}
if(enemyCount <= 0) {
var instance : GameObject = Instantiate(Resources.Load("boss"));
}
}
I also have a C# script that deals with enemies patrolling Waypoints and chasing the player if they wander within a certain distance from the player. This script is also attached to the enemies, as well as the boss himself. However, I cannot assign Waypoints to the boss like I can to the other enemies. From researching I've read you cannot do this to instantiated objects.
Is there any way around this? Your help would be much appreciated. Many thanks!
EDIT: C# script for Waypoint finding and player chasing/attacking:
using UnityEngine;
using System.Collections;
public class EnemyMovementController : MonoBehaviour
{
// speed of the AI player
public int speed = 4;
// speed the ai player rotates by
public int rotationSpeed = 5;
// the waypoints
public Transform[] waypoints;
// current waypoint id
private int waypointId = 0;
// the character controller component
private CharacterController characterController;
private Transform player;
public int chasingDistance = 30;
private bool attacking = false;
/**
Init
*/
void Start()
{
// retrieve this GameObjects CharacterController Component and store in characterController (todo)
characterController = gameObject.GetComponent<CharacterController>();
player = Motor.Instance.transform;
}
/**
Patrol around the waypoints
*/
void Patrol()
{
// if no waypoints have been assigned
if (waypoints.Length == 0)
{
//Debug.LogError("You need to assign some waypoints within the Inspector!");
return;
}
// if distance to waypoint is less than 2 metres then start heading toward next waypoint
if (Vector3.Distance(waypoints[waypointId].position, transform.position) < 2)
{
// increase waypoint id
waypointId++;
// make sure new waypointId isn't greater than number of waypoints
// if it is then set waypointId to 0 to head towards first waypoint again
if (waypointId >= waypoints.Length) waypointId = 0;
}
// move towards the current waypointId's position
MoveTowards(waypoints[waypointId].position);
attacking = false;
}
/**
Update - Every Frame
*/
void Update()
{
PatrolAndChase ();
}
/**
Move towards the targetPosition
*/
void MoveTowards(Vector3 targetPosition)
{
// calculate the direction to waypoint
Vector3 direction = targetPosition - transform.position;
// rotate over time to face the target rotation - Quaternion.LookRotation(direction)
transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
// set the x and z axis of rotation to 0 so the agent stands upright (otherwise equals REALLY bad leaning)
transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, 0);
// use the CharacterController Component's SimpleMove(...) function
// multiply the agent's forward vector by the speed to move the AI
characterController.SimpleMove(transform.forward * speed);
// crossfade the walking animation (todo)
animation.CrossFade("walking",0.2F);
}
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 player is within 30m and angle is greater than 130 then begin chasing the player
if (distanceToPlayer < chasingDistance && angle > 130) {
// move towards the players position
//MoveTowards (player.transform.position);
// attack the player ONLY if not already attacking
if (!attacking && distanceToPlayer < 4) {
StartCoroutine (Attack ());
} else if (!attacking) {
// player is "out of sight"
MoveTowards (player.transform.position);
}
} else {
// patrol
Patrol ();
// if attacking, then toggle to stop
}
}
/**
Fire at the player
*/
IEnumerator Attack()
{
// toggle attacking on
attacking = true;
// crossfade the attacking animation
animation.CrossFade("jump", 0.2F);
// odds of player being attacked successfully
float odds = Random.Range(0.0f, 1.0f);
// was the player attacked?
if (odds >= 0.0f)
{
// player has been attacked
HealthController.Instance.HasBeenAttacked();
}
// create delay before attacking again (else would be constant every frame = dead player)
yield return new WaitForSeconds(1);
// allow attacking again
attacking = false;
}
}
Answer by Vandarthul · Apr 28, 2014 at 03:46 AM
Okay you have two options.
I'll write and advice before writing options. Instead of controlling enemy count on every enemy object, create an EnemyController.cs script and add an empty gameobject called Enemy_Manager. This script should contain the information of how many enemies left on your game. The following script considers all of your enemies has "Enemy" tag.
**Enemy Controller Class**[c#]
public int enemyCount;
GameObject enemies[];
void Start()
{
enemies = GameObject.FindGameObjectsWithTag("Enemy");
enemyCount = enemies.Length;
}
public void ModifyEnemyCount()
{
enemyCount --;
if (enemyCount == 0)
{
//DoSomething.
}
}
After then if your enemies die, they should decrease this value. So you should modify your EnemyDead.js script as:
function OnCollisionEnter( collision : Collision )
{
if(collision.gameObject.tag == "fireball")
{
animation.Play("dying");
audio.Play();
yield WaitForSeconds(0.2);
GameObject.Destroy ( gameObject ) ;
var enemyCont : EnemyController = GameObject.Find("Enemy_Manager").GetComponent<EnemyController>();
enemyCont.ModifyEnemyCount();
}
This way you now have a centralised enemy control system that you can do other things too. Now to your problem' solution.
First Option:
Add your boss before you start the game, add the waypoints and disable his GameObject. When all the enemies are defeated, enable his GameObject. So basically what you want to do is on your ModifyEnemyCount method, you want to enable your boss's gameobject. So;
public void ModifyEnemyCount()
{
enemyCount --;
if (enemyCount == 0)
{
GameObject boss = GameObject.Find("boss");
boss.enabled = true;
}
}
Second Option:
You need a waypoint manager just like enemy manager we did back there. So add an empty gameobject called Waypoint_Manager and attach a script called WaypointController.
**Waypoint Controller Class**[c#]
public Transform[] waypoints;
Attach your waypoints to this object and do the following within the EnemyMovementController.cs script:
public class EnemyMovementController : MonoBehaviour
{
// speed of the AI player
public int speed = 4;
// speed the ai player rotates by
public int rotationSpeed = 5;
// the waypoints
Transform[] waypoints; // NO NEED FOR THIS TO BE PUBLIC ANYMORE
// current waypoint id
private int waypointId = 0;
// the character controller component
private CharacterController characterController;
private Transform player;
public int chasingDistance = 30;
private bool attacking = false;
WaypointController waypointScript; //TO REFERENCE OUR NEW SCRIPT
/**
Init
*/
void Start()
{
// retrieve this GameObjects CharacterController Component and store in characterController (todo)
characterController = gameObject.GetComponent<CharacterController>();
player = Motor.Instance.transform;
waypointScript = GameObject.Find("Waypoint_Manager").GetComponent<WaypointController>(); // get the WaypointController script on Waypoint_Manager gameobject within our waypointScript variable.
waypoints = waypointScript.waypoints; // assign our centralised waypoints from WaypointController to enemies' waypoints.
}
Note that I didn't test the scripts, just wrote them here, there might be some errors but you should be able to fix them if happens. If not, please ask again. I hope this helps.
Hi @Vandarthul. As mentioned, I have a C# script that deals with enemy waypoints. I then make these waypoints on my scene and drag them into the Waypoint fields under the script in the Inspector. I have edited the post to include this script.
The script I show first is the EnemyDead.js script, which is attached to every enemy. It deals with their deaths and checks whether all enemies have been defeated to instantiate the boss.
The lengthy C# script is the Enemy$$anonymous$$ovementController.cs script that is also attached to every enemy. This deals with waypoint finding and player chasing/attacking.
Lastly, I have a boss script (BossScript.cs) that is solely attached to the boss, which is only concerned with health and going to the next level.
I hope this clear's out my project's structure! Thanks for your time!
@Vandarthul I still can't get this to work. Has what I've added given you any other thoughts?
Thanks so much for your time, I will have a go at implementing this and will be sure to tick if it provides the solution I'm looking for.
If it's easier, do you think you could provide a solution to this question (using SetActive() ins$$anonymous$$d of Instantiating the boss)? I think it would be a more flexible approach to take, but I will definitely still try your method.
Once again, your support is thoroughly appreciated. Thank you!
Answer by Cherno · Apr 28, 2014 at 01:15 PM
Store all your instantiated enemies in a list, and remove them if they are destroyed. If they are in the list, they can be accessed either by their index number in the list or by using List.Contains() and comparing the enemy you want to access to the list's contents.
Your answer
Follow this Question
Related Questions
Car- can someone help me convert this to C#? 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
The problem of Enemy scale when he follow the player (script) . How to fix? 0 Answers
Health drop, and picking it up. 1 Answer