/// <summary> /// UpdateTank runs the AI code that will update the tank's orientation and /// position. It is very similar to UpdateMouse, but is slightly more /// complicated: where mouse only has two states, idle and active, the Tank has /// three. /// </summary> private void UpdateTank () { // However, the tank's behavior is more complicated than the mouse's, and so // the decision making process is a little different. // First we have to use the current state to decide what the thresholds are // for changing state, as described in the doc. float tankChaseThreshold = TankChaseDistance; float tankCaughtThreshold = TankCaughtDistance; // if the tank is idle, he prefers to stay idle. we do this by making the // chase distance smaller, so the tank will be less likely to begin chasing // the cat. if (tankState == TankAiState.Wander) { tankChaseThreshold -= TankHysteresis / 2; } // similarly, if the tank is active, he prefers to stay active. we // accomplish this by increasing the range of values that will cause the // tank to go into the active state. else if (tankState == TankAiState.Chasing) { tankChaseThreshold += TankHysteresis / 2; tankCaughtThreshold -= TankHysteresis / 2; } // the same logic is applied to the finished state. else if (tankState == TankAiState.Caught) { tankCaughtThreshold += TankHysteresis / 2; } // Second, now that we know what the thresholds are, we compare the tank's // distance from the cat against the thresholds to decide what the tank's // current state is. float distanceFromCat = Vector2.Distance (tankPosition, catPosition); if (distanceFromCat > tankChaseThreshold) { // just like the mouse, if the tank is far away from the cat, it should // idle. tankState = TankAiState.Wander; } else if (distanceFromCat > tankCaughtThreshold) { tankState = TankAiState.Chasing; } else { tankState = TankAiState.Caught; } // Third, once we know what state we're in, act on that state. float currentTankSpeed; if (tankState == TankAiState.Chasing) { // the tank wants to chase the cat, so it will just use the TurnToFace // function to turn towards the cat's position. Then, when the tank // moves forward, he will chase the cat. tankOrientation = TurnToFace (tankPosition, catPosition, tankOrientation, TankTurnSpeed); currentTankSpeed = MaxTankSpeed; } else if (tankState == TankAiState.Wander) { // wander works just like the mouse's. Wander (tankPosition, ref tankWanderDirection, ref tankOrientation, TankTurnSpeed); currentTankSpeed = .25f * MaxTankSpeed; } else { // this part is different from the mouse. if the tank catches the cat, // it should stop. otherwise it will run right by, then spin around and // try to catch it all over again. The end result is that it will kind // of "run laps" around the cat, which looks funny, but is not what // we're after. currentTankSpeed = 0.0f; } // this calculation is also just like the mouse's: we construct a heading // vector based on the tank's orientation, and then make the tank move along // that heading. Vector2 heading = new Vector2 ( (float)Math.Cos (tankOrientation), (float)Math.Sin (tankOrientation)); tankPosition += heading * currentTankSpeed; }
/// <summary> /// UpdateTank runs the AI code that will update the tank's orientation and /// position. It is very similar to UpdateMouse, but is slightly more /// complicated: where mouse only has two states, idle and active, the Tank has /// three. /// </summary> private void UpdateTank() { // However, the tank's behavior is more complicated than the mouse's, and so // the decision making process is a little different. // First we have to use the current state to decide what the thresholds are // for changing state, as described in the doc. float tankChaseThreshold = TankChaseDistance; float tankCaughtThreshold = TankCaughtDistance; // if the tank is idle, he prefers to stay idle. we do this by making the // chase distance smaller, so the tank will be less likely to begin chasing // the cat. if (tankState == TankAiState.Wander) { tankChaseThreshold -= TankHysteresis / 2; } // similarly, if the tank is active, he prefers to stay active. we // accomplish this by increasing the range of values that will cause the // tank to go into the active state. else if (tankState == TankAiState.Chasing) { tankChaseThreshold += TankHysteresis / 2; tankCaughtThreshold -= TankHysteresis / 2; } // the same logic is applied to the finished state. else if (tankState == TankAiState.Caught) { tankCaughtThreshold += TankHysteresis / 2; } // Second, now that we know what the thresholds are, we compare the tank's // distance from the cat against the thresholds to decide what the tank's // current state is. float distanceFromCat = Vector2.Distance(tankPosition, catPosition); if (distanceFromCat > tankChaseThreshold) { // just like the mouse, if the tank is far away from the cat, it should // idle. tankState = TankAiState.Wander; } else if (distanceFromCat > tankCaughtThreshold) { tankState = TankAiState.Chasing; } else { tankState = TankAiState.Caught; } // Third, once we know what state we're in, act on that state. float currentTankSpeed; if (tankState == TankAiState.Chasing) { // the tank wants to chase the cat, so it will just use the TurnToFace // function to turn towards the cat's position. Then, when the tank // moves forward, he will chase the cat. tankOrientation = TurnToFace(tankPosition, catPosition, tankOrientation, TankTurnSpeed); currentTankSpeed = MaxTankSpeed; } else if (tankState == TankAiState.Wander) { // wander works just like the mouse's. Wander(tankPosition, ref tankWanderDirection, ref tankOrientation, TankTurnSpeed); currentTankSpeed = .25f * MaxTankSpeed; } else { // this part is different from the mouse. if the tank catches the cat, // it should stop. otherwise it will run right by, then spin around and // try to catch it all over again. The end result is that it will kind // of "run laps" around the cat, which looks funny, but is not what // we're after. currentTankSpeed = 0.0f; } // this calculation is also just like the mouse's: we construct a heading // vector based on the tank's orientation, and then make the tank move along // that heading. Vector2 heading = new Vector2( (float)Math.Cos(tankOrientation), (float)Math.Sin(tankOrientation)); tankPosition += heading * currentTankSpeed; }