多人游戏 - 客户端插值计算?

Tas*_*ons 24 javascript algorithm multiplayer

我正在使用javascript中的socket io创建一个多人游戏.除了客户端插值之外,游戏目前完美无缺.现在,当我从服务器获取数据包时,我只需将客户端位置设置为服务器发送的位置.这是我试图做的:

getServerInfo(packet) {
     var otherPlayer = players[packet.id]; // GET PLAYER
     otherPlayer.setTarget(packet.x, packet.y); // SET TARGET TO MOVE TO
     ...
}
Run Code Online (Sandbox Code Playgroud)

所以我设置了球员的目标位置.然后在Players Update方法中,我只是这样做:

var update = function(delta) {
    if (x != target.x || y != target.y){
        var direction = Math.atan2((target.y - y), (target.x - x));
        x += (delta* speed) * Math.cos(direction);
        y += (delta* speed) * Math.sin(direction);
        var dist = Math.sqrt((x - target.x) * (x - target.x) + (y - target.y)
                * (y - target.y));
        if (dist < treshhold){
            x = target.x;
            y = target.y;
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

这基本上使玩家以固定速度朝目标方向移动.问题是玩家在下一个信息从服务器到达之前或之后到达目标.

编辑:我刚读过关于这个主题的Gabriel Bambettas 文章,他提到了这个:

假设你在t = 1000时收到位置数据.你已经在t = 900时收到了数据,所以你知道玩家在t = 900和t = 1000的位置.所以,从t = 1000和t = 1100,你会看到什么另一个玩家从t = 900到t = 1000.这样你总是会显示用户的实际移动数据,除非你显示100毫秒"迟到".

这再次假设它正好晚了100毫秒.如果您的ping变化很大,这将无法正常工作.

你能提供一些伪代码,这样我就可以了解如何做到这一点吗?

我在网上发现了这个问题在这里.但是没有一个答案提供了如何做到的例子,只提供了建议.

Lam*_*ell 8

我对多人游戏客户端/服务器架构和算法完全不满意,但在阅读这个问题时,首先想到的是对每个玩家的相关变量实施二阶(或更高)卡尔曼滤波器.

具体而言,卡尔曼预测步骤比简单的航位推算要好得多.此外,卡尔曼预测和更新步骤在某种程度上作为加权或最佳插值器工作.而且,玩家的动态可以直接编码,而不是使用其他方法中使用的抽象参数化.

同时,快速搜索引导我:

利用卡尔曼滤波器最小化三维在线游戏网络流量的航位推算算法的改进

摘要:

在线3D游戏需要通过网络提供高效且快速的用户交互支持,并且通常使用网络游戏引擎来实现网络支持.网络游戏引擎应该最小化网络延迟并减轻网络流量拥塞.为了最小化游戏用户之间的网络流量,使用基于客户端的预测(航位推算算法).每个游戏实体使用该算法来估计其自身的移动(也是其他实体的移动),并且当估计误差超过阈值时,实体将UPDATE(包括位置,速度等)分组发送到其他实体.随着估计准确度的增加,每个实体可以最小化UPDATE分组的传输.为提高航位推算算法的预测精度,我们提出了基于卡尔曼滤波器的航位推算方法.为了展示真实的演示,我们使用流行的网络游戏(BZFlag),并使用卡尔曼滤波器改进游戏优化的航位推算算法.我们提高预测准确性并将网络流量减少12%.

可能看起来很罗嗦,并且像一个全新的问题,可以了解它的全部内容......以及离散的状态空间.

简而言之,我会说卡尔曼滤波器是一个考虑到不确定性的滤波器,这就是你在这里得到的.它通常用于已知采样率下的测量不确定度,但可以重新调整以适应测量周期/相位的不确定性.

这个想法是代替适当的测量,你只需要用卡尔曼预测进行更新.策略类似于目标跟踪应用程序.

我自己在stackexchange上推荐了他们 - 花了大约一个星期来弄清楚它们是如何相关的,但我已经成功地在视觉处理工作中实现了它们.

(...它让我想现在试验你的问题!)

由于我想要更直接地控制过滤器,我将其他人在matlab中自己实现的卡尔曼滤波器复制到openCV(在C++中):

void Marker::kalmanPredict(){

    //Prediction for state vector 
    Xx = A * Xx;
    Xy = A * Xy;
    //and covariance
    Px = A * Px * A.t() + Q;
    Py = A * Py * A.t() + Q;
}

void Marker::kalmanUpdate(Point2d& measuredPosition){

    //Kalman gain K:
    Mat tempINVx = Mat(2, 2, CV_64F);
    Mat tempINVy = Mat(2, 2, CV_64F);
    tempINVx = C*Px*C.t() + R;
    tempINVy = C*Py*C.t() + R;
    Kx = Px*C.t() * tempINVx.inv(DECOMP_CHOLESKY);
    Ky = Py*C.t() * tempINVy.inv(DECOMP_CHOLESKY);

    //Estimate of velocity
    //units are pixels.s^-1
    Point2d measuredVelocity = Point2d(measuredPosition.x - Xx.at<double>(0), measuredPosition.y - Xy.at<double>(0));  
    Mat zx = (Mat_<double>(2,1) << measuredPosition.x, measuredVelocity.x);
    Mat zy = (Mat_<double>(2,1) << measuredPosition.y, measuredVelocity.y);

    //kalman correction based on position measurement and velocity estimate:
    Xx = Xx + Kx*(zx - C*Xx);
    Xy = Xy + Ky*(zy - C*Xy);
    //and covariance again
    Px = Px - Kx*C*Px;
    Py = Py - Ky*C*Py;
}
Run Code Online (Sandbox Code Playgroud)

我不希望你能直接使用它,但如果有人遇到它并理解'A','P','Q'和'C'在状态空间(提示提示,状态 - 空间理解是这里的预先要求)他们可能会看到如何连接点.

(matlab和openCV都有自己的卡尔曼滤波器实现方式......)

  • @TastyLemons小心,不要让问题陈述的简单性损害解决方案!:)尽管我同意,这需要一些学习和概念上的理解(大部分情况下是关于状态空间的),但这似乎是技术的作用所在。我最终实现的相关算法部分(在openCV中)只有30行左右。 (2认同)