我想知道是否有人知道任何与OpenGL集成的网络代码示例。
基本上,我需要通过网络将某些东西的位置坐标发送到我的OpenGL显示器......然后将对象绘制到正确的位置。
我遇到的问题是将我的UDP代码与游戏集成。我基本上有一个不断更新/绘制的循环。我原本以为我可以在单独的线程中使用UDP代码并只更新共享坐标。但是,如果我的绘制函数在网络代码写入新位置之前读取位置,那么我有一个竞争条件和无效数据...但是我不能使更新或绘制循环块...
我不确定我是否应该在这里使用同步或异步网络代码。
那么,关于如何解决这个问题的任何提示?感谢
答案 0 :(得分:10)
我认为你的游戏是实时的,因为你写的是你使用UDP,而你没有说过。这个问题的一般解决方案是:
实施客户预测。
缓冲可以提高稳定性,因为模拟总是会滞后于您收到的数据。这样,您将永远不会耗尽用于接收端仿真的数据。这种自然结果是潜伏期略有增加。使用良好的启发式(适当大小的缓冲区),模拟将永远不会赶上缓冲区,即同步永远不会阻塞,除非通信通道本身在较长时间内变得不稳定。这可能是可用带宽的突然变化,数据包丢失,延迟严重增加等。您还可以使用同步原语来阻止超时,例如1 ms。当发生超时时,您可以使用外推而不是插值(见下文),放弃一起更新缺失状态并仅更新客户端预测处理的内容(如果有),或拒绝更新任何内容,直到您与偏远的一面。
您的模拟应以恒定频率进行采样。通过将模拟与渲染分离,您可以以比模拟采样更高的频率进行渲染。例如,您的模拟可以以30 fps的速度运行,但您仍可以以图形卡允许的速度进行渲染,例如300 fps。这意味着您需要通过网络发送更少的数据,但不会牺牲动画质量。
在两个样本之间平滑插值,而不是将数据视为绝对数据。例如可以是游戏中的玩家位置。如果您使用矢量直接移动或捕捉玩家位置,则需要一些非常高的采样频率,这会淹没您的网络。通过分别在两点或三点之间使用线性或三次插值,可以获得平滑的运动,但采样点非常少。这当然需要指向插入到,所以它会增加一个增量时间的延迟,即你的时间步长。
编辑:好的,那么这些概念与您的问题直接相关?你的问题是一个设计问题;您只需将数据直接输入到模拟中,并在它们到达线路时进行渲染。使用wait()
函数超时的互斥锁,可以修复阻塞问题,但不能解决数据不足问题。 某些延迟优于频繁超时。这就是为什么我建议实现缓冲,并将带宽使用量降低到理智水平。
只发送所需的数据,以获得足够好的结果。
有关游戏网络理论的优秀见解,请访问Glenn Fiedler博客上的文章:
Gaffer on games : networking for game-programmers
Gaffer on games : game-physics
答案 1 :(得分:2)
在单独的线程中运行网络,在新数据到达时设置标志(原子写入)并在更新/绘制中检查,然后仅进行同步。然后,您可以使用互斥锁作为共享数据。
同步部分可能与代码的其余部分相比非常高效,因此它不会对绘制循环产生太大影响。
答案 2 :(得分:2)
对于这样做的真实游戏的例子,您当然可以浏览一些合适的Quake源代码。 Quake 3 Arena使用OpenGL,并为其多人游戏使用UDP网络。
答案 3 :(得分:1)
Mads的建议非常好,所以我只想补充一下。沿着插值的方向,使用客户端预测是非常有价值的。同步位置和速度(以及可选的加速度)而不仅仅是位置。作为额外的改进,当更新到达时指示当前位置出错时,在几帧内插入到新的正确位置而不是直接捕捉到它。
这样,即使服务器更新很少,客户端也可以继续预测对象位置。如果您的对象移动顺畅,那么这可以很好地工作。这是大多数多层游戏使用的方法。每秒只能进行几次更新(以节省带宽),并且可以处理可变的网络延迟。