// This does ALL the settings of values on aiUtilRecs because anything I set in the Inspector // is not copied when I use GameObject.AddComponent() in ArenaManager void SetAIUtilRecs() { aiUtilRecs = new List <UtilRec>(); UtilRec ur; // Explore ur = new UtilRec(); ur.stratType = eStrat.explore; ur.enabled = true; ur.utilMinMax = new Vector2(0.0f, 0.4f); ur.curveFunc = x => x; ur.strat = new JBS_Explore(ur); aiUtilRecs.Add(ur); // Wander ur = new UtilRec(); ur.stratType = eStrat.wander; ur.enabled = true; ur.utilMinMax = new Vector2(0.3f, 0.3f); ur.curveFunc = x => x; ur.strat = new JBS_Wander(ur); aiUtilRecs.Add(ur); // I've removed the rest of these for you to figure out yourself. – JGB }
public JBStrat(UtilRec ur) { uRec = ur; }
public JBS_Wander(UtilRec ur) : base(ur) // ": base(ur)" calls the JBStrat constructor and passes in ur { }
/// <summary> /// The main method that you should override in your Agent subclass is AIUpdate(). /// </summary> /// <param name="inputs"></param> public override void AIUpdate(List <SensoryInput> inputs) { base.AIUpdate(inputs); // THE FIRST LINE OF YOUR AIUpdate() override MUST be: base.AIUpdate(inputs); // AIUpdate copies inputs into sensed if (!inited) { Init(); } // AIUpdate copies inputs into sensed SensedObject sawSomeone = null; toClosestEnemy = Vector3.one * 1000; closestEnemy = null; foreach (SensoryInput si in sensed) { switch (si.sense) { case SensoryInput.eSense.vision: if (si.type == eSensedObjectType.enemy) { sawSomeone = si.obj; // Check to see whether the Enemy is within the firing arc // The dot product of two vectors is the magnitude of A * the magnitude of B * cos(the angle between them) Vector3 toEnemy = si.pos - pos; if (toEnemy.magnitude < toClosestEnemy.magnitude) { toClosestEnemy = toEnemy; closestEnemy = si.obj as Agent; } // float dotProduct = Vector3.Dot(headTrans.forward, toEnemy.normalized); // float theta = Mathf.Acos(dotProduct) * Mathf.Rad2Deg; // if (theta <= ArenaManager.AGENT_SETTINGS.bulletAimVarianceDeg) { // if (ammo > 0) { // Fire(); // } // } } break; } // Regardless of the sense type, I want to know if it was a PickUp and what it was if (si.type == eSensedObjectType.item) { PickUp.eType puType = (si.obj as PickUp).puType; // Check the position of this item relative to the position of known item SpawnPoints if (MEM[PickUp.eType.none].Count > 0) { SpawnPoint foundSP = null; foreach (SpawnPoint sp in MEM[PickUp.eType.none]) { if ((sp.pos - si.obj.pos).magnitude < 0.1f) // We found it! { foundSP = sp; break; } } if (foundSP != null) { MEM[PickUp.eType.none].Remove(foundSP); if (!MEM.ContainsKey(puType)) { MEM.Add(puType, new List <SpawnPoint>()); } MEM[puType].Add(foundSP); } else { // No big deal, this just means that we already know about the SpawnPoint at that loc. } } } if (si.type == eSensedObjectType.enemy) { // tracker.Track(si); } } if (sawSomeone == null) { LookCenter(); // leadObj = null; } else { // Turn head to track enemies // How far is the enemy from current headTrans.forward float dotProdToClosest = Vector3.Dot(toClosestEnemy.normalized, headTrans.forward); // Account for the NaN errors that happen if Mathf.Acos(x) is called for x outside of -1 < x < 1 dotProdToClosest = Mathf.Clamp(dotProdToClosest, -1, 1); float angToClosest = Mathf.Acos(dotProdToClosest) * Mathf.Rad2Deg; // This shouldn't be needed because of the Clamp above // if (Mathf.Approximately(dotProdToClosest,1)) { // angToClosest = 0; // } else if (Mathf.Approximately(dotProdToClosest,-1)) { // angToClosest = 180; // } else { // angToClosest = Mathf.Acos( dotProdToClosest ) * Mathf.Rad2Deg; // } // // The following is here because the Acos of 1 is NaN. // if (float.IsNaN(angToClosest)) { // angToClosest = 0; // } // A dot product of toEnemy and transform.right will tell you whether to look left or right float posNeg = (Vector3.Dot(toClosestEnemy.normalized, headTrans.right) < 0) ? -1 : 1; angToClosest *= posNeg; // print("AngleToClosest: "+angToClosest); LookTheta(angToClosest); if (angToClosest <= ArenaManager.AGENT_SETTINGS.bulletAimVarianceDeg) { if (ammo > 0) { Fire(); } } } // Utility AI – Iterate through all the aiUtilRecs and find the one with the highest utility float maxUtil = -1; UtilRec uRecBest = null; foreach (UtilRec ur in aiUtilRecs) { if (ur.strat.Utility(this) > maxUtil) { uRecBest = ur; maxUtil = ur.u; } } aiU = maxUtil; aiStrat = uRecBest.stratType; if (uRecBest.dest != nmAgent.destination && health > 0) { nmAgent.SetDestination(uRecBest.dest); navMeshTargetLoc = uRecBest.dest; } // report on knowledge spawnPointKnowledge.x = MEM.ContainsKey(PickUp.eType.none) ? MEM[PickUp.eType.none].Count : 0; spawnPointKnowledge.y = MEM.ContainsKey(PickUp.eType.health) ? MEM[PickUp.eType.health].Count : 0; spawnPointKnowledge.z = MEM.ContainsKey(PickUp.eType.ammo) ? MEM[PickUp.eType.ammo].Count : 0; if (health > 0) { nmAgent.SetDestination(nmAgent.destination); } }