/// <summary> /// Seareches for the available respawn quarter for the given playerDefaultGuns. /// </summary> /// <param name="quarterOwner">The given player that has to be respawned</param> /// <param name="gameTime">Game time</param> /// <returns>Quarter where the given player can be respawned</returns> TownQuarter FindAndRespawnQuartersFor(ITownQuarterOwner quarterOwner, GameTime gameTime) { TownQuarter newPosQuarter = null; IOrderedEnumerable <TownQuarter> randomizedQuarters = from q in town.Quarters where q.Owner == quarterOwner || q.Owner == EmptyTownQuarterOwner.Instance orderby random.Next() select q; foreach (TownQuarter quarter in town.Quarters) { if (quarter.Owner == quarterOwner) { if (newPosQuarter == null) { newPosQuarter = quarter; } else { quarter.SetOwner(EmptyTownQuarterOwner.Instance, gameTime); } } } if (newPosQuarter == null) { newPosQuarter = randomizedQuarters.First(); } return(newPosQuarter); }
/// <summary> /// Performs a gun action - the shoot. It Releases the bullet into the space and calls the bullet collision resolving. /// </summary> /// <param name="gameTime">Game time</param> /// <param name="position">The gun position in the shoot moment</param> /// <param name="azimuth">The shoot direction</param> public override void DoAction(GameTime gameTime, PositionInTown position, float azimuth) { if (gameTime.TotalGameTime - lastTimeShot >= type.ShotTimeout && Usable) { bool somethingWasHit = PerformShoot(gameTime, position, azimuth, true); if (!somethingWasHit && Holder is Player) //affect the secondary drawn quarter { TownQuarter secondaryQuarter = Game.Town.SecondaryDrawnQuarter; Debug.Write("Secondary quarer", secondaryQuarter.Name); Vector2 positionDelta = secondaryQuarter.CurrentDrawingPositionDelta; float azimuthDelta = secondaryQuarter.CurrentDrawingAzimuthDelta; PositionInTown secondaryPosition = new PositionInTown(secondaryQuarter, Vector3.Transform(position.PositionInQuarter.ToVector3(0), Matrix.CreateTranslation(-positionDelta.ToVector3(0)) * Matrix.CreateRotationY(azimuthDelta)).XZToVector2()); float secondaryAzimuth = azimuth - azimuthDelta; PerformShoot(gameTime, secondaryPosition, secondaryAzimuth, false); if (secondaryQuarter != Game.Opponent.Position.Quarter && gameTime.IsRunningSlowly) { secondaryQuarter.Update(gameTime, true); } } Game.SoundPlayer.PlaySound(type.ShootSount, position); lastTimeShot = gameTime.TotalGameTime; bullets--; } }
/// <summary> /// Respawns the human into a specified quarter. /// </summary> /// <param name="targetQuarter">The destination quarter</param> public void RespawnInto(TownQuarter targetQuarter) { Position.Quarter.BeLeftBy(this); Position = new PositionInTown(targetQuarter, targetQuarter.GetRandomSquare(fillType => fillType == MapFillType.Road, point => point != targetQuarter.FlagPoint).ToVector2() * TownQuarter.SquareWidth); Position.Quarter.BeEnteredBy(this); health = 100; tasks.Clear(); }
/// <summary> /// Updates the kill task logic. It navigates the holder to the target and waits for him to shoot the target. If the holder has not a usable gun, it leads him to search for a toolbox. It can also lead him to for a healbox if it is needed. /// </summary> /// <param name="gameTime">Game time</param> public override void Update(GameTime gameTime) { if (Holder.SelectedTool is Gun && ((Gun)Holder.SelectedTool).Type.Range < TownQuarter.SquareWidth) { Box nearestToolBox = Holder.Position.Quarter.GetNearestBox(Holder.Position, true); if (nearestToolBox != null) { Holder.AddUrgentTask(new MoveTask(Holder, nearestToolBox.Pivot)); } } int neededHealth = target.Health - (Holder.SelectedTool is Gun ? ((Gun)Holder.SelectedTool).Type.Damage : 0); if (Holder.Health < neededHealth) { Box nearestHealBox = Holder.Position.Quarter.GetNearestBox(Holder.Position, false); if (nearestHealBox != null) { Holder.AddUrgentTask(new MoveTask(Holder, nearestHealBox.Pivot)); } } if (gameTime.TotalGameTime - lastUpdatedWaypoints > RecomputeWaypointsTimeout && (lastTargetQuarter != target.Position.Quarter || target.Position.Quarter == Holder.Position.Quarter)) { lastTargetQuarter = target.Position.Quarter; goStraightToTarget = false; if (Holder.Position.Quarter == target.Position.Quarter) { Vector2 wayVect = (target.Position.PositionInQuarter - Holder.Position.PositionInQuarter); float direction = (wayVect.GetAngle() + 1 * MathHelper.PiOver2) % MathHelper.TwoPi; Quadrangle viewLine = Quadrangle.CreateBand(Holder.Pivot.PositionInQuarter, direction, Holder.Size.X, wayVect.Length()); goStraightToTarget = !Grid.IsInCollision(viewLine, c => !(c is Human)); } if (!goStraightToTarget) { RecomputeWaypoints(Holder.Position, target.Position); } lastUpdatedWaypoints = gameTime.TotalGameTime; } if (goStraightToTarget) { if (Holder.Position.MinimalDistanceTo(target.Position) > TownQuarter.SquareWidth) { Holder.GoThisWay(target.Position, (float)gameTime.ElapsedGameTime.TotalSeconds); } else { Holder.TurnThisWay(target.Position, (float)gameTime.ElapsedGameTime.TotalSeconds); } } else { base.Update(gameTime); } }
/// <summary> /// Creates a new bullet visualisation. /// </summary> /// <param name="quarter">Town quarter where the bullet is located</param> /// <param name="start">Starting position</param> /// <param name="azimuth">The flight direction</param> /// <param name="range">The flight range</param> /// <param name="startHeight">Starting height</param> /// <param name="endHeight">Ending height</param> public BulletVisualisation(TownQuarter quarter, Vector2 start, float azimuth, float range, float startHeight, float endHeight) { Vector2 end = start.Go(range, azimuth); Vector2 startL = start.Go(Width, azimuth - MathHelper.PiOver2); Vector2 startR = start.Go(Width, azimuth + MathHelper.PiOver2); Vector2 endL = end.Go(Width, azimuth - MathHelper.PiOver2); Vector2 endR = end.Go(Width, azimuth + MathHelper.PiOver2); horizontalPlate = new Plate(quarter, startL.ToVector3(startHeight), startR.ToVector3(startHeight), endL.ToVector3(endHeight), endR.ToVector3(endHeight), Texture, Texture, false); verticalPlate = new Plate(quarter, start.ToVector3(startHeight + Width), start.ToVector3(startHeight - Width), end.ToVector3(endHeight + Width), end.ToVector3(endHeight - Width), Texture, Texture, false); }
/// <summary> /// Creates a new plate. /// </summary> /// <param name="homeQuarter">Town quarter where is it located</param> /// <param name="upperLeft">Upper left corner</param> /// <param name="upperRight">Upper right corner</param> /// <param name="lowerLeft">Lower left corner</param> /// <param name="lowerRight">Lower right corner</param> /// <param name="front">Front side texture</param> /// <param name="back">Back side texture</param> /// <param name="enableDefaultLightning">Determines if the default lightning is used</param> public Plate(TownQuarter homeQuarter, Vector3 upperLeft, Vector3 upperRight, Vector3 lowerLeft, Vector3 lowerRight, Texture2D front, Texture2D back, bool enableDefaultLightning) : base(upperLeft.XZToVector2(), upperRight.XZToVector2(), lowerLeft.XZToVector2(), lowerRight.XZToVector2()) { quarter = homeQuarter; ul = upperLeft; ur = upperRight; ll = lowerLeft; lr = lowerRight; this.back = back; this.front = front; graphicsDevice = front.GraphicsDevice; frontVertices = new VertexPositionNormalTexture[4]; backVertices = new VertexPositionNormalTexture[4]; indexes = new short[6]; BuildEffects(enableDefaultLightning); }
/// <summary> /// Creates a new guard for this human. /// </summary> /// <param name="targetQuarter">Quarted that has to be guarded</param> /// <returns>The guard</returns> public Human CreateAllyGuard(TownQuarter targetQuarter) { PositionInTown pos = new PositionInTown(targetQuarter, targetQuarter.GetRandomSquare(x => x == MapFillType.Road).ToVector2() * TownQuarter.SquareWidth); Human guard = new Human(game, Content.AllyHumanModel, pos, 0, game.Drawer.WorldTransformMatrix); foreach (Human enemy in enemies) { guard.AddEnemy(enemy); } foreach (Human friend in friends) { guard.AddFriend(friend); } foreach (Human has in hasMeAsEnemy) { has.AddEnemy(guard); } guard.AddTask(new InfinityWalkingTask(guard, targetQuarter.GetRandomWalkingWaypoints())); foreach (GunType gt in game.GuardDefaultGuns) { guard.AddTool(new Gun(gt, gt.DefaultBulletCount, guard, game)); } return(guard); }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { if (running) { base.Update(gameTime); Debug.Write("UPS", 1d / gameTime.ElapsedGameTime.TotalSeconds); // Allows the game to exit if (Keyboard.GetState().IsKeyDown(Keys.Escape)) { this.Restart(); return; } bool opponentInTheSameQuarter = opponent.Position.Quarter == town.CurrentQuarter; if (!opponentInTheSameQuarter) { opponent.Position.Quarter.Update(gameTime, true); } if (town.SecondaryDrawnQuarter != null && town.SecondaryDrawnQuarter != opponent.Position.Quarter && town.SecondaryDrawnQuarter != player.Position.Quarter && !gameTime.IsRunningSlowly) { town.SecondaryDrawnQuarter.Update(gameTime, false); } opponent.Update(gameTime, !opponentInTheSameQuarter); player.Update(gameTime); ITownQuarterOwner owner = town.Quarters[0].Owner; if ((owner == player || owner == opponent) && town.Quarters.All(q => q.Owner == owner)) { System.Drawing.Bitmap townMap = town.CreateTownMapImage(); PrepareEnd(); bool playAgain; using (GameOver gameOver = new GameOver(owner == player, townMap)) { System.Windows.Forms.DialogResult result = gameOver.ShowDialog(); playAgain = result != System.Windows.Forms.DialogResult.Cancel; } townMap.Dispose(); if (playAgain) { ShowMainMenuDialog(false); PrepareStart(); } else { Exit(); } return; } if (player.Health <= 0) { TownQuarter newQuarter = FindAndRespawnQuartersFor(player, gameTime); player.RespawnInto(newQuarter); drawer.ShowMessage(gameTime, String.Format("You were killed! You are now in {0}.", newQuarter.Name)); town.CurrentQuarter = newQuarter; drawer.ShowFullscreenEffect(gameTime, contentRepository.RespawnFullscreenEffect, Player.RespawnFullscreenEffectDuration); } if (opponent.Health <= 0) { TownQuarter newQuarter = FindAndRespawnQuartersFor(opponent, gameTime); opponent.RespawnInto(newQuarter); opponent.ClearTasks(); drawer.ShowMessage(gameTime, String.Format("Congratulations, your opponent was killed. He respawned in {0}.", newQuarter.Name)); } } }
/// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { if (running) { using (Loading loadingForm = new Loading()) { GameTime gameTime = new GameTime(TimeSpan.Zero, TimeSpan.Zero); loadingForm.Show(); loadingForm.SetLabel("Loading graphics device tools..."); spriteBatch = new SpriteBatch(GraphicsDevice); loadingForm.SetLabel("Loading content..."); contentRepository.LoadContent(); loadingForm.SetLabel("Loading gun types..."); LoadGunTypes(); player = new Player(this); opponent = new Opponent(this); town = new Town(this, loadingForm); loadingForm.SetLabel("Loading player..."); loadingForm.SetValue(0); Point playerPoint = town.CurrentQuarter.GetRandomSquare(s => s == MapFillType.Sidewalk); PositionInTown playerPosition = new PositionInTown(town.CurrentQuarter, playerPoint.ToVector2() * TownQuarter.SquareWidth + Vector2.One * 0.5f * TownQuarter.SquareWidth); player.Load(contentRepository.Player, playerPosition, MathHelper.PiOver2, drawer.WorldTransformMatrix); town.CurrentQuarter.SpaceGrid.AddObject(player); town.CurrentQuarter.SetOwner(player, gameTime); player.AddEnemy(opponent); loadingForm.SetLabel("Loading opponent..."); loadingForm.SetValue(0); TownQuarter oppQuarter = (from q in town.Quarters where q != town.CurrentQuarter orderby random.Next() select q).First(); Point oppPoint = oppQuarter.GetRandomSquare(s => s == MapFillType.Sidewalk); PositionInTown oppPosition = new PositionInTown(oppQuarter, oppPoint.ToVector2() * TownQuarter.SquareWidth); opponent.Load(contentRepository.Opponent, oppPosition, 0, drawer.WorldTransformMatrix); oppQuarter.BeEnteredBy(opponent); oppQuarter.SetOwner(opponent, gameTime); opponent.AddEnemy(player); Components.Add(town); BulletVisualisation.Texture = Content.Load <Texture2D>("Textures/white"); backgroundSound = Content.Load <SoundEffect>("Sounds/background").CreateInstance(); loadingForm.SetLabel("Cleaning memory..."); loadingForm.SetValue(0); GC.Collect(); loadingForm.SetValue(100); loadingForm.SetLabel("Content loaded. Get ready to play!"); loadingForm.SetValue(100); loadingForm.Close(); backgroundSound.IsLooped = true; backgroundSound.Play(); drawer.ShowMessage(new GameTime(), String.Format("Wellcome in the game. You're in {0}.", player.Position.Quarter.Name)); } if (settings.Fullscreen) { graphics.ToggleFullScreen(); } } }
/// <summary> /// Creates a new spatial object. /// </summary> /// <param name="model">Model</param> /// <param name="quarter">Town quarter</param> /// <param name="positionInQuarter">Position inside the town quarter</param> /// <param name="azimuth">Azimuth</param> /// <param name="worldTransform">World transform matrix</param> public SpatialObject(Model model, TownQuarter quarter, Vector3 positionInQuarter, double azimuth, Matrix worldTransform) : base(new PositionInTown(quarter, positionInQuarter.XZToVector2()), azimuth, (model == null? Vector2.Zero : model.GetSize(worldTransform).XZToVector2())) { Load(model, new PositionInTown(quarter, positionInQuarter.XZToVector2()), positionInQuarter.Y, azimuth, worldTransform); }
/// <summary> /// Performes the bullet releasing in the shoot process /// </summary> /// <param name="gameTime">Game time</param> /// <param name="position">Start position</param> /// <param name="azimuth">Flight direction</param> /// <param name="visualiseBullet">Whether the bullet should be visualised indicator</param> /// <returns>True if the bullet hit something</returns> bool PerformShoot(GameTime gameTime, PositionInTown position, float azimuth, bool visualiseBullet) { const float bulletWidth = 0.02f; //const float startHeight = 0.5f; const float bulletWidthHalf = bulletWidth / 2; bool solveHeight = (Holder is Player); double lookAngle = Holder.LookAngle; //Vector2 quarterPosition = position.PositionInQuarter; float startHeight = Holder.FirstHeadPosition.Y - bulletWidth; Vector2 quarterPosition = position.PositionInQuarter; Vector2 left = quarterPosition.Go(bulletWidthHalf, azimuth - MathHelper.PiOver2); Vector2 right = quarterPosition.Go(bulletWidthHalf, azimuth + MathHelper.PiOver2); Quadrangle bullet = new Quadrangle(right, left, right.Go(type.Range, azimuth), left.Go(type.Range, azimuth)); TownQuarter quarter = position.Quarter; List <Quadrangle> colliders = new List <Quadrangle>(quarter.SpaceGrid.GetAllCollisions(bullet)); colliders.RemoveAll(x => x == Holder); //Half-interval search Stack <RangeF> testedParts = new Stack <RangeF>(); Dictionary <float, float> heights = new Dictionary <float, float>(); testedParts.Push(new RangeF(0, type.Range)); if (solveHeight) { heights.Add(0, startHeight); heights.Add(type.Range, startHeight + type.Range * (float)Math.Tan(lookAngle)); } Quadrangle nearest = null; float distance = type.Range; while (testedParts.Count != 0) { RangeF bulletRangePart = testedParts.Pop(); float h1 = 0f; float h2 = 0f; if (solveHeight) { h1 = heights[bulletRangePart.Begin]; h2 = heights[bulletRangePart.End]; } Quadrangle bulletPart = new Quadrangle( left.Go(bulletRangePart.Begin, azimuth), right.Go(bulletRangePart.Begin, azimuth), left.Go(bulletRangePart.End, azimuth), right.Go(bulletRangePart.End, azimuth)); List <Quadrangle> newColliders = new List <Quadrangle>( colliders.Where( x => (solveHeight && x is SpatialObject && (((SpatialObject)x).Size.Y >= h2 || ((SpatialObject)x).Size.Y >= h2) && (0 <= h1 || 0 <= h2) && x.IsInCollisionWith(bulletPart)) || (!solveHeight && x.IsInCollisionWith(bulletPart)) ) ); if (newColliders.Count != 0) { if (newColliders.Count == 1 || bulletRangePart.Length <= bulletWidthHalf) { nearest = newColliders[0]; distance = bulletRangePart.End; break; } colliders = newColliders; float halfLength = bulletRangePart.Length * 0.5f; float middle = bulletRangePart.Begin + halfLength; testedParts.Push(new RangeF(middle, bulletRangePart.End)); testedParts.Push(new RangeF(bulletRangePart.Begin, middle)); if (solveHeight && halfLength != 0f) { heights.Add(middle, startHeight + middle * (float)Math.Tan(lookAngle)); } } } if (visualiseBullet) { quarter.AddBullet(gameTime, new BulletVisualisation(quarter, quarterPosition, azimuth, distance, startHeight, startHeight + distance * (float)Math.Tan(lookAngle))); } if (nearest != null) { Debug.Write("Shot", nearest.ToString()); nearest.BecomeShoot(gameTime, type.Damage, Holder); return(true); } return(false); }
/// <summary> /// Performs move to the spcifed target. /// </summary> /// <param name="destination">Wished destination</param> /// <param name="seconds">Duration</param> public void GoThisWay(PositionInTown destination, float seconds) { if (destination.Quarter == Position.Quarter) { double actualRotateAngle = RotateAngle * seconds; float direction = (destination.PositionInQuarter - Position.PositionInQuarter).GetAngle() + 1 * MathHelper.PiOver2; direction = direction % MathHelper.TwoPi; if (IsAzimuthTooFarFrom(direction, actualRotateAngle)) { bool toLeft = (azimuth > direction && direction >= 0 && azimuth - direction < MathHelper.Pi) || (direction > azimuth && direction - azimuth > MathHelper.Pi); Rotate(toLeft, seconds); if (Math.Abs(azimuth - direction) < MathHelper.PiOver2 && Position.MinimalDistanceTo(destination) > TownQuarter.SquareWidth) { Go(seconds); } } else { azimuth = direction; Go(seconds); } } else { TownQuarterInterface rightIface = null; foreach (TownQuarterInterface iface in Position.Quarter.Interfaces) { if (iface.OppositeInterface.Quarter == destination.Quarter) { rightIface = iface; } } if (rightIface != null) { if (Position.MinimalDistanceTo(rightIface.LeftPathGraphVertex.Position) <= Human.EpsilonDistance || Position.MinimalDistanceTo(rightIface.RightPathGraphVertex.Position) <= Human.EpsilonDistance) { //Changes home quarter TownQuarter newQuarter = rightIface.OppositeInterface.Quarter; Position.Quarter.BeLeftBy(this); Game.Drawer.StopDrawingObject(this); Vector2 posDelta = Town.ResolveQuarterPositionDelta(rightIface); float azDelta = Town.ResolveQuarterAzimuthDelta(rightIface.SidePosition, rightIface.OppositeInterface.SidePosition); MoveTo( new PositionInTown(newQuarter, Vector3.Transform(PositionInQuarter, Matrix.CreateTranslation(-posDelta.ToVector3(0)) * Matrix.CreateRotationY(azDelta)).XZToVector2()), Azimuth - azDelta ); newQuarter.BeEnteredBy(this); if (newQuarter.CurrentlyDrawed) { Game.Drawer.StartDrawingObject(this, newQuarter.CurrentDrawingAzimuthDelta, newQuarter.CurrentDrawingPositionDelta); } } else { GoThisWay(rightIface.LeftPathGraphVertex.Position, seconds); } } } }