/// <summary> /// It will process the A.I. which has been registered to the list. /// When the current A.I. is updated and then, when ActiveTime, /// which is specified in the current A.I., /// becomes zero, it will be replaced with the next-to-be-executed A.I. /// </summary> protected override void OnUpdate(GameTime gameTime) { if ((ActiveAI == null && NextAI == null) || !activeOn) return; // Change to next AI if (ActiveAI == null) { PlayAI(NextAI, NextAI.ActiveTime); } else if (NextAI != null && ActiveAI.ActiveTime == 0.0f) { PlayAI(NextAI, NextAI.ActiveTime); nextAI = null; } else { // Process to current AI if (ActiveAI != null) { ActiveAI.Update(gameTime); if (ActiveAI.ActiveTime > 0.0f) ActiveAI.ActiveTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; if( ActiveAI.ActiveTime < 0.0f) ActiveAI.ActiveTime = 0.0f; } } }
/// <summary> /// by using the index of the registered A.I., /// it specifies the next-to-be-executed A.I. /// The active time of the next-to-be-executed A.I. is specified by activeTime. /// </summary> public void SetNextAI(int index, float activeTime) { if (!activeOn) { return; } nextAI = FindAI(index); nextAI.ActiveTime = activeTime; }
/// <summary> /// The specified A.I. will be played. /// The active time of the A.I. is specified by activeTime. /// The A.I., which has been active so far, will call the /// Finish event handler and will be replaced by the newly specified A.I. /// When the newly specified A.I. start activating, /// Start event handler is called. /// </summary> private void PlayAI(int index, float activeTime) { if (!activeOn) { return; } AIBase aiBase = FindAI(index); PlayAI(aiBase, activeTime); }
/// <summary> /// A new A.I. will be played. /// The active time of the A.I. is specified by activeTime. /// The A.I., which has been active so far, will be ignored. /// </summary> public void StartAI(int index, float activeTime) { if (!activeOn) { return; } activeAI = null; nextAI = null; PlayAI(index, activeTime); }
/// <summary> /// it adds an A.I. with the specified name to the list. /// </summary> public int AddAI(string name, AIBase aiBase) { if (!activeOn) { return(-1); } aiBase.Name = name; aiList.Add(aiBase); return(aiList.IndexOf(aiBase)); }
/// <summary> /// The specified A.I. will be played. /// The active time of the A.I. is specified by activeTime. /// The A.I., which has been active so far, will call the /// Finish event handler and will be replaced by the newly specified A.I. /// When the newly specified A.I. start activating, /// Start event handler is called. /// </summary> private void PlayAI(AIBase aiBase, float activeTime) { if (!activeOn) { return; } // Call the finish event of the previous A.I. if (activeAI != null) { activeAI.AIFinish(); } // Set to new active A.I. activeAI = aiBase; activeAI.ActiveTime = activeTime; // Call start event of new A.I. activeAI.AIStart(); }
/// <summary> /// It will process the A.I. which has been registered to the list. /// When the current A.I. is updated and then, when ActiveTime, /// which is specified in the current A.I., /// becomes zero, it will be replaced with the next-to-be-executed A.I. /// </summary> protected override void OnUpdate(GameTime gameTime) { if ((ActiveAI == null && NextAI == null) || !activeOn) { return; } // Change to next AI if (ActiveAI == null) { PlayAI(NextAI, NextAI.ActiveTime); } else if (NextAI != null && ActiveAI.ActiveTime == 0.0f) { PlayAI(NextAI, NextAI.ActiveTime); nextAI = null; } else { // Process to current AI if (ActiveAI != null) { ActiveAI.Update(gameTime); if (ActiveAI.ActiveTime > 0.0f) { ActiveAI.ActiveTime -= (float)gameTime.ElapsedGameTime.TotalSeconds; } if (ActiveAI.ActiveTime < 0.0f) { ActiveAI.ActiveTime = 0.0f; } } } }
public virtual void OnAISearchEvent(AIBase aiBase) {}
/// <summary> /// it adds an A.I. with the specified name to the list. /// </summary> public int AddAI(string name, AIBase aiBase) { if (!activeOn) return -1; aiBase.Name = name; aiList.Add(aiBase); return aiList.IndexOf(aiBase); }
public virtual void OnAIAttackEvent(AIBase aiBase, GameTime gameTime) { }
public virtual void OnAIMoveEvent(AIBase aiBase, GameTime gameTime) { }
public virtual void OnAITurnRightEvent(AIBase aiBase) { }
public virtual void OnAITurnLeftEvent(AIBase aiBase) {}
/// <summary> /// boss's A.I. function. /// turns the body left. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAITurnLeftEvent(AIBase aiBase) { MoveStop(); if (aiBase.IsActive) { float fTurnAngleSpeed = SpecData.TurnAngle; // Turning left Rotate(new Vector2(fTurnAngleSpeed, 0.0f)); ActionTurn(fTurnAngleSpeed); } else { if (isMoveBlocked) { CollideSphere collideSphere = Collide as CollideSphere; float movingTime = (float)HelperMath.Randomi(2) + HelperMath.RandomNormal(); Vector3 simulateAmount = movingTime * new Vector3(0.0f, 0.0f, SpecData.MoveSpeed); simulateAmount = CalculateVelocity(simulateAmount); Vector3 start = WorldTransform.Translation + (WorldTransform.Up * 1.0f); // Test collision CollisionResult result = HitTestWithWorld(start, Direction); // Is moving way clear? if (result != null) { float moveDistance = (SpecData.MoveSpeed * movingTime); float resultDistance = result.distance - collideSphere.Radius; if (resultDistance > 0.0f) { if (resultDistance < moveDistance) { // Recalculate moving time for move and stop movingTime *= resultDistance / moveDistance; isMoveBlocked = true; } else { isMoveBlocked = false; } } // Can't move else { isMoveBlocked = true; } } else { isMoveBlocked = false; } if (isMoveBlocked) { // turn right SetNextAI(AIType.TurnRight, 90.0f / SpecData.TurnAngle); } else { SetNextAI(AIType.Move, movingTime); } } else SetNextAI(AIType.Search, 0.2f); } }
/// <summary> /// creates and initializes all base A.I. /// </summary> public override void Initialize() { base.Initialize(); // Entry patrol update function in AI AIBase aiSearch = new AIBase(); aiSearch.Updating += new EventHandler<AIBase.AIUpdateEventArgs>(OnSearchUpdateEvent); indexAiSearch = AIContext.AddAI("Search", aiSearch); // Entry move update function in AI AIBase aiMove = new AIBase(); aiMove.Updating += new EventHandler<AIBase.AIUpdateEventArgs>(OnMoveUpdateEvent); indexAiMove = AIContext.AddAI("Move", aiMove); // Entry attack update function in AI AIBase aiAttack = new AIBase(); aiAttack.Updating += new EventHandler<AIBase.AIUpdateEventArgs>(OnAttackUpdateEvent); indexAiAttack = AIContext.AddAI("Attack", aiAttack); // Entry left turn update function in AI AIBase aiTurnLeft = new AIBase(); aiTurnLeft.Updating += new EventHandler<AIBase.AIUpdateEventArgs>(OnTurnLeftUpdateEvent); indexAiTurnLeft = AIContext.AddAI("TurnLeft", aiTurnLeft); // Entry right turn update function in AI AIBase aiTurnRight = new AIBase(); aiTurnRight.Updating += new EventHandler<AIBase.AIUpdateEventArgs>(OnTurnRightUpdateEvent); indexAiTurnRight = AIContext.AddAI("TurnRight", aiTurnRight); WorldTransform = SpawnPoint; // Remove a collision if (colLayerEnemyMech != null) { if (colLayerEnemyMech.IsContain(Collide)) colLayerEnemyMech.RemoveCollide(Collide); } // Remove a collision if (colLayerAllMech != null) { if (colLayerAllMech.IsContain(Collide)) colLayerAllMech.RemoveCollide(Collide); } }
/// <summary> /// tank's A.I. function. /// moves to the position and stops when collides with others. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAIMoveEvent(AIBase aiBase, GameTime gameTime) { if (aiBase.IsActive) { Vector3 vMoveVelocity = new Vector3(0.0f, 0.0f, SpecData.MoveSpeed); CollisionResult result = MoveHitTest(gameTime, vMoveVelocity); if (result != null) { if (GameSound.IsPlaying(soundMove)) GameSound.Stop(soundMove); MoveStop(); // Cannot move } else { Move(vMoveVelocity); if (!GameSound.IsPlaying(soundMove)) soundMove = GameSound.Play3D(SoundTrack.TankMove, this); } } else { if (GameSound.IsPlaying(soundMove)) GameSound.Stop(soundMove); MoveStop(); turretAngleSpeed = 0.0f; SetNextAI(AIType.Search, HelperMath.RandomNormal()); } }
/// <summary> /// boss's A.I. function. /// attacks when the attack objective is within the shooting range. /// Otherwise, it searches for an attack object again. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAIAttackEvent(AIBase aiBase, GameTime gameTime) { bool fired = false; MoveStop(); // The enmey weapon reloading if (CurrentWeapon.CurrentAmmo == 0 && !IsFiring && !IsReloading) { ActionReload(CurrentWeapon); } else if (CurrentWeapon.IsPossibleToFire()) { // Attack action if (currentAction == Action.Melee) { // Waiting for ready to first fire if (this.actionElapsedTime >= CurrentWeapon.SpecData.FireDelayTimeTillFirst) { this.actionElapsedTime = 0.0f; WeaponFire(); fired = true; } else { this.actionElapsedTime += (float)gameTime.ElapsedGameTime.TotalSeconds; } } else { ActionMelee(); CurrentWeapon.StopFireSound(); } } if (!aiBase.IsActive && fired) { SetNextAI(AIType.Search, 0.2f); } }
/// <summary> /// tank's A.I. function. /// checks whether an attack objective is within shooting range. /// if it is within shooting range, attacks. Otherwise, moves. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAISearchEvent(AIBase aiBase) { if (!aiBase.IsActive) { // Searching Player inside fire range float distanceBetweenPlayer = Vector3.Distance(RobotGameGame.SinglePlayer.Position, Position); Vector3 targetDirection = Vector3.Normalize(RobotGameGame.SinglePlayer.Position - Position); Vector3 turretDirection = BoneTransforms[indexTurretBone].Forward; float dot = Vector3.Dot(turretDirection, targetDirection); float angleDiff = MathHelper.ToDegrees(dot); if (Math.Abs(angleDiff) < 3.0f) { // Firing inside fire range if (distanceBetweenPlayer <= CurrentWeapon.SpecData.FireRange) { SetNextAI(AIType.Attack, 1.0f); } else { SetNextAI(AIType.Search, 1.0f); } } else { // Turning right if (angleDiff > 3.0f) { SetNextAI(AIType.TurnRight, Math.Abs(angleDiff) / SpecData.TurnAngle); } // Turning left else if (angleDiff < -3.0f) { SetNextAI(AIType.TurnLeft, Math.Abs(angleDiff) / SpecData.TurnAngle); } else { throw new InvalidOperationException("Invalid processing"); } } turretAngleSpeed = 0.0f; } MoveStop(); }
/// <summary> /// call attack A.I. /// </summary> internal void OnAttackUpdateEvent(object sender, AIBase.AIUpdateEventArgs e) { OnAIAttackEvent(sender as AIBase, e.GameTime); }
/// <summary> /// call turn left A.I. /// </summary> internal void OnTurnLeftUpdateEvent(object sender, AIBase.AIUpdateEventArgs e) { OnAITurnLeftEvent(sender as AIBase); }
/// <summary> /// call movement A.I. /// </summary> internal void OnMoveUpdateEvent(object sender, AIBase.AIUpdateEventArgs e) { OnAIMoveEvent(sender as AIBase, e.GameTime); }
/// <summary> /// call search A.I. /// </summary> internal void OnSearchUpdateEvent(object sender, AIBase.AIUpdateEventArgs e) { OnAISearchEvent(sender as AIBase); }
/// <summary> /// tank's A.I. function. /// turns the body left. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAITurnLeftEvent(AIBase aiBase) { if (aiBase.IsActive) { turretAngleSpeed = SpecData.TurnAngle; } else { SetNextAI(AIType.Search, HelperMath.RandomNormal()); } }
/// <summary> /// by using the index of the registered A.I., /// it specifies the next-to-be-executed A.I. /// The active time of the next-to-be-executed A.I. is specified by activeTime. /// </summary> public void SetNextAI(int index, float activeTime) { if (!activeOn) return; nextAI = FindAI(index); nextAI.ActiveTime = activeTime; }
/// <summary> /// tank's A.I. function. /// attacks when the attack objective is within the shooting range. /// Otherwise, it searches for an attack object again. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAIAttackEvent(AIBase aiBase, GameTime gameTime) { MoveStop(); // The enmey weapon reloading if (CurrentWeapon.CurrentAmmo == 0 && !IsFiring && !IsReloading) { ActionReload(CurrentWeapon); } else if (CurrentWeapon.IsPossibleToFire()) { // If weapon fired, just action fire ActionFire(); WeaponFire(); } turretAngleSpeed = 0.0f; SetNextAI(AIType.Search, HelperMath.RandomNormal()); }
/// <summary> /// A new A.I. will be played. /// The active time of the A.I. is specified by activeTime. /// The A.I., which has been active so far, will be ignored. /// </summary> public void StartAI(int index, float activeTime) { if (!activeOn) return; activeAI = null; nextAI = null; PlayAI(index, activeTime); }
/// <summary> /// boss's A.I. function. /// checks whether there’s an enemy within shooting range. /// If there’s an enemy within the shooting range, it will fire, otherwise, /// it moves. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAISearchEvent(AIBase aiBase) { if (!aiBase.IsActive) { CollideSphere collideSphere = Collide as CollideSphere; // Searching Player inside fire range float distanceBetweenPlayer = Vector3.Distance(RobotGameGame.SinglePlayer.Position, Position); Vector3 vTargetDirection = Vector3.Normalize(RobotGameGame.SinglePlayer.Position - Position); float dotRight = Vector3.Dot(Right, vTargetDirection); float dotDirection = Vector3.Dot(Direction, vTargetDirection); float angle = MathHelper.ToDegrees(dotRight); // Forward area if (dotDirection > 0.0f) { // Turning right if (angle > 5.0f) { SetNextAI(AIType.TurnRight, Math.Abs(angle) / SpecData.TurnAngle); } // Turning left else if (angle < -5.0f) { SetNextAI(AIType.TurnLeft, Math.Abs(angle) / SpecData.TurnAngle); } else { // Firing inside fire range if (distanceBetweenPlayer <= CurrentWeapon.SpecData.FireRange) { SetNextAI(AIType.Attack, 1.0f); } // Trace to player else { float movingTime = (float)HelperMath.Randomi(2) + HelperMath.RandomNormal(); Vector3 simulateAmount = movingTime * new Vector3(0.0f, 0.0f, SpecData.MoveSpeed); simulateAmount = CalculateVelocity(simulateAmount); Vector3 start = WorldTransform.Translation + (WorldTransform.Up * 1.0f); // Test collision CollisionResult result = HitTestWithWorld(start, Direction); // clear moving way ? if (result != null) { float moveDistance = (SpecData.MoveSpeed * movingTime); float resultDistance = result.distance - collideSphere.Radius; if (resultDistance > 0.0f) { if (resultDistance < moveDistance) { // Recalculate moving time for move and stop movingTime = resultDistance / moveDistance; isMoveBlocked = true; } else { isMoveBlocked = false; } } // Can't move else { isMoveBlocked = true; } } else { isMoveBlocked = false; } if (isMoveBlocked) { // turn if (dotRight > 1.0f) { SetNextAI(AIType.TurnRight, 90.0f / SpecData.TurnAngle); } else { SetNextAI(AIType.TurnLeft, 90.0f / SpecData.TurnAngle); } } else { SetNextAI(AIType.Move, movingTime); } } } } // Behind area else { // turn if (dotRight > 1.0f) SetNextAI(AIType.TurnRight, 90.0f / SpecData.TurnAngle); else SetNextAI(AIType.TurnLeft, 90.0f / SpecData.TurnAngle); } if (this.CurrentAction != Action.Idle) ActionIdle(); MoveStop(); } }
/// <summary> /// The specified A.I. will be played. /// The active time of the A.I. is specified by activeTime. /// The A.I., which has been active so far, will call the /// Finish event handler and will be replaced by the newly specified A.I. /// When the newly specified A.I. start activating, /// Start event handler is called. /// </summary> private void PlayAI(AIBase aiBase, float activeTime) { if (!activeOn) return; // Call the finish event of the previous A.I. if (activeAI != null) activeAI.AIFinish(); // Set to new active A.I. activeAI = aiBase; activeAI.ActiveTime = activeTime; // Call start event of new A.I. activeAI.AIStart(); }
/// <summary> /// boss's A.I. function. /// moves to the position and stops when collides with others. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAIMoveEvent(AIBase aiBase, GameTime gameTime) { if (aiBase.IsActive) { Vector3 moveVelocity = new Vector3(0.0f, 0.0f, SpecData.MoveSpeed); Vector3 simulateAmount = CalculateVelocityPerFrame(gameTime, moveVelocity); // Check moving area CollisionResult result = MoveHitTestWithMech(simulateAmount); // If moving way is blocked if (result != null) { MoveStop(); Vector3 oppositeDirection = Vector3.Negate(GetMoveAt(this.Velocity)); // Move to reverse direction AddPosition(oppositeDirection * Math.Abs(result.distance)); // Crash with player, and attacking if (result.detectedCollide.Owner is GamePlayer) { SetNextAI(AIType.Attack, 0.5f); } else { // turn to right SetNextAI(AIType.TurnRight, 90.0f / SpecData.TurnAngle); } } else { // Critical damage if (IsCriticalDamaged) MoveStop(); else Move(moveVelocity); } } else { // If moving way is blocked if (isMoveBlocked) { // turn to right SetNextAI(AIType.TurnRight, 90.0f / SpecData.TurnAngle); } else { MoveStop(); SetNextAI(AIType.Search, 0.2f); } } ActionMovement(gameTime, Velocity); }
/// <summary> /// mech's A.I. function. /// attacks an attack objective if it is within shooting range. /// If not, searches for an attack objective again. /// </summary> /// <param name="aiBase">current A.I.</param> /// <param name="gameTime"></param> public override void OnAIAttackEvent(AIBase aiBase, GameTime gameTime) { MoveStop(); // The enmey weapon reloading if (CurrentWeapon.CurrentAmmo == 0 && !IsFiring && !IsReloading) { ActionReload(CurrentWeapon); } else if (CurrentWeapon.IsPossibleToFire()) { // Attack action if (currentAction == Action.Fire) { // Waiting for ready to first fire if (this.fireDelayElapsedTime >= CurrentWeapon.SpecData.FireDelayTimeTillFirst) { this.fireDelayElapsedTime = 0.0f; WeaponFire(); } else { this.fireDelayElapsedTime += (float)gameTime.ElapsedGameTime.TotalSeconds; } } else { ActionFire(); } } if (!aiBase.IsActive && currentAction != Action.Fire) { SetNextAI(AIType.Search, HelperMath.RandomNormal()); } }