/// <summary> /// This method computes the edges of the walls /// </summary> private void WallCollisionSize() { foreach (Wall wall in theServerWorld.Walls.Values) { Vector2D head = wall.endPoint1; Vector2D tail = wall.endPoint2; // check which endpoint is the head if (!wall.IsEndpoint1Head) { head = wall.endPoint2; tail = wall.endPoint1; } if (wall.IsHorizontal) { wall.x1 = head.GetX() - wall.halfWallSize; wall.x2 = tail.GetX() + wall.halfWallSize; wall.y1 = head.GetY() - wall.halfWallSize; wall.y2 = head.GetY() + wall.halfWallSize; } else { wall.y1 = head.GetY() - wall.halfWallSize; wall.y2 = tail.GetY() + wall.halfWallSize; wall.x1 = head.GetX() - wall.halfWallSize; wall.x2 = head.GetX() + wall.halfWallSize; } } }
/// <summary> /// Move a tank based on given tank and movement, if tank will collide with a wall, tank will not move /// If tank goes out of the world, tank will be wrapped back into the world /// </summary> /// <param name="movement">movement command string, either "none", "left", "right", "up", or "down"</param> private void HandleTankMovement(string movement, Tank tank) { if (movement != "none") { //Get the direction vector base on Vector2D dir = GetDirection(movement, tank); //Set tank's orientation base on the wasd tank.Orientation = dir; //Compute next frame location Vector2D nextframelocation = tank.Location + dir * _tankspeed; //If tank will not collide with wall and in world, the update the tank location based on current engine strength (tank speed) and given direction if (!CollisionDetect.ObjectWallsCollision(tank, nextframelocation, theWorld) && InWorld(nextframelocation)) { tank.Location = nextframelocation; } //Wrap around to the other side if (!InWorld(nextframelocation)) { //Horizontal direction if (Math.Abs(nextframelocation.GetX()) > (theWorld.Size / 2)) { tank.Location = new Vector2D(-nextframelocation.GetX(), nextframelocation.GetY()); } //Vertical direction if (Math.Abs(nextframelocation.GetY()) > (theWorld.Size / 2)) { tank.Location = new Vector2D(nextframelocation.GetX(), -nextframelocation.GetY()); } } } }
/// <summary> /// This method checks if a vector collides with walls /// </summary> /// <param name="vector"></param> /// <param name="obj"></param> /// <returns></returns> private bool WallCollisionCheck(Vector2D vector, object obj) { double halfObj = 0; if (obj is Tank) { halfObj = Constant.TankSize / 2; } if (obj is Powerup) { halfObj = 10; } lock (theServerWorld) { foreach (Wall wall in theServerWorld.Walls.Values) { if (vector.GetX() > wall.x1 - halfObj && vector.GetX() < wall.x2 + halfObj && vector.GetY() > wall.y1 - halfObj && vector.GetY() < wall.y2 + halfObj) { return(true); } } } return(false); }
/// <summary> /// Checks for collision between powerup and current walls. /// </summary> /// <param name="position"></param> /// <returns></returns> private bool CheckPowerupWallCollision(Vector2D position) { bool temp = false; lock (world) { double x = (double)position.GetX(), y = (double)position.GetY(), worldsize = world.GetSize() / 2; foreach (Wall w in world.GetWalls()) { Vector2D p1 = w.p1, p2 = w.p2; double topX = Math.Max(p1.GetX() + 35, p2.GetX() + 35); double botX = Math.Min(p1.GetX() - 35, p2.GetX() - 35); double leftY = Math.Min(p1.GetY() - 35, p2.GetY() - 35); double rightY = Math.Max(p1.GetY() + 35, p2.GetY() + 35); if (x > botX && x < topX && y > leftY && y < rightY) { temp = true; } } if (x < -worldsize || x > worldsize || y < -worldsize || y > worldsize) { temp = true; } } return(temp); }
/// <summary> /// This method checks if a vector reaches the bounds of the world /// </summary> /// <param name="vector"></param> /// <returns></returns> private bool OutsideOfBoundsDetection(Vector2D vector) { if (vector.GetX() < -theServerWorld.worldSize / 2 || vector.GetX() > theServerWorld.worldSize / 2 || vector.GetY() < -theServerWorld.worldSize / 2 || vector.GetY() > theServerWorld.worldSize / 2) { return(true); } return(false); }
/// <summary> /// Returns the wraparound position of tank when needed. Otherwise, returns original position. /// </summary> /// <param name="position"></param> /// <returns></returns> private Vector2D TankWraparound(Vector2D position) { double x = (double)position.GetX(), y = (double)position.GetY(), worldsize = world.GetSize() / 2; Vector2D temp; if (x < 15 - worldsize) { temp = new Vector2D(worldsize - 16, y); } else if (x > worldsize - 15) { temp = new Vector2D(16 - worldsize, y); } else if (y < 15 - worldsize) { temp = new Vector2D(x, worldsize - 16); } else if (y > worldsize - 15) { temp = new Vector2D(x, 16 - worldsize); } else { temp = new Vector2D(x, y); } return(temp); }
/// <summary> /// Method for calculating the tank turret direction based on the mouse location in order to send /// to the server. /// </summary> /// <param name="x">X location of the mouse</param> /// <param name="y">Y location of the mouse</param> public void ProcessMouseMove(double x, double y) { Vector2D loc = new Vector2D(x - Constants.ViewSize / 2, y - Constants.ViewSize / 2); loc.Normalize(); commands.aiming = new Vector2D(loc.GetX(), loc.GetY()); }
public static void TranslateTransformToCenterPlayersView(int viewSize, int worldSize, Vector2D playerLocation, PaintEventArgs e) { double playerX = playerLocation.GetX(); double playerY = playerLocation.GetY(); double ratio = (double)viewSize / (double)worldSize; int halfSizeScaled = (int)(worldSize / 2.0 * ratio); double inverseTranslateX = -WorldSpaceToImageSpace(worldSize, playerX) + halfSizeScaled; double inverseTranslateY = -WorldSpaceToImageSpace(worldSize, playerY) + halfSizeScaled; e.Graphics.TranslateTransform((float)inverseTranslateX, (float)inverseTranslateY); }
/// <summary> /// Handle the mouse movement via centering x and y at our tank center. /// We then normalize and set the Turret direction. /// </summary> /// <param name="sender"></param> /// <param name="mousePoint"></param> public void HandleMouseMovement(object sender, Vector2D mousePoint) { // x,y to be centered at our tank double x = mousePoint.GetX() - 450; double y = mousePoint.GetY() - 450; mousePoint = new Vector2D(x, y); mousePoint.Normalize(); commands.SetTDIR(mousePoint); }
/// <summary> /// Checks for collision between a tank and the current walls. /// </summary> /// <param name="position"></param> /// <returns></returns> private bool CheckTankWallCollision(Vector2D position) { bool temp = false; lock (world) { double x = (double)position.GetX(), y = (double)position.GetY(); foreach (Wall w in world.GetWalls()) { Vector2D p1 = w.p1, p2 = w.p2; double topX = Math.Max(p1.GetX() + 55, p2.GetX() + 55); double botX = Math.Min(p1.GetX() - 55, p2.GetX() - 55); double leftY = Math.Min(p1.GetY() - 55, p2.GetY() - 55); double rightY = Math.Max(p1.GetY() + 55, p2.GetY() + 55); if (x > botX && x < topX && y > leftY && y < rightY) { temp = true; } } } return(temp); }
/// <summary> /// Check if given tank/projectile/powerup will collide with any of the wall in the world /// </summary> /// <param name="obj">tank/projectile/powerup object</param> /// <param name="dir">direction tank will go next frame</param> /// <returns>True if object collides any of the walls in world, false if object doesn't collide with any of the wall</returns> public static bool ObjectWallsCollision(Object obj, Vector2D location, World world) { double wallpadding; if (obj is Projectile || obj is Powerup) { wallpadding = world.WallSize / 2; } else { wallpadding = world.WallSize / 2 + world.TankSize / 2; } foreach (Wall wall in world.Walls.Values) { // Compute wall direction Vector2D walldir = wall.P1 - wall.P2; bool collide; if (walldir.GetX() == 0) // Vertical wall { // Get x y ranges double xmin = wall.P1.GetX() - wallpadding; double xmax = wall.P1.GetX() + wallpadding; double ymin = Math.Min(wall.P1.GetY(), wall.P2.GetY()) - wallpadding; double ymax = Math.Max(wall.P1.GetY(), wall.P2.GetY()) + wallpadding; collide = Collide(xmin, xmax, ymin, ymax, location); } else //Horizontal wall { // Get x y ranges double ymin = wall.P1.GetY() - wallpadding; double ymax = wall.P1.GetY() + wallpadding; double xmin = Math.Min(wall.P1.GetX(), wall.P2.GetX()) - wallpadding; double xmax = Math.Max(wall.P1.GetX(), wall.P2.GetX()) + wallpadding; collide = Collide(xmin, xmax, ymin, ymax, location); } if (collide) { return(true); } } //Tank doesn't collide with any wall in the world return(false); }
/// <summary> /// Method for drawing walls /// </summary> /// <param name="o"></param> /// <param name="e"></param> private void WallDrawer(object o, PaintEventArgs e) { // checks if the image of the wall is already loaded // the purpose is to load the image only in 1 frame, not every frame, so improve the performance if (wallImg == null) { wallImg = Image.FromFile(Constant.WallFile); } Wall w = o as Wall; int location = -(Constant.WallSize / 2); Vector2D head = w.endPoint1; Vector2D tail = w.endPoint2; // check which endpoint is the head if (!w.IsEndpoint1Head) { head = w.endPoint2; tail = w.endPoint1; } // if horizontal wall, increase X by 50 to draw the next wall // if vertical wall, increase Y if (w.IsHorizontal) { for (double i = head.GetX(); i <= tail.GetX(); i += 50.0F) { e.Graphics.DrawImage(wallImg, location, -(Constant.WallSize / 2), Constant.WallSize, Constant.WallSize); location += 50; } } else { for (double i = head.GetY(); i <= tail.GetY(); i += 50.0F) { e.Graphics.DrawImage(wallImg, -(Constant.WallSize / 2), location, Constant.WallSize, Constant.WallSize); location += 50; } } }
/// <summary> /// Compute the dot product of this vector with another vector /// </summary> /// <param name="v">The other vector</param> /// <returns></returns> public double Dot(Vector2D v) { return(GetX() * v.GetX() + GetY() * v.GetY()); }
/// <summary> /// This method is invoked when the DrawingPanel needs to be re-drawn /// </summary> protected override void OnPaint(PaintEventArgs e) { //Makes sure world is null, since it is null while loading game if (theWorld != null) { //Locks world since it accesses info from it lock (theWorld) { //Get player's tank to center view Tank player; if (theWorld.GetTank(PlayerID, out player)) { double playerX = player.location.GetX(); double playerY = player.location.GetY(); double ratio = (double)ViewSize / (double)theWorld.GetSize(); int halfSizeScaled = (int)(theWorld.GetSize() / 2.0 * ratio); double inverseTranslateX = -WorldSpaceToImageSpace(theWorld.GetSize(), playerX) + halfSizeScaled; double inverseTranslateY = -WorldSpaceToImageSpace(theWorld.GetSize(), playerY) + halfSizeScaled; e.Graphics.TranslateTransform((float)inverseTranslateX, (float)inverseTranslateY); } //Draw background e.Graphics.DrawImage(Background, new Rectangle(0, 0, theWorld.GetSize(), theWorld.GetSize())); // Draw the tanks foreach (Tank tank in theWorld.GetTanks()) { //Draw tank, turret, and info if tank is alive and ingame if (!tank.died && !tankTimer.ContainsKey(tank) && tank.hitPoints > 0) { DrawObjectWithTransform(e, tank, theWorld.GetSize(), tank.location.GetX(), tank.location.GetY(), tank.orientation.ToAngle(), TankDrawer); DrawObjectWithTransform(e, tank, theWorld.GetSize(), tank.location.GetX(), tank.location.GetY(), tank.aiming.ToAngle(), TurretDrawer); DrawObjectWithTransform(e, tank, theWorld.GetSize(), tank.location.GetX(), tank.location.GetY(), 0, InfoDrawer); } //Otherwise, add tank to tank timer, increment tank timer, or remove tank from tank timer if it is alive else { //If tank is a live again, remove from tank timer if (tank.hitPoints > 0) { tankTimer.Remove(tank); break; } //If tank is already in tank timer, decrement tank timer or remove tank from timer if (tankTimer.ContainsKey(tank)) { if (tankTimer[tank] < 200) { tankTimer[tank]++; } else { tankTimer.Remove(tank); } } //Add tank to timer if not in timer yet else { tankTimer.Add(tank, 0); } } } // Draw the walls foreach (Wall w in theWorld.GetWalls()) { Vector2D location = GetWallLocation(w); DrawObjectWithTransform(e, w, theWorld.GetSize(), location.GetX(), location.GetY(), 0, WallDrawer); } //Draw beams if existed for less than 60 frames List <Beam> beams = new List <Beam>(beamsTimer.Keys); foreach (Beam b in beams) { if (beamsTimer[b] > 60) { beamsTimer.Remove(b); } //Increments beamsTimer and draws beams else { beamsTimer[b]++; DrawObjectWithTransform(e, b, theWorld.GetSize(), b.origin.GetX(), b.origin.GetY(), b.direction.ToAngle(), BeamDrawer);; } } // Draw the powerups if not dead foreach (Powerup pow in theWorld.GetPowerups()) { if (!pow.died) { DrawObjectWithTransform(e, pow, theWorld.GetSize(), pow.location.GetX(), pow.location.GetY(), 0, PowerupDrawer); } } //Draw projectiles if not dead foreach (Projectile p in theWorld.GetProjectiles()) { if (!p.died) { DrawObjectWithTransform(e, p, theWorld.GetSize(), p.location.GetX(), p.location.GetY(), p.orientation.ToAngle(), ProjectileDrawer); } } //Draw tank explosions with tanks in tankTimer List <Tank> tanks = new List <Tank>(tankTimer.Keys); foreach (Tank t in tanks) { DrawObjectWithTransform(e, t, theWorld.GetSize(), t.location.GetX(), t.location.GetY(), 0, ExplosionDrawer); } } } // Do anything that Panel (from which we inherit) needs to do base.OnPaint(e); }
/// <summary> /// Check if a given location is inside of the world /// </summary> /// <param name="loc">Vector2d representing object location</param> /// <returns>True if given vector is in the world, false otherwise</returns> private bool InWorld(Vector2D loc) => - theWorld.Size / 2 <= loc.GetX() && loc.GetX() <= theWorld.Size / 2 && -theWorld.Size / 2 <= loc.GetY() && loc.GetY() <= theWorld.Size / 2;
/// <summary> /// A range check on if object collides with within certain range /// </summary> /// <param name="xmin">x lower bound</param> /// <param name="xmax">x upper bound</param> /// <param name="ymin">y lower bound</param> /// <param name="ymax">y upper bound</param> /// <param name="input">location to check if it is specific range</param> /// <returns></returns> private static bool Collide(double xmin, double xmax, double ymin, double ymax, Vector2D input) => xmin <= input.GetX() && input.GetX() <= xmax && ymin <= input.GetY() && input.GetY() <= ymax;