Topic 11: Behaviour via Coroutines via Iterators - Undergraduate
Topic 11: Behaviour via Coroutines via Iterators - Undergraduate
Topic 11: Behaviour via Coroutines via Iterators - Undergraduate
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
CITS4242:Game Design and MultimediaFaculty of Engineering,Computing and MathematicsSCHOOL OF COMPUTER SCIENCE & SOFTWARE ENGINEERING<strong>Topic</strong> <strong>11</strong>:<strong>Behaviour</strong> <strong>via</strong> <strong>Coroutines</strong><strong>via</strong> <strong>Iterators</strong>
Implementing <strong>Behaviour</strong>// Continued from previous slideFaculty of Engineering,Computing and MathematicsSCHOOL OF COMPUTER SCIENCE & SOFTWARE ENGINEERINGprotected override void OnTick(){base.OnTick();updateTaskTimer -= TickDelta;if (updateTaskTimer
DefenderAI – FlockWithRevenge/// Flock, but take revenge on characters who collide with our character. protected IEnumerable FlockWithRevenge(){while (true){if (collidedWith != null && collidedWith != Target &&collidedWith.Type.InitialAI.Name == "ChaserAI"){foreach (var move in GetRevenge(collidedWith)) yield return move;collidedWith = null;}else{submesh.MaterialName = "RobotGreen";yield return Flock();}}}Target = origTarget;protected Vec2 Flock(){return steer.Wander(2, 4, 2) * WanderMult + steer.Arrive(Target.Position, 2) * ArriveMult +steer.Alignment(neighbours) * AlignMult + steer.Cohesion(neighbours) * CohesMult +steer.Separation(neighbours) * SepMult;}
DefenderAI.cs - GetRevengeIEnumerable GetRevenge(Character avengee){var oldTarget = Target;Target = avengee;submesh.MaterialName = "RobotBlue";for (int i = 0; i < 3f / timeInterval; i++) yield return Vec2.Zero; // Wait before starting revenge.while (true){submesh.MaterialName = "RobotWhite";foreach (var b in HitWith("Ball", avengee)) yield return b; // Do HitWith until it finishes.if (!failed) break;failed = false;submesh.MaterialName = "RobotPurple";foreach (var b in HitWith("Cart", avengee)) yield return b; // Do HitWith until it finishes.if (!failed) break;failed = false;}submesh.MaterialName = "RobotExtraRed";foreach (var b in ChaseHit(avengee)) yield return b; // Do ChaseHit until it finishes.if (!failed) break;failed = false;}String mat = submesh.MaterialName;for (int i = 0; i < 4f / timeInterval; i++) // Wait, flash colour{submesh.MaterialName = (i/10) % 2 == 0 ? "RobotCyan" : mat;yield return Vec2.Zero;}Target = oldTarget;yield break;
DefenderAI.cs – ChaseHit & GetDynamic/// Chase a target until a collision with it occurs./// IEnumerable ChaseHit(Character newTarget){chasing = true;collidedWith = null;int ticks = 0;float moveMult = 10f;while (collidedWith != Target){maxMoveForce = (ticks++ * timeInterval / 6f + 1f) * PlayerCharacter.Difficulty;GetNeighbours(Controlled.Type.Name);yield return steer.Pursuit(Target) * moveMult;}maxMoveForce = 1f;// +sb.Avoid(neighbours) * SepMult;chasing = false;collidedWith = null;}yield break;// caught target, chasing is finished, return no moves.Dynamic GetDynamicOfType(String dynTypeName){Dynamic ret=null;Map.Instance.GetObjects(new Sphere(Controlled.Position, Controlled.ViewRadius * 3f), mapObj =>{var dyn = mapObj as Dynamic;if (dyn != null && dyn.Type.Name == dynTypeName)ret = mapObj as Dynamic;});return ret;}
DefenderAI - HitWith/// Find a particular type of dynamic entity and hit it towards a target. IEnumerable HitWith(String useDynTypeName, Character aimAt){Dynamic useDyn=GetDynamicOfType(useDynTypeName);if (useDyn == null) { failed = true; yield break; }float duration = 0f;while ((duration += timeInterval) < 10f) // Move to about 3m behind Dyn{var DynPos = useDyn.Position.ToVec2();var runTo = DynPos + 3f * (DynPos - aimAt.Position.ToVec2()).GetNormalizeFast();if ((runTo - Controlled.Position.ToVec2()).LengthSqr() < 1f) break;yield return steer.Arrive(new Vec3(runTo.X, runTo.Y, useDyn.Position.Z), 1f);}if (duration > 10f) { failed = true; yield break; } // Failed to get in correct position.bool hit = false;Body.CollisionDelegate cd = (ref CollisionEvent ce) =>{if (ce.OtherShape.Body.UserData != null){var ent = ce.OtherShape.Body.UserData as Entity;if (ent != null & ent.Type == Target.Type) hit = true;}};foreach(var body in useDyn.PhysicsModel.Bodies) body.Collision += cd;}}while (!hit && (duration += timeInterval) < 30 * 15){if(useDyn.Position.Z < Controlled.MainBody.GetGlobalBounds().Maximum.Z) maxMoveForce = 5f;yield return steer.Pursuit(useDyn) * maxMoveForce; // Hit with a lot of extra force.maxMoveForce = 1f;}foreach (var body in useDyn.PhysicsModel.Bodies) body.Collision -= cd;if (!hit) { failed = true; yield break; }
DefenderAI - Points of interestFaculty of Engineering,Computing and MathematicsSCHOOL OF COMPUTER SCIENCE & SOFTWARE ENGINEERINGNote the following ways that behaviours are combined in DefenderAI:- The avoid and the FlockWithRevenge behaviours are run at the sametime (in parallel), with avoid taking priority.- FlockWithRevenge normally does the Flock behaviour, but it swaps tothe GetRevenge behaviour when hit by a “Chaser”, and continues untilGetRevenge completes.- GetRevenge tries three different ways of getting revenge in order, andcontinues until one of them succeeds.– So, we have sequencing, looping and goal directed behaviour.- HitWith attempts to locate the object, then gets on the opposite side ofit from the target, and hits it. It fails if it can't get to the right positionwithin 10sec.