/// <summary> /// Update this AI instance. /// </summary> /// <param name="wo">WorldObject controlled by this AI instance /// </param> /// <param name="lev">Currently active level</param> public override void Update(WorldObject wo, Level lev) { // If the player is dead then do not update and stop motion if (lev.Player.Dead) { wo.Stand(); return; } // Turn to face the player if (wo.WorldX - lev.Player.WorldX < 0) { wo.FlipX(); } else { wo.UnflipX(); } // Update the timers CurFireTime += GameMain.SecondsPerFrame; CurDuckTime += GameMain.SecondsPerFrame; // If attacking then let it finish if (wo.State == WorldObject.AnimationState.Attack) { return; } // Distance to any incoming shots float shotDistX = 0.0F; float shotDistY = 0.0F; if (!CheckDuck(wo, lev, ref shotDistX, ref shotDistY)) { // If not ducking a shot then check if an attack // should occur if (wo.State != WorldObject.AnimationState.Duck && Math.Abs(wo.WorldX - lev.Player.WorldX) <= MaxX && CurFireTime >= CurFireRate) { CurFireTime = 0; CurFireRate = (FireRateMin + GameMain.Random() * (FireRateMax - FireRateMin)); wo.Attack(); } else if (wo.State != WorldObject.AnimationState.Duck) { wo.Stand(); } } }
/// <summary> /// Initialize this instance of the fly by AI. /// </summary> /// <param name="wo">WorldObject owning this AI</param> /// <param name="lev">Current level</param> public override void Init(WorldObject wo, Level lev) { // Determine random circling and attacking altitudes circleY = MaxY * .6F + .8F * MaxY * GameMain.Random(); attackY = MinY * .8F + .4F * MinY * GameMain.Random(); // Make sure the object is stopped wo.VelocityY = 0.0F; wo.VelocityX = 0.0F; // Make sure that the circling altitude is at least as high as // the attacking altitude. if (circleY < attackY) { circleY = attackY; } // Start at the circling altitude wo.WorldY = circleY; // Start with the walking animation wo.Walk(); }
/// <summary> /// Initialize this instance of AI. /// </summary> /// <param name="wo">WorldObject controlled by this AI instance /// </param> /// <param name="lev">Currently active level</param> public override void Init(WorldObject wo, Level lev) { CurFireRate = (FireRateMin + GameMain.Random() * (FireRateMax - FireRateMin)); }
/// <summary> /// Determine if the world object should duck, assuming there is a /// need to. /// </summary> /// <param name="lev">Current level</param> /// <param name="wo">WorldObject to check</param> /// <returns>true if the object should duck, false otherwise</returns> protected bool ShouldDuck(Level lev, WorldObject wo) { return((CurDuckTime >= DuckRate && GameMain.Random() < DuckChance) || Math.Abs(wo.WorldX - lev.Player.WorldX) > MaxX); }
/// <summary> /// Update the player. /// </summary> /// <param name="gi">Input instance</param> /// <param name="lev">Current level</param> /// <returns>Always false</returns> public override bool Update(Input gi, Level lev) { // Assume there is no misfire this frame misfireValue = false; // If a shot is charging then update the time if (shotStarted) { shotTime += GameMain.SecondsPerFrame; } // If the player is not dead then update it if ((State & AnimationState.Dead) == 0) { // clear out the current direction but leave the animation // state State = prevState & AnimationState.AnimationMask; // If attacking then update the shot state if ((State & AnimationState.Attack) != 0) { // If the shot is not already fired and the current // animation cell is the one where the player shoots // then launch a shot if (!GetShotInfo()[0].Fired && Animation.CurCell == GetShotInfo()[0].ShootCell) { // Determine the direction of the shot WorldDir dir = WorldDir.Left; if ((DrawOptions & DrawOptions.BlitMirrorLeftRight) == 0) { dir = WorldDir.Right; } // Velocity multipliers float shotVelXMultiplier; float shotVelYMultiplier; // Determine the chance of a misfire based on the shot // bar charge (min to max) float misfireChance = shotMisfireMax - CurrentShotBarPercent * (shotMisfireMax - shotMisfireMin); if (GameMain.Random() < misfireChance) { // A misfire occurred so set the flag and // update the velocity multipliers accordingly misfireValue = true; shotVelXMultiplier = shotMisfireVelocityXMin + GameMain.Random() * (shotVelocityXMax - shotVelocityXMin); shotVelYMultiplier = shotMisfireVelocityYMin + GameMain.Random() * (shotVelocityYMax - shotVelocityYMin); } else { // No misfire, so the velocities are set // relative to the bar charge percentage shotVelXMultiplier = shotVelocityXMin + CurrentShotBarPercent * (shotVelocityXMax - shotVelocityXMin); shotVelYMultiplier = shotVelocityYMax - CurrentShotBarPercent * (shotVelocityYMax - shotVelocityYMin); } // Fire a shot and reset the charge time shotTime = 0.0F; FireShot(lev, GetShotInfo()[0], dir, shotVelXMultiplier, shotVelYMultiplier); } else if (Animation.Done) { // If the shot animation is done then reset shot info GetShotInfo()[0].Fired = false; State = AnimationState.Walk; curCycle = WalkCycle; } } else if (gi.KeyPressed((int)Keys.Down)) { // If pressing down then attempt to crawl. State = AnimationState.Duck; curCycle = DuckCycle; } else if (gi.KeyPressed((int)Keys.Up)) { // If pressing up then stand up State = AnimationState.Walk; curCycle = WalkCycle; } else if (!shotStarted && gi.KeyDown( (int)gi.HardwareKeys[buttonMapValue[ (int)Buttons.FireShot]])) { // If the fire button is pressed then start charging // the bar shotStarted = true; shotTime = 0.0F; } else if (shotStarted && gi.KeyReleased( (int)gi.HardwareKeys[buttonMapValue[ (int)Buttons.FireShot]])) { // If the fire button is released then start the shot // animation curCycle = AttackCycle; State |= AnimationState.Attack; Animation.SetCycle(WalkCycle.StartCell, WalkCycle.EndCell, WalkCycle.AnimationRate); Animation.StartOneShot(AttackCycle.StartCell, AttackCycle.EndCell, AttackCycle.AnimationRate); shotStarted = false; } Debug.Assert(curCycle != null, "Player.Update: Invalid animation sequence"); Debug.Assert((State & AnimationState.AnimationMask) != 0, "Player.Update: Invalid animation state determined"); // Attempt to walk in the direction the user is pressing if (gi.KeyDown((int)Keys.Left)) { WalkLeft(lev); } else if (gi.KeyDown((int)Keys.Right)) { WalkRight(lev); } else { Stop(lev); } Debug.Assert((State & AnimationState.DirectionMask) != 0 && (State & AnimationState.AnimationMask) != 0, "Player.Update: Invalid movement state determined"); } // Update the animation Animation.Update(GameMain.SecondsPerFrame); // Set the previous state prevState = State; // The player always returns false return(false); }
/// <summary> /// Update this AI instance. /// </summary> /// <param name="wo">WorldObject controlled by this AI instance /// </param> /// <param name="lev">Currently active level</param> public override void Update(WorldObject wo, Level lev) { // If the player is dead then do not update and stop motion if (lev.Player.Dead) { wo.Stand(); wo.VelocityX = 0.0F; wo.VelocityY = 0.0F; return; } // Update the timers CurFireTime += GameMain.SecondsPerFrame; CurDuckTime += GameMain.SecondsPerFrame; // If attacking then let it finish if (wo.State == WorldObject.AnimationState.Attack) { return; } // Distance to any incoming shots float shotDistX = 0.0F; float shotDistY = 0.0F; // Cache some parameters Player p = lev.Player; float deltaPlayerX = p.WorldX - wo.WorldX; float deltaPlayerY = p.WorldY - wo.WorldY; // Check if the world object should evade a shot if (!CheckDuck(wo, lev, ref shotDistX, ref shotDistY)) { if (wo.State != WorldObject.AnimationState.Duck && Math.Abs(deltaPlayerX) <= MaxX && CurFireTime >= CurFireRate) { // If the player is within range, the world object is not // ducking, and it is time to fire then shoot at the // player CurFireTime = 0; CurFireRate = (FireRateMin + GameMain.Random() * (FireRateMax - FireRateMin)); wo.Attack(); wo.VelocityX = 0.0F; } else if (wo.State != WorldObject.AnimationState.Duck) { // Walk toward the player if not overlapping // Overlapping can only occur when collisions are off if (deltaPlayerX > 5.0F) { wo.Walk(); wo.VelocityX = VelocityX; wo.FlipX(); } else if (deltaPlayerX < -5.0F) { wo.Walk(); wo.VelocityX = -VelocityX; wo.UnflipX(); } else { wo.Stand(); wo.VelocityX = 0.0F; } } } else { // Stop all movement if ducking wo.VelocityX = 0.0F; } }