如何设计基于计时器的网页游戏(如Cafe World)

时间:2009-11-19 16:10:02

标签: language-agnostic

我需要设计和实现基于计时器的游戏(客户端上的Flash,服务器上的PHP),例如Cafe World,即用户点击按钮,等待几秒钟,发生一些事情,然后他可以再次点击。这将是对食品生产线的模拟。

将有N个生产线元素,每个元素都有一个具有不同持续时间的独立计时器,每个元素都可以提示M个操作(首先立即启动,下一个启动时完成,依此类推)。

如何使用数据库后端实现此类功能的服务器端?目前我正在考虑提示的计数器,当前活动操作的“剩余时间”指示和上次更新的时间。当请求操作时,我将使用从上次更新开始经过的时间更新“剩余时间”和提示计数器。任何想法,评论或更好的想法?

最佳答案获得赏金。

5 个答案:

答案 0 :(得分:5)

在阅读了您的问题,其他答案和讨论之后,我想我终于掌握了您的要求(因此是一个新答案)。

首先,您需要跟踪最终用户的会话。当游戏开始时,您将不得不启动一个新的PHP会话并向Flash游戏发送某种会话标识符。每当flash游戏ping服务器时,它都会传递会话标识符,以便PHP知道它正在使用哪个游戏实例。

PHP服务器本身将是一个被动实体 - 闪存客户端将进行数据的推送和拉取。假设一个用户对事件X,Y和Z进行排队,它们每个都需要20秒......一旦用户尝试对每个事件进行排队,Flash客户端就会通知服务器,服务器会将其记录在队列中,或者由于验证而返回错误(即队列中的事件太多)。

此外,客户端将每隔几秒轮询服务器以检查事件的状态。每次客户端注册新事件或轮询状态时,服务器将检查队列中的时间戳并将事件标记为已完成/等,然后向客户端发送响应。这比尝试在后台运行一个试图每秒实时更新数据库的脚本更清晰,更实用。唯一的缺点是,如果由于某种原因断开连接,客户端重新连接之前不会处理特定会话的事件。但无论连接之间的时间长短,用户仍然会将服务器视为实时更新,因为数据在发送回客户端之前总是会刷新。

如果您有任何特定于实现的问题,请随时发布您的数据库架构和/或您的服务器代码。

更新:为了回应Pie的评论,基本上有三种方法可以将事件标记为已完成... 1.)当客户端连接到服务器时,将完成的事件标记为在数据库中完成请求,或2.)使用后台进程自动将事件标记为已完成,或者3.)两者的组合。

如果您按照选项1检查事件时间戳并在每个客户端连接上标记已完成的事件,则在提供客户端请求时,您的数据库将完全是最新的。如果你遵循选项二,在cron上运行的PHP脚本可以确保即使客户端消失,数据库也是最新的,确保你的数据通常不到一分钟 - 无论客户端是否存在或不。

无论您将如何使用数据(高分表等),结合使用这两种技术可能是最好的主意。新鲜数据总是有利的,而cron脚本的定期增量刷新从不会伤害任何人。

就标记事件已完成而言,您只需要检查事件的相对开始时间+事件持续时间与当前时间的关系。在队列中,事件的开始时间定义为添加到队列中第一个项目的起始时间戳的所有先前未完成的排队事件的持续时间和冷却时间。

答案 1 :(得分:2)

使用“剩余时间”字段是一个坏主意,因为可以使用诸如Cheat Engine之类的程序在客户端进行攻击。

在数据库中,记录上次事件的时间。您的中间件(请参阅Tim's Answer)仍会执行验证,但会告知客户端是否可以执行请求的操作。所有验证都需要在中间件的服务器端完成。根据新请求,中间件可以检查数据库时间戳,查看是否已经过了所需的时间量,并执行请求或向客户端返回错误。在服务器端执行间隔检查可防止通过内存中的修补程序破坏客户端验证的情况。 从不将验证留给客户单独使用。

答案 2 :(得分:1)

像CafeWorld,FarmVille,YoVille等游戏使用3层架构。 Flash应用程序是一个胖(ish!)客户端,内置一些逻辑,使用存储在服务器上的数据,一个中间层来源数据接口并处理验证规则(例如一次不能使用两个炉子)以及处理数据存储的持久层。

状态由客户端维护,但重要的是客户端无法将状态写入服务器,只有客户端上的事件才能触发服务器(中间层)的更改。以这种方式,中间层和客户端都维持单独的定时,这些定时以一定间隔同步。当这些间隔没有对齐时,你会注意到在像FarmVille这样的游戏中,你会收到一条消息,通知你“游戏不同步”。

答案 3 :(得分:1)

如果我已正确理解你的问题 - 游戏规则由服务器实现;定时器从客户端开始;它是“用户经过的时间”这一点很重要,而不是“服务器上的经过时间”(即用户不会因为滞后连接而受到惩罚);但它绝不能让假客户假装有高延迟。

在这种情况下,这是我非常愚蠢的建议:

在服务器上,仅存储客户端发送给您的信息以及您发送给客户端的信息。 (即,我不会计划存储服务器计算的“剩余时间”,因为它几乎可以保证是错误的。相反,只需存储“开始操作”事件的“客户端开始时间”和“允许持续时间” 。)

查看类似于timeseal http://www.freechess.nl/timeseal.htm的解决方案,以确保欺骗客户端更难写。例如,使用客户端和服务器上的私钥加密时间戳(或整个消息),检查接收的时间戳是否由有效密钥加密。

根据可容忍的意外延迟程度,您可能希望向客户端发送“潜在触发器”而不是“立即触发器”。即,而不是发送客户“现在客户B离开而没有付款(因为玩家首先关注客户A)”,发送“如果玩家首先参加客户A,客户B离开而不付钱”。

检查服务器上是否在客户端正确发生了这些规则,这很简单,可以验证根据数据库中的选项接收的事件的顺序。因此,对于上面的示例,如果您看到事件“关注客户A”,您预计下一个事件将是“客户B离开而不付款”。

玩家游戏的数据库表最终是一个美化的事件日志 - 除了它还存储“接下来会发生什么”。您从游戏规则引擎中获取规则并将其存储为“下一个可用的操作状态”事件。

如果您确实选择发送客户端“潜在触发器”,我建议也加密它们。否则,有人会想写一个嗅探器,这样他们就可以编写一个非常简单的机器人来计算所提供事件中最好的选项。

答案 4 :(得分:1)

阅读了您的问题和给定的答案后,我建议您重新考虑您的应用程序架构。在我看来,你应该在客户端应用程序(flash)中实现整个游戏逻辑。您的服务器端应用程序应该只处理用户登录和游戏状态的管理。例如。玩家登录您的Flash应用程序 - >如果用户存在则检查服务器端,然后返回该用户的实际游戏状态。 为什么这个命题: 1.让用户机器做繁重的工作而不是服务器机器 2.限制进出服务器的流量

处理安全问题我建议您在数据流量中实施简单的“质询 - 响应身份验证” challenge response on wiki