// Sends information about the current game state to the players // resendTimeout is how long to wait until sending another GameStatePacket private void _sendGameState(PlayerInfo player, TimeSpan resendTimeout) { if (DateTime.Now >= (player.LastPacketSentTime.Add(resendTimeout))) { // Set the data GameStatePacket gsp = new GameStatePacket(); gsp.LeftY = LeftPlayer.Paddle.Position.Y; gsp.RightY = RightPlayer.Paddle.Position.Y; gsp.BallPosition = _ball.Position; gsp.LeftScore = LeftPlayer.Paddle.Score; gsp.RightScore = RightPlayer.Paddle.Score; _sendTo(player, gsp); } }
protected override void Update(GameTime gameTime) { // Check for close KeyboardState kbs = Keyboard.GetState(); if (kbs.IsKeyDown(Keys.Escape)) { // Player wants to quit, send a ByePacket (if we're connected) if ((_state == ClientState.EstablishingConnection) || (_state == ClientState.WaitingForGameStart) || (_state == ClientState.InGame)) { // Will trigger the network thread to send the Bye Packet _sendBye.Value = true; } // Will stop the network thread _running.Value = false; _state = ClientState.GameOver; Exit(); } // Check for time out with the server if (_timedOut()) { _state = ClientState.GameOver; } // Get message NetworkMessage message; bool haveMsg = _incomingMessages.TryDequeue(out message); // Check for Bye From server if (haveMsg && (message.Packet.Type == PacketType.Bye)) { // Shutdown the network thread (not needed anymore) _running.Value = false; _state = ClientState.GameOver; } switch (_state) { case ClientState.EstablishingConnection: _sendRequestJoin(TimeSpan.FromSeconds(1)); if (haveMsg) { _handleConnectionSetupResponse(message.Packet); } break; case ClientState.WaitingForGameStart: // Send a heartbeat _sendHeartbeat(TimeSpan.FromSeconds(0.2)); if (haveMsg) { switch (message.Packet.Type) { case PacketType.AcceptJoin: // It's possible that they didn't receive our ACK in the previous state _sendAcceptJoinAck(); break; case PacketType.HeartbeatAck: // Record ACK times _lastPacketReceivedTime = message.ReceiveTime; if (message.Packet.Timestamp > _lastPacketReceivedTimestamp) { _lastPacketReceivedTimestamp = message.Packet.Timestamp; } break; case PacketType.GameStart: // Start the game and ACK it _sendGameStartAck(); _state = ClientState.InGame; break; } } break; case ClientState.InGame: // Send a heartbeat _sendHeartbeat(TimeSpan.FromSeconds(0.2)); // update our paddle _previousY = _ourPaddle.Position.Y; _ourPaddle.ClientSideUpdate(gameTime); _sendPaddlePosition(_sendPaddlePositionTimeout); if (haveMsg) { switch (message.Packet.Type) { case PacketType.GameStart: // It's possible the server didn't receive our ACK in the previous state _sendGameStartAck(); break; case PacketType.HeartbeatAck: // Record ACK times _lastPacketReceivedTime = message.ReceiveTime; if (message.Packet.Timestamp > _lastPacketReceivedTimestamp) { _lastPacketReceivedTimestamp = message.Packet.Timestamp; } break; case PacketType.GameState: // Update the gamestate, make sure its the latest if (message.Packet.Timestamp > _lastPacketReceivedTimestamp) { _lastPacketReceivedTimestamp = message.Packet.Timestamp; GameStatePacket gsp = new GameStatePacket(message.Packet.GetBytes()); _left.Score = gsp.LeftScore; _right.Score = gsp.RightScore; _ball.Position = gsp.BallPosition; // Update what's not our paddle if (_ourPaddle.Side == PaddleSide.Left) { _right.Position.Y = gsp.RightY; } else { _left.Position.Y = gsp.LeftY; } } break; case PacketType.PlaySoundEffect: #if CAN_PLAY_SOUNDS // Play a sound PlaySoundEffectPacket psep = new PlaySoundEffectPacket(message.Packet.GetBytes()); if (psep.SFXName == "ball-hit") { _ballHitSFX.Play(); } else if (psep.SFXName == "score") { _scoreSFX.Play(); } #endif break; } } break; case ClientState.GameOver: // Purgatory is here break; } base.Update(gameTime); }