- Home /
The generic list blues (Argument out of range error)
Here is an AI script I have made:
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
public class DragonAI : MonoBehaviour {
//This is the AI script for the Dragon.
//Make sure to make this is tidy enough to be used as a soldier and mutants AI script.
NavMeshAgent pathFinder;
Entity entity;
GameObject model;
Vector3 startPOS;
Animator animator;
GameManager GM;
public bool isAggro = false;
public bool isFleeing = false;
public int speed = 0; // 0: Walking, 1: Running
public bool isFlying = false;
public bool isInAir = false;
public Targets targets;
public States states;
GameObject threatWinner;
void Start() {
GM = GameObject.Find ("GameManager").GetComponent<GameManager> ();
startPOS = transform.position;
pathFinder = GetComponent<NavMeshAgent>();
entity = gameObject.GetComponent<Entity> ();
model = transform.FindChild ("Model").gameObject;
animator = model.GetComponent<Animator> ();
targets.checkDelay += Random.Range (targets.checkDelay*-0.2f, targets.checkDelay*0.2f);
targets.processDelay += Random.Range (targets.processDelay*-0.2f, targets.processDelay*0.2f);
StartCoroutine ("FindNearbyEntitys");
StartCoroutine ("Process");
targets.currentCooldown = targets.idleCooldown;
pathFinder.stoppingDistance = targets.meleeStopDistance;
}
void Update() {
if ( states.trueSendDelay > 0 ) {
states.trueSendDelay -= Time.deltaTime;
}
if ( states.trueTargetDelay > 0 ) {
states.trueTargetDelay -= Time.deltaTime;
}
}
//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
//-------------------------------------------------------PROCESS--------------------------------------------------------------------------------------------------------------------------------------------------------------
//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
IEnumerator FindNearbyEntitys() {
while(true) {
Collider[] colliders = Physics.OverlapSphere (transform.position, targets.checkRadius);
// DETECT ANY NEARBY ENTITYS THROUGH SIGHT AND HEARING
// FUTURE AI SCRIPTS SHOULD HAVE THE THIS SAME DETECTION
// NO AI PROCESSING DONE HERE!
for (int i = 0; i < colliders.Length; i++) {
GameObject currentGO = colliders[i].transform.root.gameObject;
if(currentGO.GetComponent<Entity>() != null && !targets.nearbyGO.Contains (currentGO) && !targets.allyGO.Contains (currentGO) && !targets.enemyGO.Contains (currentGO) && currentGO != gameObject) {
Vector3 colliderPOS = colliders[i].transform.root.position;
Vector3 targetDir = colliderPOS - transform.position;
float dist = Vector3.Distance(colliderPOS, transform.position) - colliders[i].gameObject.transform.root.GetComponent<Entity>().loudness;
float angle = Vector3.Angle(targetDir, transform.forward);
bool canSee = false;
float seeDist = targets.visionDistance + currentGO.GetComponent<Entity>().visibility;
// VISION
if (angle <= targets.fieldOfView && Vector3.Distance(colliderPOS, transform.position) <= seeDist) {
Vector3 dir = colliderPOS - transform.position;
RaycastHit hit;
if (Physics.Raycast (transform.position, dir,out hit , seeDist)) {
if (hit.collider == colliders[i]) {
canSee = true;
}
}
}
// HEARING
if (dist <= targets.hearingAlertSensitivity && !isAggro) {
pathFinder.SetDestination(colliderPOS);
}
// CHECK IF DETECTED
if ( canSee || dist <= targets.hearingAggroSensitivity ) {
targets.nearbyGO.Add(currentGO);
}
}
}
// ORGANISE NEARBY ENTITYS INTO ENEMIES AND ALLIES
foreach(GameObject go in targets.nearbyGO) {
Entity otherEntity = go.GetComponent<Entity>();
// IF THE ENTITY IS AN ENEMY
if (entity.myFaction.enemies.Contains(otherEntity.faction) && !targets.enemyGO.Contains(go)) {
targets.enemyGO.Add (go);
SendWarning(go.transform.position);
isAggro = true;
continue;
}
// OTHERWISE, IF THE ENTITY IS AN ALLY
else if (entity.myFaction.allies.Contains(otherEntity.faction) || entity.faction == otherEntity.faction) {
if (!targets.allyGO.Contains(go)) {
targets.allyGO.Add (go);
continue;
}
}
// ELSE, SKIP. IGNORE THE ENTITY
else {
continue;
}
}
yield return new WaitForSeconds(targets.checkDelay);
}
}
// PROCESS THE AI
// ALL PROCESSING TO BE DONE HERE!
IEnumerator Process() {
// CHECK DISTANCE TO ULTIMATE PATH
while(true) {
if ( pathFinder.remainingDistance <= pathFinder.stoppingDistance ) {
pathFinder.ResetPath();
}
// IF AGGRESIVE (NEARBY ENEMIES)
if (isAggro) {
speed = 2;
float dist = 200;
// FIGURE OUT WHAT TO ATTACK
// GET LIST OF THE BIGGEST THREATS
if ( states.trueChangeTargetDelay <= 0 ) {
if ( targets.enemyGO.Count > 0 ) {
List<GameObject> sortedThreats = new List<GameObject>();
List<GameObject> unsortedThreats = new List<GameObject>();
List<GameObject> unsortedThreatsCopy = new List<GameObject>();
unsortedThreats.AddRange(targets.enemyGO);
unsortedThreatsCopy.AddRange(targets.enemyGO);
// FOR EACH THREAT IN THE UN-SORTED THREATS
foreach (GameObject threat in unsortedThreats) {
float highestThreat = -9999f;
// FOR EACH THREAT IN UN-SORTED THREATS IN UN-SORTED THREATS
foreach (GameObject threat2 in unsortedThreatsCopy) {
float tempDanger = 0f;
Entity goEntity = threat2.GetComponent<Entity>();
tempDanger = goEntity.dangerRating;
tempDanger -= goEntity.inDangerRating*0.5f;
tempDanger -= Vector3.Distance (threat2.transform.position, transform.position)*0.2f;
tempDanger *= Random.Range(-0.35f,0.35f);
if (tempDanger > highestThreat) {
threatWinner = threat2;
highestThreat = tempDanger;
}
}
sortedThreats.Add (threatWinner);
unsortedThreatsCopy.Remove (threatWinner);
}
unsortedThreats.Clear ();
unsortedThreatsCopy.Clear();
// ATTACK THE BIGGEST THREAT
if ( targets.currentTarget != null ) {
targets.currentTarget.GetComponent<Entity>().StopGettingTargetedBy(gameObject);
}
targets.currentTarget = sortedThreats[0];
pathFinder.SetDestination(targets.currentTarget.transform.position);
sortedThreats.Clear ();
states.trueChangeTargetDelay = states.changeTargetDelay;
}
}
else {
states.trueChangeTargetDelay -= targets.processDelay;
}
// IF I HAVE A TARGET
if (targets.currentTarget != null) {
pathFinder.SetDestination(targets.currentTarget.transform.position);
targets.currentTarget.GetComponent<Entity>().GetTargetedBy(gameObject);
}
}
// IF NOT AGGRESIVE (IDLE)
else if (!isAggro) {
speed = 1;
if ( !pathFinder.hasPath ) {
if( targets.currentCooldown <= 0 ) {
float radius = targets.idleRadius;
pathFinder.SetDestination (new Vector3(startPOS.x+Random.Range(radius*-1,radius), startPOS.y+Random.Range(radius*-1,radius), startPOS.z+Random.Range(radius*-1,radius)));
targets.currentCooldown = targets.idleCooldown;
}
else {
targets.currentCooldown -= targets.processDelay;
}
}
}
ProcessAnimator();
yield return new WaitForSeconds(targets.processDelay);
}
}
// PROCESS THE ANIMATIONS
// MAKE SURE TO FINISH THIS!
void ProcessAnimator() {
if( speed == 1 ) {
pathFinder.speed = states.walkSpeed;
}
else if ( speed == 2 ) {
pathFinder.speed = states.sprintSpeed;
}
if (pathFinder.velocity != Vector3.zero ) {
animator.SetInteger("Speed", speed);
}
else {
animator.SetInteger("Speed", 0);
}
}
//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
//-------------------------------------------------------CLASSES--------------------------------------------------------------------------------------------------------------------------------------------------------------
//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
[System.Serializable]
public class Targets {
// DETECTION RADIUS
public float checkRadius = 1000f;
public float hearingAggroSensitivity = 500f;
public float hearingAlertSensitivity = 500f;
// VISION
public float visionDistance = 200f;
public float fieldOfView = 30f;
// DELAY
public float checkDelay = 2f;
public float processDelay = 1f;
public float idleCooldown = 2f;
public float currentCooldown = 2f;
// MOVEMENT VARIABLES
public float idleRadius = 50f;
public float meleeStopDistance = 5f;
public float airStopDistance = 20f;
// TARGETS
public List<GameObject> nearbyGO = new List<GameObject>();
public List<GameObject> enemyGO = new List<GameObject>();
public List<GameObject> allyGO = new List<GameObject>();
public GameObject currentTarget;
}
[System.Serializable]
public class States {
// SPEED
public float sprintSpeed = 20f;
public float walkSpeed = 5f;
public float flySpeed = 30f;
// DELAY
public float sendDelay = 1f;
public float trueSendDelay = 0f;
public float targetDelay = 1f;
public float trueTargetDelay = 0f;
public float changeTargetDelay = 5f;
public float trueChangeTargetDelay = 0f;
}
//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
//-------------------------------------------------------COMMUNICATION--------------------------------------------------------------------------------------------------------------------------------------------------------
//<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>
// TAKE DAMAGE, SENT FROM ENTITY SCRIPT
public void GetDamaged(GameObject dealer) {
if ( !targets.enemyGO.Contains(dealer) ) {
targets.enemyGO.Add (dealer);
}
SendWarning (dealer.transform.position);
}
// RECEIVE WARNING, CONTAINS LOCATION OF POSSIBLE THREAT OR ALLY
public void ReceiveWarning(Vector3 pos) {
pathFinder.SetDestination(pos);
}
// RECEIVE ENTITY INFORMATION FROM ALLY
public void ReceiveEntity(GameObject go, bool isEnemy) {
if ( !targets.nearbyGO.Contains(go) ) {
if (isEnemy) {
targets.enemyGO.Add(go);
}
else {
targets.allyGO.Add(go);
}
}
}
// SEND WARNING TO NEARBY ALLIES, CONTAINS THREAT POSITION
void SendWarning(Vector3 pos) {
if ( states.trueSendDelay <= 0 ) {
foreach(GameObject ally in targets.allyGO) {
if (ally.GetComponent<DragonAI>() != null) {
ally.GetComponent<DragonAI>().ReceiveWarning(pos);
}
}
states.trueSendDelay = states.sendDelay;
}
}
// SEND INFROMATION ABOUT NEARBY ENTITY TO ALL ALLIES
void SendEntity(GameObject go, bool isEnemy) {
if ( states.trueSendDelay <= 0 ) {
foreach(GameObject ally in targets.allyGO) {
if (ally.GetComponent<DragonAI>() != null) {
ally.GetComponent<DragonAI>().SendEntity(go, isEnemy);
}
}
states.trueSendDelay = states.sendDelay;
}
}
}
*Bug fixed, code above replaced with working version!
Answer by NoseKills · Jan 10, 2015 at 05:59 PM
Hoh. I was looking at those loops for a looong time before i noticed the inner loop has a wrong exit condition.
for (int i = 0; i < unsortedThreats.Count; i++) {
float highestThreat = -9999f;
GameObject threatWinner = new GameObject();
for (int ii = 0; i < unsortedThreats.Count; ii++) {
i guess the inner loop should be
ii < unsortedThreats.Count
with a double "i"
Wow, thanks so much! I did just switch over too foreach statements though, but I cant believe I spent two days trying to fix that tiny error, and I even re-wrote it twice! Thanks so much though. I will replace my code above with the working version so that people can use it.
Your answer
Follow this Question
Related Questions
Argument out of Range Exception Error - Parameter Name: Index 1 Answer
List Emptying Itself? 1 Answer
A node in a childnode? 1 Answer
Have falling object exit from a collider after collision? 2 Answers
A* pathfinding for 2D top Down 0 Answers