2013-08-07 107 views
-1

我有一个关于编程网络游戏上的客户端/服务器通信的一般问题。 我使用TCP作为协议,并且通信...有效,但我不确定,如果这是一种有效的方式。GAMEPROGRAMMING通过....进行客户端/服务器通信? (JAVA)

在一般情况下,在客户端所发生的行为会throught所有这些步骤:(例如火球正投)

  1. 一些行动
  2. [*]对于这个动作我定义了一个字符串(例如#F#270#130#,这意味着'F'表示它是一个火球,270是(例如)角度,130 - 火球的速度是射击。)
  3. 字符串进入客户端的输出缓冲器&等待队列
  4. 字符串被发送
  5. 字符串被服务器接收
  6. [*]服务器需要一个可以检测字符串含义的行解释器(这里:什么意思是F?这是一个火球!)&增加了一个唯一的身份,基于,从哪个客户端收到命令。
  7. [*]服务器需要根据发生的动作计算逻辑(火球对别人造成伤害,是否立即触及某人或立即飞行)
  8. 服务器发送一个(更新的)字符串所有客户都会采取的行动。 (例如,也许火球速度由于某种原因减速 - 这里将是一个更新的字符串(#F#12345#270#90# - 12345是唯一的玩家身份)
  9. 客户端接收字符串
  10. [* * ]客户端将字符串解析为命令+处理它(触发动画序列...)
  11. originaly发送命令的客户端将收到的字符串与等待队列中的字符串进行比较 - 当相等时,不执行任何操作(平滑某些操作,否则通过连接问题/延迟,一些动作会发生两次或跳转从一个位置到另一个位置,基于ping

真的有必要通过所有t这些步骤?在所有标有[*]的步骤中,我需要为每个命令定义新的行解释器/操作,因此我将每个操作编码两次,客户端为&服务器端。 我读了一些关于发送可序列化对象的东西,但在genereal中,这个想法对我来说似乎是一样的,我发送一个对象,该对象必须被解释+处理,并且我发回一个对象...

任何提示?为了解决整个沟通更优雅,用更少的代码?或略偏分类 - 所有这些#楼##男寻找不同的动作##^h#标签使它越来越复杂:)

(其实我确实有如下处理/操作:

- 移动 -Look /旋转 -hpchange -firearrow -spawn /断开 ...)

希望你明白我的意思 - 我知道,我可能只是继续编码一样的是,它会以某种方式工作,但它似乎太复杂了,因为它可能是。

谢谢!

+0

还有更多:)字符串被发送,字节被转移到服务器,字符串被服务器接收,其他100个步骤你没有提到 – Tala

回答

0

在决定游戏是否需要更改之前,您需要先看几个因素。

首先,TCP是最好的通信渠道吗?你有没有比较它与UDP。使用UDP实现网络会更好吗?如果有几个数据包丢失了,它会影响吗?如果网络速度慢,会发生什么?

其次,看你投票/推送到服务器的频率。这可以减少吗?游戏是否必须实时进行?游戏的所有部分都必须实时进行。也许某些事情可能是非实时的。火球会继续沿着直线前进,所以你不必更新服务器的位置,你可以直接告诉它的方向和速度。游戏的其他方面可能不是实时的。唯一需要发送的是玩家位置和动作。大多数其他事情,如碰撞检测可以卸载到客户端。

第三,每个按键都需要发送到服务器吗?如果用户靠墙并希望进一步移动,则客户端知道他们不能,因此不会将这些按键发送到服务器。如果用户已移至新的有效位置,请更新服务器。某些事情可以一次性缓冲并发送到服务器,而不是向服务器发送多个查询。也就是说,如果我向前迈进,跳起并投掷一个火球,这就是客户端的3个按键,它们能够在下一个500毫秒被缓冲并发送出去吗?

如果您担心网络开销,您应该在位级别工作。发送长度为11个字节的长字符串“#F#270#130#”而不是发送3个连续字节(24位)是有意义的。

7位代表动作(127个不同的动作)。 9位将表示角度(1-512),但您只需要它直到0-360度。 8位代表力。

这个或任何其他字节格式在网络上更短,更容易使用,并且产生更紧密的代码。而且二进制比较速度更快,所以现在可以更轻松地在服务器上编写动作解析器。即而不是寻找#F#的大型开关盒,你只需看看前7位,并将其与int进行比较。

您可以减少其他网络开销,而不是强制由客户端决定,服务器是否可以决定这一点。即一个标准的力,或2个力的水平(好得多,因为这可以用1位表示)。这阻止了客户端和恶意用户向服务器发送垃圾数​​据(例如999的强制),现在该力量可以是0或1,即10或20的速度,没有什么愚蠢的。

+0

好吧,谢谢,据我所知,这听起来非常有用,最知名的多玩家游戏(RealTimeStrategy ...星际争霸?,不知道肯定,但魔兽世界?)使用UDP,但我无法想象如何处理缺失的信息,我的意思是,几乎所有行动都很重要,或者可能很重要发送的每个对象都可能是一个接近死亡的治疗。 我喜欢减少交通的部分,但我不认为我会通过我的小游戏达到沉重的交通状况:D 它可以处理,不知道,也许多达5个玩家和〜50个其他移动物体。 此刻,动作缓存在50毫秒的堆栈中...... –

+0

也许你的消息可以用几个字节来表示消息ID。每个客户端都有自己的消息队列 - 发送消息和消息,并且它们是连续的,所以00000001和00000010等等不断增加(并最终重置),所以你可以保持一个轨道。如果服务器或客户端看到的消息不是按顺序排列的,则会知道消息在转换中已经丢失。 – Husman

1

你可以做一个更面向对象的方式,如果你:

  1. 定义称为动作或类似的东西的对象,它具有上述所有参数的 - 动作的类型,动作的方向(或 目标),造成的伤害等。
  2. 创建这些Action对象为您的游戏正常执行
  3. ,使用ObjectOutputStream链接到你的TPC插座输出整个Action对象到服务器/传回给客户端。
  4. 在服务器上,通过检查ObjectInputStream中收到的对象来解释发生了什么。

我觉得这种方式会在情况更清洁和更灵活添加更多的逻辑,不仅仅是分析字符串,但没有那么快(因为对象进入的ObjectOutputStream需要序列)。

+0

好吧,那听起来就像我读过的。但是,是的,这将更加优雅:) 我想我会编辑我的代码到这个变体并且定义一个抽象操作类,以及许多将描述操作的子操作类......是否可以在类中定义方法,fe doLogic()然后被发送到服务器并返回后,调用它们?例如。 action.doLogic()和这些会更新游戏的一些参数?这将非常有帮助! ^^ –

+0

是的,它可以定义方法,基本上你可以传递任何普通的类,只要它没有引用外部的东西 - 例如对文件或数据库的引用等等。如果是这样,那些代表引用的实例变量必须用修饰符transient标记,以便它们不会被序列化。你可以阅读更多关于何时使用瞬态:http://stackoverflow.com/questions/5960280/what-is-the-use-of-transient-variables希望有所帮助,祝你好运! –