/// <summary> /// Sets Tank rotation increment given current input state. /// </summary> /// <param name="input">Player input.</param> /// <param name="tank">Player tank.</param> private void SetRotInc(AbstractInput input, Tank tank) { // check rotation if (input.Rotate) { // stop the tank // (player can't rotate AND translate at once) tank.XSpeed = tank.YSpeed = tank.RotIncrement = 0; // rotate clockwise if (input.Rotate && (input.Right || input.Down)) { tank.RotIncrement = Tank.RotInc; } // rotate counterclockwise else if (input.Rotate && (input.Left || input.Up)) { tank.RotIncrement = -Tank.RotInc; } } // not rotating, so must be translating else { // not rotating, reset rotation increment tank.RotIncrement = 0; } }
///////////////////////////////////////////////////////////////////////////// // Player keyboard controls // NOTE: If one GamePad is connected, the keyboard controls are disabled // for player 1. If two GamePads are connected, both keyboard controls // are disabled. // General Game controls: P - pause game // Escape - quit game // N - new game // // Player 1 controls: Arrow keys - translational movement // Right-ctrl + Arrow key - rotate tank (can't translate) // Enter - fire // '/' key: switch weapon // Player 2 controls: WASD - translation movement // Left-shift + WASD key - rotate tank (can't translate) // Space - fire // Q key - switch weapon ///////////////////////////////////////////////////////////////////////////// /// <summary> /// Checks key up states, and /// applies input processing for the appropriate player. /// </summary> private void MainGame_KeyUp(object sender, KeyEventArgs e) { // send key up event to static input check AbstractInput.SetStaticInput(e); // don't do anything if the game is paused // (i.e. only static input is read from the keyboard while paused) if (_bGamePaused) { return; } // take a snapshot of the player inputs list List <AbstractInput> inputSnapshot; lock (_oInputLock) { inputSnapshot = new List <AbstractInput>(_lPlayerInputs); } // send key up event to each player input foreach (AbstractInput ab in inputSnapshot) { ab.SetKeyUpInput(e); } // update the player inputs list lock (_oInputLock) { _lPlayerInputs = new List <AbstractInput>(inputSnapshot); } }
/// <summary> /// Checks for fire input, and fires the player's gun /// </summary> /// <param name="input">Player input.</param> /// <param name="thisPlayer">Player data.</param> /// <param name="tank">Player tank.</param> /// <param name="movingShapes">Collection of moving shapes.</param> private void SetFireWeapon(AbstractInput input, PlayerData thisPlayer, Tank tank, List <DynamicShape> movingShapes) { if (input.Fire) { // check if not reloading if (thisPlayer.CheckReload()) { // get gunshot color (white by default) Color shotColor = Color.White; switch (thisPlayer.Player) { case PlayerNumber.One: switch (thisPlayer.CurrentWeapon) { case GunType.MachineGun: shotColor = _cPlayer1MGColor; break; case GunType.Rocket: shotColor = _cPlayer1RocketColor; break; } break; case PlayerNumber.Two: switch (thisPlayer.CurrentWeapon) { case GunType.MachineGun: shotColor = _cPlayer2MGColor; break; case GunType.Rocket: shotColor = _cPlayer2RocketColor; break; } break; } // get a new gunshot Gunfire newShot = new Gunfire(tank.Position, tank.Rotation, thisPlayer.CurrentWeapon, shotColor, thisPlayer.Player); // start reloading timer thisPlayer.StartReloading(); //add new gunshot it to the list of moving shapes movingShapes.Add(newShot); } } }
/// <summary> /// Initializes main form members. /// </summary> private void InitializeMembers(string XMLValue) { // initialize the level _lvGameLevel = new Level(XMLValue); // reset pause flag _bGamePaused = false; // initialize players PlayerData p1 = new PlayerData(PlayerNumber.One); PlayerData p2 = new PlayerData(PlayerNumber.Two); // initialize abstract inputs AbstractInput a1 = new AbstractInput(PlayerNumber.One); AbstractInput a2 = new AbstractInput(PlayerNumber.Two); // tank 1 starts at a random spawn point PointF startP1 = _lvGameLevel._respawnPoints[_rng.Next(0, _lvGameLevel._respawnPoints.Count)]; // tank 2 starts as far from player 1 as possible PointF startP2 = GetFurthestSpawn(startP1); // initialize the tanks Tank t1 = new Tank(startP1, _cPlayer1Color, PlayerNumber.One); Tank t2 = new Tank(startP2, _cPlayer2Color, PlayerNumber.Two); // add inputs to input list _lPlayerInputs = new List <AbstractInput> { a1, a2 }; // add player data to data list _lPlayerData = new List <PlayerData> { p1, p2 }; // add tank shapes to dynamic shape list _lDynShapes = new List <DynamicShape> { t1, t2 }; // make wall list a copy of the level's walls _lWalls = new List <Wall>(_lvGameLevel.Walls); // make ammo drops a copy of the level's ammo drops _lAmmoDrops = new List <Ammo>(_lvGameLevel._ammoDrops); // start background input processing thread _tBackgroundProcessing = new Thread(TBackground); }
/// <summary> /// Checks current input state, and switches weapon if necessary. /// </summary> /// <param name="input">Player input.</param> /// <param name="thisPlayer">Player data.</param> private void SetSwitchWeapon(AbstractInput input, PlayerData thisPlayer) { // Check weapon select if (input.SwitchWeapon) { // switch to the next weapon thisPlayer.SwitchWeapon(); // issue callback to highlight weapon icon in game UI _modelessUI.Invoke(new GameUI.delVoidSwitchWeapon(_modelessUI.CBSwitchWeapon), input.Player, thisPlayer.CurrentWeapon); // signal the abstract input to reset the SwitchWeapon flag input.ResetSwitchWeapon(); } }
/// <summary> /// Sets Tank X and Y speeds based on current input. /// </summary> /// <param name="input"> /// Player input. /// </param> /// <param name="tank"> /// Player tank. /// </param> private void SetTranslation(AbstractInput input, Tank tank) { // can't translate during rotations if (input.Rotate) { return; } // check up AND down if (input.Up && input.Down) { // trigger motor interlock tank.YSpeed = 0; } // check up OR down else { // moving straight up if (input.Up && !(input.Left || input.Right)) { tank.YSpeed = -Tank.Speed; } // moving straight down else if (input.Down && !(input.Left || input.Right)) { tank.YSpeed = Tank.Speed; } // moving up diagonally else if (input.Up && (input.Left || input.Right)) { double angle = 45 * Math.PI / 180; tank.YSpeed = -(float)Math.Sqrt(Math.Pow(Tank.Speed, 2) - Math.Pow(Tank.Speed * Math.Sin(angle), 2)); } // moving down diagonally else if (input.Down && (input.Left || input.Right)) { double angle = 45 * Math.PI / 180; tank.YSpeed = (float)Math.Sqrt(Math.Pow(Tank.Speed, 2) - Math.Pow(Tank.Speed * Math.Sin(angle), 2)); } // no vertical movement input else { tank.YSpeed = 0; } } // Check left AND right if (input.Right && input.Left) { // trigger motor interlock tank.XSpeed = 0; } // Check left OR right else { // moving straight right if (input.Right && !(input.Up || input.Down)) { tank.XSpeed = Tank.Speed; } // moving straight left else if (input.Left && !(input.Up || input.Down)) { tank.XSpeed = -Tank.Speed; } // moving right diagonally else if (input.Right && (input.Up || input.Down)) { double angle = 45 * Math.PI / 180; tank.XSpeed = (float)Math.Sqrt(Math.Pow(Tank.Speed, 2) - Math.Pow(Tank.Speed * Math.Cos(angle), 2)); } // moving left diagonally else if (input.Left && (input.Up || input.Down)) { double angle = 45 * Math.PI / 180; tank.XSpeed = -(float)Math.Sqrt(Math.Pow(Tank.Speed, 2) - Math.Pow(Tank.Speed * Math.Cos(angle), 2)); } // no horizontal movement input else { tank.XSpeed = 0; } } }
/// <summary> /// Checks input field values, and /// updates Tank properties accordingly. /// </summary> /// <param name="input"> /// Player input. /// </param> private void ApplyInput(AbstractInput input) { // player tank and data locals Tank tank; PlayerData thisPlayer; // copy moving shape and player data collections List <DynamicShape> movingShapesSnapshot; List <PlayerData> playerListSnapshot; lock (_oRenderLock) { movingShapesSnapshot = new List <DynamicShape>(_lDynShapes); playerListSnapshot = new List <PlayerData>(_lPlayerData); } // get tank and player data tank = movingShapesSnapshot.Find(dn => dn is Tank && dn.Player == input.Player) as Tank; thisPlayer = playerListSnapshot.Find(p => p.Player == input.Player); // check rotation SetRotInc(input, tank); // check translation SetTranslation(input, tank); // Check weapon select SetSwitchWeapon(input, thisPlayer); // Check fire cannon SetFireWeapon(input, thisPlayer, tank, movingShapesSnapshot); // update moving shape list lock (_oRenderLock) { _lDynShapes = new List <DynamicShape>(movingShapesSnapshot); } // Check for pause if (AbstractInput.Pause) { // set pause flag _bGamePaused = true; } // pause flag is false -- unpause the game else { _bGamePaused = false; } // check quit game if (AbstractInput.Quit) { // shutdown the game Application.Exit(); // kill thread to prevent it from // accessing the graphics as it's being disposed of _tBackgroundProcessing.Abort(); } // check new game if (AbstractInput.NewGame) { Application.Restart(); _tBackgroundProcessing.Abort(); } }