/// <summary> /// Update called for the Flying state /// </summary> /// <param name="time"></param> void UpdateFly(GameTime time) { // linear lerp position = Vector3.Lerp(srcPosition, dstPosition, flyProgress); flyProgress += time.ElapsedGameTimeSeconds * 0.5f; // estimate the remaining time to check if the target city's catch // animation should be played to make it in time float timeStamp = destCity.CatchPreserveTime; timeStamp = 1.5f - timeStamp; if ((flyProgress / 0.5f) > timeStamp) { if (!notifyedDest) { destCity.NotifyIncomingBall(this); // only notify once notifyedDest = true; } } // estimate the remaining time to check if the receive sound should be played timeStamp += 0.5f; if ((flyProgress / 0.5f) > timeStamp) { if (!catchSoundPlayed) { catchSound.Fire(); catchSoundPlayed = true; } } // now adds height to the position { float t = flyProgress * 2; const float Gr = 1000; float h; if (t < 1) { h = Gr * t - 0.5f * (Gr * t * t); } else { h = 0.5f * Gr - 0.5f * Gr * MathEx.Sqr(t - 1); } position += normal * h; } // finishes as long as the progress reaches 1 if (flyProgress > 1) { ChangeState(State.Finished); } }
void ChangeState(State newState) { if (newState == State.Flying) { for (int i = 0; i < subBalls.Count; i++) { subBalls[i].SetDockCity(null); } srcPosition = position; City dstCity = goPath[0]; this.destCity = dstCity; Quaternion newDstOri = dstCity.GetOrientation(srcPosition); normal = sourceCity.Transformation.Up + dstCity.Transformation.Up; normal.Normalize(); dstPosition = GetRGBallPosition(dstCity, newDstOri); notifyedDest = false; flyProgress = 0; throwSound.Fire(); } else if (newState == State.Finished) { ReleaseBalls(); } state = newState; }
public override void Update(GameTime gameTime) { float dt = (float)gameTime.ElapsedGameTimeSeconds; if (weaponCoolDown > 0) { weaponCoolDown -= dt; } // accelerating and decelerating if (speedModifier < speedModifierTarget) { speedModifier += dt; } else if (speedModifier > speedModifierTarget) { speedModifier -= dt; } switch (state) { case RBallState.Standby: { IntegrateRoundAngle(dt); Vector3 pos; CalculateRoundTransform(currentRadius, false, out pos, out orientation); Position = pos; // stand by balls can contribute their docking city if (dockCity.Owner != null) { if (dockCity.Owner == Owner) { dockCity.Heal(dt * props.Heal, props.HealthIncr * dt); dockCity.Develop(props.Contribution, dt); } else { dockCity.Develop(-props.Contribution * 5, dt); } } break; } case RBallState.Gathering: { NewMoveUpdate(dt); if (!isMoving) { ChangeState(RBallState.Gathered); } break; } case RBallState.Free: { NewMoveUpdate(dt); if (!isMoving) { ChangeState(RBallState.Standby); } break; } case RBallState.BeginingAttackCity: { NewMoveUpdate(dt); if (!isMoving) { ChangeState(RBallState.AttackCity); } break; } case RBallState.AttackCity: { // attack when city not owned if (dockCity.Owner != Owner) { IntegrateRoundAngle(dt); Vector3 pos; CalculateRoundTransform(CityAttackRadius, true, out pos, out orientation); Position = pos; //tail.Update(gameTime, position, orientation.Forward); if (speedModifier >= AttackCitySpeedMod - 0.5f) { if (weaponCoolDown <= 0) { float dmg = props.Damage; dockCity.Damage(dmg, Owner); Damage(dmg * 0.075f); weaponCoolDown = WeaponCoolDownTime; } } } else { // when owned, check if the speed has decreased low enough if (speedModifier < AttackCitySpeedMod * 0.3f || speedModifier < MinSpeedMod) { // if so, go back to normal standby position Reposition(); } else { // otherwise, keep moveing, decelerating IntegrateRoundAngle(dt); Vector3 pos; CalculateRoundTransform(CityAttackRadius, true, out pos, out orientation); Position = pos; speedModifierTarget = MinSpeedMod; } } break; } case RBallState.Defend: case RBallState.Attack: { if (target == null || target.Owner == Owner || target.IsDied) { Reposition(); } else { NewMove(target.position); NewMoveUpdate(dt); float dist = Vector3.DistanceSquared(ref position, ref target.position); if (dist < AttackRange * AttackRange) { if (weaponCoolDown <= 0) { float dmg = props.Damage; target.Damage(dmg); weaponCoolDown = WeaponCoolDownTime; } } } break; } case RBallState.Float: { NewMoveUpdate(dt); float dist = Vector3.DistanceSquared(position, floatingTarget.Position); if (dist < City.CityOutterRadius * City.CityOutterRadius) { Free(floatingTarget); } break; } } base.Update(gameTime); // try attack if any attackable, and when in a suitable state if (dockCity != null && (state != RBallState.Gathered && state != RBallState.Gathering && state != RBallState.Free && state != RBallState.Float)) { if (dockCity.Owner != Owner) { // In an enemy city enemyCheckTime -= dt; if (enemyCheckTime <= 0 && props.Damage > 10) { if (dockCity.NearbyOwnedBallCount == 0) { if (state != RBallState.AttackCity && state != RBallState.BeginingAttackCity) { AttackCity(); } } else { if (state != RBallState.Attack) { Attack(); } } enemyCheckTime = EnemyCheckTime; } } else { switch (Type) { case RBallType.Oil: case RBallType.Green: case RBallType.Education: case RBallType.Volience: if (props.Damage > 10) { // defend if any if (dockCity.NearbyEnemyBallCount > 0) { if (state != RBallState.Attack) { Defend(); } } } break; case RBallType.Health: case RBallType.Disease: // These type of balls // defend if able to attack and the city is in good condition if (dockCity.HPRate > 1 - float.Epsilon && props.Damage > 10) { if (dockCity.NearbyEnemyBallCount > 0) { if (state != RBallState.Attack) { Defend(); } } } break; } } } if (shouldPlayDeathSonds) { soundObject.Position = position; soundObject.Update(gameTime); soundObject.Fire(); shouldPlayDeathSonds = false; } }