C# 客户端预测问题

C# 客户端预测问题,c#,networking,xna,C#,Networking,Xna,我正在尝试实现一个客户端预测和服务器协调的示例,如果有更好的方法,请让我知道!我试图隐藏网络游戏的延迟。目前,我正在为客户端使用lidgren和XNA,而为服务器使用一个控制台应用程序。我将服务器端的lidgren设置为模拟1.5秒的延迟。因此,当我运行这段代码时,它在很大程度上是有效的,但是客户端似乎正在缓冲移动,然后最终在屏幕上移动角色,但是根据我下面引用的演示,我没有看到缓冲类型的行为,我只是在问它可能是什么?提前感谢你们能提供的任何帮助,如果你需要更多的代码,请告诉我我不想在文章中充斥太

我正在尝试实现一个客户端预测和服务器协调的示例,如果有更好的方法,请让我知道!我试图隐藏网络游戏的延迟。目前,我正在为客户端使用lidgren和XNA,而为服务器使用一个控制台应用程序。我将服务器端的lidgren设置为模拟1.5秒的延迟。因此,当我运行这段代码时,它在很大程度上是有效的,但是客户端似乎正在缓冲移动,然后最终在屏幕上移动角色,但是根据我下面引用的演示,我没有看到缓冲类型的行为,我只是在问它可能是什么?提前感谢你们能提供的任何帮助,如果你需要更多的代码,请告诉我我不想在文章中充斥太多

在SendMovement方法中,我接受用户输入并序列化一个命令以发送到服务器,它将继续移动播放器并将move命令存储在队列中

    private Queue<MovementCommand> _previousMovements = new Queue<MovementCommand>(5000);

    public void SendMovement(float elapsed, byte direction)
    {
        MovementCommand movement = new MovementCommand(_id, _sequenceNumber++, elapsed, direction);

        OutputCommand<MovementCommand> moveCommand = new OutputCommand<MovementCommand>(GamePacketTypes.Movement, movement);

        byte[] msgData = moveCommand.Serialize();

        Send(msgData);

        Console.WriteLine(string.Format("Elapsed Time = {0}, Sequence # = {1}", elapsed, _sequenceNumber));

        if (_clientSidePrediction == true)
        {
            _player.Move(movement);

            _previousMovements.Enqueue(movement);

        }
    }
}

Client.prototype.processServerMessages=function(){
while(true){
var message=this.network.receive();
如果(!消息){
打破
}
//世界国家是实体国家的列表。
对于(变量i=0;i

我不太懂C#,但在
HandleMessages()
的最内层循环中,您使用的是
Dequeue()
在两个分支中,您在其中一个分支中增加了
j
——我感觉这不正确。您可能希望在服务器更新后重新应用输入几次。

我尝试向您的页面添加链接,但它也不允许我这样做。
    public void HandleMessages()
    {
        while (true)
        {
            if (mIncomingMessages.Count > 0)
            {
                for (int i = 0; i < mIncomingMessages.Count; i++)
                {
                    byte command = mIncomingMessages[i].ReadByte();


                    switch ((GamePacketTypes)command)
                    {
                        case GamePacketTypes.UpdateEntity:


                            EntityStateType stateObj = EntityStateType.Deserialize(mIncomingMessages[i].ReadBytes(mIncomingMessages[i].LengthBytes - 1));

                            _player.Position(stateObj);


                            if (_serverReconciliation == true)
                            {
                                if (stateObj.ID == _id)
                                {
                                    int j = 0;

                                    while (j < _previousMovements.Count)
                                    {
                                        MovementCommand move = _previousMovements.Peek();

                                        if (move.InputSequence <= stateObj.LastProcessedInput)
                                        {
                                            _previousMovements.Dequeue();
                                        }
                                        else
                                        {
                                            _player.Move(_previousMovements.Dequeue());
                                            j++;
                                        }

                                    }
                                }
                            }

                            break;

                    }

                }

                mIncomingMessages.Clear();
            }

            Thread.Sleep(25);
        }
    }
    private async Task<bool> HandleMovement(MovementCommand move)
    {
        switch((DirectionHeading)move.Direction)
        {
            case DirectionHeading.North:
                _player.Y -= (move.PressedTime * _player.Velocity);
                break;
            case DirectionHeading.East:
                _player.X += (move.PressedTime * _player.Velocity);
                break;
            case DirectionHeading.South:
                _player.Y += (move.PressedTime * _player.Velocity);
                break;
            case DirectionHeading.West:
                _player.X -= (move.PressedTime * _player.Velocity);

                break;

        }
        _player.Direction = move.Direction;
        LastProcessedInput = move.InputSequence;
        Console.WriteLine("Last Processed Input = {0}", LastProcessedInput);
        return true;
    }
// Get inputs and send them to the server.
// If enabled, do client-side prediction.
Client.prototype.processInputs = function() {
// Compute delta time since last update.
var now_ts = +new Date();
var last_ts = this.last_ts || now_ts;
var dt_sec = (now_ts - last_ts) / 1000.0;
this.last_ts = now_ts;

// Package player's input.
var input;
if (this.key_right) {
  input = { press_time: dt_sec };
} else if (this.key_left) {
  input = { press_time: -dt_sec };
} else {
  // Nothing interesting happened.
  return;
}

// Send the input to the server.
input.input_sequence_number = this.input_sequence_number++;
input.entity_id = this.entity_id;
this.server.network.send(client_server_lag, input);

// Do client-side prediction.
if (client_side_prediction) {
  this.entity.applyInput(input);
}

// Save this input for later reconciliation.
this.pending_inputs.push(input);
}


Server.prototype.processInputs = function() {
// Process all pending messages from clients.
while (true) {
var message = this.network.receive();
if (!message) {
  break;
}

// Update the state of the entity, based on its input.
// We just ignore inputs that don't look valid; this is what prevents
// clients from cheating.
if (this.validateInput(message)) {
  var id = message.entity_id;
  this.entities[id].applyInput(message);
  this.last_processed_input[id] = message.input_sequence_number;
 }
}
Client.prototype.processServerMessages = function() {
while (true) {
var message = this.network.receive();
if (!message) {
  break;
}

// World state is a list of entity states.
for (var i = 0; i < message.length; i++) {
  var state = message[i];

  if (state.entity_id == this.entity_id) {
    // Got the position of this client's entity.

    if (!this.entity) {
      // If this is the first server update, create a local entity.
      this.entity = new Entity();
    }

    // Set the position sent by the server.
    this.entity.x = state.position;

    if (server_reconciliation) {
      // Server Reconciliation. Re-apply all the inputs not yet processed by
      // the server.
      var j = 0;
      while (j < this.pending_inputs.length) {
        var input = this.pending_inputs[j];
        if (input.input_sequence_number <= state.last_processed_input) {
          // Already processed. Its effect is already taken into account
          // into the world update we just got, so we can drop it.
          this.pending_inputs.splice(j, 1);
        } else {
          // Not processed by the server yet. Re-apply it.
          this.entity.applyInput(input);
          j++;
        }
      }
    } else {
      // Reconciliation is disabled, so drop all the saved inputs.
      this.pending_inputs = [];
    }
  } else {
    // TO DO: add support for rendering other entities.
  }
}
}