public static void Main(string[] args) { // set starting stage stageNumber = 0; randomator = new Random(); explosions = new List<Explosion>(); //// build ships // ships = new List<ShipDrone>(); // build secondary ship ShipDrone otherShip = new ShipDrone(VEL, ACC, ROT_VEL, ROT_ACC, SHIP_RADIUS, S_HEALTH, S_LIVES); otherShip.SetProjectile(PROJECTILE_ROF, PROJECTILE_VEL, PROJECTILE_RADIUS, PROJECTILE_MASS, PROJECTILE_DAMAGE); otherShip.Color = new byte[] { 255, 255, 255 }; otherShip.ProjectileColor = new byte[] { 170, 170, 255 }; otherShip.Id = 0; otherShip.SetShip(S0_START_X, S0_START_Y, S0_START_R); ships.Add(otherShip); // build main ship ShipDrone mainShip = new ShipDrone(VEL, ACC, ROT_VEL, ROT_ACC, SHIP_RADIUS, S_HEALTH, S_LIVES); mainShip.SetProjectile(PROJECTILE_ROF, PROJECTILE_VEL, PROJECTILE_RADIUS, PROJECTILE_MASS, PROJECTILE_DAMAGE); mainShip.Color = new byte[] { 255, 255, 255 }; mainShip.ProjectileColor = new byte[] { 255, 255, 0 }; mainShip.Id = 1; myShipID = mainShip.Id; mainShip.SetShip(S1_START_X, S1_START_Y, S1_START_R); ships.Add(mainShip); //// connect to server // connectedToServer = false; tcpConnection = new ClientTCP(); try { if (args.Length < 1) { tcpConnection.ConnectToServer(SERVER_IP_ADDRESS, SERVER_PORT); Console.WriteLine("Connected to server at: " + SERVER_IP_ADDRESS + ":" + SERVER_PORT); } else { tcpConnection.ConnectToServer(args[0], SERVER_PORT); Console.WriteLine("Connected to server at: " + args[0] + ":" + SERVER_PORT); } connectedToServer = true; new GraphicsWindow(tcpConnection); } catch (Exception e) { Console.WriteLine("Unable to connect to server: \n" + e.ToString()); } // send main ship information to server if(connectedToServer) { float[] shipSpecs = mainShip.RenderShip(); tcpConnection.SendMessage("Join: DRONE x: " + shipSpecs[0] + " y: " + shipSpecs[1] + " r: " + shipSpecs[2] + "\n"); } //// Main // using (var game = new GameWindow((int)(1600 / 1.25), (int)(1000 / 1.25))) { game.Load += (sender, e) => { game.VSync = VSyncMode.On; // determine map size mapWidth = TILE_SIZE * TILE_COUNT_WIDTH; mapHeight = TILE_SIZE * TILE_COUNT_HEIGHT; Console.WriteLine("Game started at: " + game.Width + "x" + game.Height + "on a " + mapWidth + "x" + mapHeight + " map."); // collision detection grid collisionGrid = new byte[TILE_COUNT_WIDTH + 1, TILE_COUNT_HEIGHT + 1][]; // set up star field starField = CreateStarField(mapWidth, mapHeight, 1000, mapWidth * 2, mapWidth / 2); //// Graphics // // make background color the color of null space GL.ClearColor(0.1f, 0.1f, 0.1f, 1.0f); // Set background color to black and opaque // load textures droneShipTex = LoadTexture("t_drone_ship1_shadow.png"); explosionTex = LoadTexture("t_explosion1.png"); carrierShipTex = LoadTexture("t_carrier_ship1.png"); starTex = LoadTexture("t_star1.png"); carrierShipUpperTex = LoadTexture("t_carrier_ship1_upper.png"); carrierShipLowerTex = LoadTexture("t_carrier_ship1_lower.png"); number1Tex = LoadTexture("t_1.png"); number2Tex = LoadTexture("t_2.png"); number3Tex = LoadTexture("t_3.png"); loseTex = LoadTexture("t_lose.png"); winTex = LoadTexture("t_win.png"); droneShip2Tex = LoadTexture("t_drone_ship2_shadow.png"); carrierShip2Tex = LoadTexture("t_carrier_ship2.png"); carrierShip2UpperTex = LoadTexture("t_carrier_ship2_upper.png"); carrierShip2LowerTex = LoadTexture("t_carrier_ship2_lower.png"); waitingTex = LoadTexture("t_waiting.png"); countdown = new Countdown(new int[] { number3Tex, number2Tex, number1Tex }, 160, 160); // 160 is dimension of number-pngs in pixels GL.Enable(EnableCap.Texture2D); // enable transparency // ready the text text = new TextRender(new Size(game.Width, game.Height), new Size(300, 100), new Font(FontFamily.GenericMonospace, 15.0f)); text.AddLine("HEALTH " + (int) ((ships[myShipID].Health * 100) / S_HEALTH) + "%", new PointF(10, 10), new SolidBrush(Color.Red)); text.AddLine("LIVES " + ships[myShipID].Lives, new PointF(10, 40), new SolidBrush(Color.Red)); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); // GL.Disable(EnableCap.DepthTest); }; //// Game resize? // game.Resize += (sender, e) => { GL.Viewport(0, 0, game.Width, game.Height); }; //// Physics recalculation and keyboard updates // game.UpdateFrame += (sender, e) => { // collision detection grid collisionGrid = new byte[TILE_COUNT_WIDTH + 1, TILE_COUNT_HEIGHT + 1][]; if (game.Keyboard[Key.Escape]) { if (connectedToServer) { connectedToServer = false; tcpConnection.Shutdown(); tcpConnection = null; } game.Exit(); } if (game.Keyboard[Key.Up]) { if(stageNumber == 1) ships[myShipID].ThrottleOn(); } if (game.Keyboard[Key.Left]) { if (!ships[myShipID].FreezeShipMovement && stageNumber == 1) ships[myShipID].TurnLeft(); } if (game.Keyboard[Key.Right]) { if (!ships[myShipID].FreezeShipMovement && stageNumber == 1) ships[myShipID].TurnRight(); } if (game.Keyboard[Key.Enter]) { if (!ships[myShipID].FreezeShipMovement && stageNumber == 1) ships[myShipID].FireProjectile(); //ships[0].FireShotgun(); } if (game.Keyboard[Key.W]) { if(myShipID == 0) ships[1].ThrottleOn(); else ships[0].ThrottleOn(); } if (game.Keyboard[Key.A]) { if (myShipID == 0) ships[1].TurnLeft(); else ships[0].TurnLeft(); } if (game.Keyboard[Key.D]) { if (myShipID == 0) ships[1].TurnRight(); else ships[0].TurnRight(); } if (game.Keyboard[Key.Space]) { if (myShipID == 0) ships[1].FireProjectile(); else ships[0].FireProjectile(); } if(connectedToServer) mainShip.CalculatePhysics(mapWidth, mapHeight); else foreach (ShipDrone ship in ships) { ship.CalculatePhysics(mapWidth, mapHeight); } foreach (ShipDrone ship in ships) { // if the ship collides with another ship, sometimes they get stuck, have them separate one to // allow them to get unstuck ShipDrone collidedWith = CollisionTest(ship); if (collidedWith != null) { ship.CalculatePhysics(mapWidth, mapHeight); collidedWith.CalculatePhysics(mapWidth, mapHeight); } } // determine if ship is ready to move after respawn if (ships[myShipID].FreezeShipMovement) { float[] xy = ships[myShipID].GetShipPosition(); double distance = Math.Sqrt((xy[0] - ships[myShipID].StartingCoordinates[0]) * (xy[0] - ships[myShipID].StartingCoordinates[0]) + (xy[1] - ships[myShipID].StartingCoordinates[1]) * (xy[1] - ships[myShipID].StartingCoordinates[1])); if (distance > DISTANCE_UNFREEZE) ships[myShipID].FreezeShipMovement = false; } for (int i = 0; i < explosions.Count; i++) { if (!(explosions[i].CalculateStreams())) explosions.RemoveAt(i); } // advance the countdown frame, start the game when ready. if (stageNumber == 0) if (countdown.OneFrame()) stageNumber = 1; // tell server of updates. // specifically of main ship's coordinates and projectiles if(connectedToServer) { //Console.WriteLine("Sending..."); StringBuilder sb = new StringBuilder(); float[] shipSpecs = mainShip.RenderShip(); foreach(float[] projectileSpecs in mainShip.GetNewProjectiles()) { // missing [3], [4], [5] sb.Append(" P: " + projectileSpecs[0] + " " + projectileSpecs[1] + " " + projectileSpecs[2]); } mainShip.ClearNewProjectiles(); tcpConnection.SendMessage("Update: DRONE x: " + shipSpecs[0] + " y: " + shipSpecs[1] + " r: " + shipSpecs[2] + sb.ToString() + "\n"); } }; //// Render game // game.RenderFrame += (sender, e) => { // always begins with GL.Clear() and ends with a call to SwapBuffers GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); GL.MatrixMode(MatrixMode.Projection); GL.LoadIdentity(); // game window follows the ship float[] shipCoord = ships[myShipID].RenderShip(); GL.Ortho(shipCoord[0] - game.Width / 2, shipCoord[0] + game.Width / 2, shipCoord[1] - game.Height / 2, shipCoord[1] + game.Height / 2, -1.0, 0.0); //GL.Ortho(0, game.Width, 0, game.Height, -1.0, 0.0); GL.MatrixMode(MatrixMode.Modelview); //text.Draw(); RenderBackground(mapWidth, mapHeight); foreach (ShipDrone ship in ships) { if (ship.FreezeShipMovement) { //// The main drone ship should be wedged between the top part of the carrier and the carrier's bay // RenderCarrierShip("lower", ship); RenderParticles(ship.RenderShipParticles()); RenderDroneShip(ship.Color, ship); RenderCarrierShip("upper", ship); } else { RenderCarrierShip(ship); } } foreach (ShipDrone ship in ships) { // do not render drone ship if in carrier. Previously rendered. if (!ship.FreezeShipMovement) RenderParticles(ship.RenderShipParticles()); } foreach (ShipDrone ship in ships) { RenderProjectiles(ship.ProjectileColor, ship); // do not render drone ship if in carrier. Previously rendered. if (!ship.FreezeShipMovement) RenderDroneShip(ship.Color, ship); } /*if (ships[myShipID].FreezeShipMovement) { // RenderCollisionGrid(); //// The main drone ship should be wedged between the top part of the carrier and the carrier's bay // RenderCarrierShip("lower", ships[0]); RenderParticles(ships[myShipID].RenderShipParticles()); RenderDroneShip(ships[myShipID].Color, ships[myShipID]); RenderCarrierShip("upper", ships[0]); foreach (ShipDrone ship in ships) { // do not render player's drone ship's exhaust particles, rendered previously if (ship.Id != myShipID) RenderParticles(ship.RenderShipParticles()); RenderParticles(ship.RenderProjectileParticles()); } foreach (ShipDrone ship in ships) { RenderProjectiles(ship.ProjectileColor, ship); // do not render player's drone ship, rendered previously if (ship.Id != myShipID) RenderDroneShip(ship.Color, ship); } } else { RenderCarrierShip(ships[0]); // RenderCollisionGrid(); foreach (ShipDrone ship in ships) { RenderParticles(ship.RenderShipParticles()); RenderParticles(ship.RenderProjectileParticles()); } foreach (ShipDrone ship in ships) { RenderProjectiles(ship.ProjectileColor, ship); RenderDroneShip(ship.Color, ship); } } */ foreach (Explosion explosion in explosions) { RenderParticles(explosion.RenderParticles()); RenderExplosion(explosion.Color, explosion); } // render text, anything drawn after text will be in relation to the screen and not the game grid text.Draw(); if (stageNumber == 0) RenderCountdown(game.Width, game.Height); if (stageNumber == 2) RenderEndScreen(game.Width, game.Height); game.SwapBuffers(); // draw the new matrix }; // Run the game at 60 updates per second game.Run(60.0); } }
/// <summary> /// Used for collision detection. Grid is set up to determine what needs to check for collision. /// </summary> private static ShipDrone CollisionTest(ShipDrone ship) { ShipDrone collidedWith = null; /* * Check ship's collision */ float[] shipCoord = ship.RenderShip(); byte[] colId = AddCollisionBoxes(shipCoord[0], shipCoord[1], (int)shipCoord[3], new byte[] { ship.Id, 0 }); // colId will only be not null if two objects share the same collision box if (colId != null) { // colId[n] = 0 is always a ship. Anything higher would be one of the ship's projectiles. if (colId[1] > 0) { // we will need to determine if a real collision has occurred. We'll need to retrieve the size of the projectile. // get the projectile, since we start projectiles at 1, we need to subtract 1 float[] projectile = ships[colId[0]].GetProjectile(colId[1] - 1); //Console.WriteLine("Possible: Ship hit bullet."); double distance = Math.Sqrt((shipCoord[0] - projectile[0]) * (shipCoord[0] - projectile[0]) + (shipCoord[1] - projectile[1]) * (shipCoord[1] - projectile[1])); if (distance < shipCoord[3] + projectile[3]) { // do not allow ship to collide if still at respawn point if (!(ship.FreezeShipMovement && ship.Id == myShipID)) { //Console.WriteLine("Ship hit bullet."); float[] velShip = ship.GetShipMomentum(); float[] velProjectile = ships[colId[0]].GetProjectileMomentum(colId[1] - 1); float vx = (velShip[0] * (velShip[2] - velProjectile[2]) + 2 * velProjectile[2] * velProjectile[0]) / (velShip[2] + velProjectile[2]); float vy = (velShip[1] * (velShip[2] - velProjectile[2]) + 2 * velProjectile[2] * velProjectile[1]) / (velShip[2] + velProjectile[2]); ship.SetShipVeloctiy(vx, vy); float[] projectileToExplosion = ships[colId[0]].RemoveProjectile(colId[1] - 1); explosions.Add(new Explosion(projectileToExplosion[0], projectileToExplosion[1], projectileToExplosion[2], EXPLOSION_STREAMS, EXPLOSION_SPAN, EXPLOSION_STRENGTH)); // if the main ship has lost all health and should be reset to respawn point if (ship.Id == myShipID) { if (ship.ChangeHealth((-1) * ship.ProjectileDamage)) RespawnShip(); text.RefreshTexture(); text.Update(0, "HEALTH " + (int)((ship.Health * 100) / S_HEALTH) + "%"); text.Update(1, "LIVES " + ship.Lives); } } } } else { //Console.WriteLine("Possible: Ships collided."); float[] otherShipCoord = ships[colId[0]].RenderShip(); double distance = Math.Sqrt((shipCoord[0] - otherShipCoord[0]) * (shipCoord[0] - otherShipCoord[0]) + (shipCoord[1] - otherShipCoord[1]) * (shipCoord[1] - otherShipCoord[1])); if (distance < shipCoord[3] + otherShipCoord[3]) { // do not allow ships to collide if still at respawn point if (!ship.FreezeShipMovement && !ships[colId[0]].FreezeShipMovement) { //Console.WriteLine("Ships collided."); float[] velShip = ship.GetShipMomentum(); float[] velShip2 = ships[colId[0]].GetShipMomentum(); float vx1 = (velShip[0] * (velShip[2] - velShip2[2]) + 2 * velShip2[2] * velShip2[0]) / (velShip[2] + velShip2[2]); float vx2 = (velShip2[0] * (velShip2[2] - velShip[2]) + 2 * velShip[2] * velShip[0]) / (velShip[2] + velShip2[2]); float vy1 = (velShip[1] * (velShip[2] - velShip2[2]) + 2 * velShip2[2] * velShip2[1]) / (velShip[2] + velShip2[2]); float vy2 = (velShip2[1] * (velShip2[2] - velShip[2]) + 2 * velShip[2] * velShip[1]) / (velShip[2] + velShip2[2]); float averageX = (shipCoord[0] + otherShipCoord[0]) / 2; float averageY = (shipCoord[1] + otherShipCoord[1]) / 2; float combinedVel = (float)Math.Sqrt((velShip[0] - velShip2[0]) * (velShip[0] - velShip2[0]) + (velShip[1] - velShip2[1]) * (velShip[1] - velShip2[1])); float angle = (float)(Math.Atan2(shipCoord[0] - otherShipCoord[0], shipCoord[1] - otherShipCoord[1]) * 180 / Math.PI); //Console.WriteLine(combinedVel); Explosion e1 = new Explosion(averageX, averageY, angle + 90, S_EXPLOSION_STREAMS, S_EXPLOSION_SPAN, (combinedVel / 1.4f)); Explosion e2 = new Explosion(averageX, averageY, angle - 90, S_EXPLOSION_STREAMS, S_EXPLOSION_SPAN, (combinedVel / 1.4f)); e1.Color = new byte[] { 255, 220, 150 }; e2.Color = new byte[] { 255, 220, 150 }; explosions.Add(e1); explosions.Add(e2); ship.SetShipVeloctiy(vx1, vy1); ships[colId[0]].SetShipVeloctiy(vx2, vy2); collidedWith = ships[colId[0]]; if (ships[colId[0]].Id == myShipID) { // if the main ship has lost all health and should be reset to respawn point if (ships[colId[0]].ChangeHealth((-1) * combinedVel * MOMENTUM_DAMAGE_RATIO)) RespawnShip(); text.RefreshTexture(); text.Update(0, "HEALTH " + (int)((ships[colId[0]].Health * 100) / S_HEALTH) + "%"); text.Update(1, "LIVES " + ships[colId[0]].Lives); } if (ship.Id == myShipID) { // if the main ship has lost all health and should be reset to respawn point if (ship.ChangeHealth((-1) * combinedVel * MOMENTUM_DAMAGE_RATIO)) RespawnShip(); text.RefreshTexture(); text.Update(0, "HEALTH " + (int)((ship.Health * 100) / S_HEALTH) + "%"); text.Update(1, "LIVES " + ship.Lives); } } } } } /* * Check to make sure ship hasn't collided with edge of screen */ // check width (x) if (shipCoord[0] < 0 || shipCoord[0] > mapWidth) { float[] velShip = ship.GetShipMomentum(); float combinedVel = Math.Abs(velShip[0]); ship.SetShipVeloctiy(-velShip[0], velShip[1]); if (ship.Id == myShipID) { // if the main ship has lost all health and should be reset to respawn point if (ship.ChangeHealth((-1) * combinedVel * MOMENTUM_DAMAGE_RATIO)) RespawnShip(); text.RefreshTexture(); text.Update(0, "HEALTH " + (int)((ship.Health * 100) / S_HEALTH) + "%"); text.Update(1, "LIVES " + ship.Lives); } } // check height (y) if (shipCoord[1] < 0 || shipCoord[1] > mapHeight) { float[] velShip = ship.GetShipMomentum(); float combinedVel = Math.Abs(velShip[1]); ship.SetShipVeloctiy(velShip[0], -velShip[1]); if (ship.Id == myShipID) { // if the main ship has lost all health and should be reset to respawn point if (ship.ChangeHealth((-1) * combinedVel * MOMENTUM_DAMAGE_RATIO)) RespawnShip(); text.RefreshTexture(); text.Update(0, "HEALTH " + (int)((ship.Health * 100) / S_HEALTH) + "%"); text.Update(1, "LIVES " + ship.Lives); } } /* * Test projectile's collision */ List<float[]> projectiles = ship.RenderProjectiles(); for (int i = 0; i < projectiles.Count; i++) { colId = AddCollisionBoxes(projectiles[i][0], projectiles[i][1], (int)projectiles[i][3], new byte[] { ship.Id, (byte)(i + 1) }); if (colId != null) { if (colId[1] > 0) { float[] otherProjectile = ships[colId[0]].GetProjectile(colId[1] - 1); //Console.WriteLine("Possible: Bullets collided."); double distance; if (otherProjectile.Length == 0) distance = 0; else distance = Math.Sqrt((otherProjectile[0] - projectiles[i][0]) * (otherProjectile[0] - projectiles[i][0]) + (otherProjectile[1] - projectiles[i][1]) * (otherProjectile[1] - projectiles[i][1])); if (distance == 0 || distance < otherProjectile[3] + projectiles[i][3]) { ships[colId[0]].RemoveProjectile(colId[1] - 1); float[] projectileToExplosion = ship.RemoveProjectile(i); //Console.WriteLine("Bullets collided."); explosions.Add(new Explosion(projectileToExplosion[0], projectileToExplosion[1], projectileToExplosion[2], P_EXPLOSION_STREAMS, P_EXPLOSION_SPAN, P_EXPLOSION_STRENGTH)); } } else { //Console.WriteLine("Possible: Ship hit with bullet..."); shipCoord = ships[colId[0]].RenderShip(); double distance = Math.Sqrt((shipCoord[0] - projectiles[i][0]) * (shipCoord[0] - projectiles[i][0]) + (shipCoord[1] - projectiles[i][1]) * (shipCoord[1] - projectiles[i][1])); if (distance < shipCoord[3] + projectiles[i][3]) { // do not allow ship to collide if still at respawn point if (!(ships[colId[0]].FreezeShipMovement && ships[colId[0]].Id == myShipID)) { //Console.WriteLine("Ship hit with bullet."); float[] velShip = ships[colId[0]].GetShipMomentum(); float[] velProjectile = ship.GetProjectileMomentum(i); float vx = (velShip[0] * (velShip[2] - velProjectile[2]) + 2 * velProjectile[2] * velProjectile[0]) / (velShip[2] + velProjectile[2]); float vy = (velShip[1] * (velShip[2] - velProjectile[2]) + 2 * velProjectile[2] * velProjectile[1]) / (velShip[2] + velProjectile[2]); ships[colId[0]].SetShipVeloctiy(vx, vy); float[] projectileToExplosion = ship.RemoveProjectile(i); explosions.Add(new Explosion(projectileToExplosion[0], projectileToExplosion[1], projectileToExplosion[2], EXPLOSION_STREAMS, EXPLOSION_SPAN, EXPLOSION_STRENGTH)); if (ships[colId[0]].Id == myShipID) { // if the main ship has lost all health and should be reset to respawn point if (ships[colId[0]].ChangeHealth((-1) * ships[colId[0]].ProjectileDamage)) RespawnShip(); text.RefreshTexture(); text.Update(0, "HEALTH " + (int)((ships[colId[0]].Health * 100) / S_HEALTH) + "%"); text.Update(1, "LIVES " + ships[colId[0]].Lives); } // test health level //if (ships[colId[0]].Id == myShipID) // Console.WriteLine("Health3: " + ships[colId[0]].Health); } } } } } return collidedWith; }
/// <summary> /// Renders a given ship. The ship takes on the color given in the parameter. /// </summary> private static void RenderDroneShip(byte[] color, ShipDrone ship) { float[] shipPosition = ship.RenderShip(); GL.LoadIdentity(); GL.Translate(shipPosition[0], shipPosition[1], 0.0f); GL.Rotate(shipPosition[2], 0.0f, 0.0f, 1.0f); // texture GL.Color3(color); if(ship.Id == 0) GL.BindTexture(TextureTarget.Texture2D, droneShipTex); if(ship.Id == 1) GL.BindTexture(TextureTarget.Texture2D, droneShip2Tex); GL.Begin(PrimitiveType.Quads); //GL.Color3(color); //Top-Right GL.TexCoord2(0, 0); GL.Vertex2(-32.5f, 25f); //Top-Left GL.TexCoord2(1, 0); GL.Vertex2(32.5f, 25f); //Bottom-Left GL.TexCoord2(1, 1); GL.Vertex2(32.5f, -25f); //Bottom-Right GL.TexCoord2(0, 1); GL.Vertex2(-32.5f, -25f); GL.End(); // remove texture GL.BindTexture(TextureTarget.Texture2D, 0); }