【问题标题】:rails turn based game managerrails 回合制游戏管理器
【发布时间】:2015-09-26 23:28:02
【问题描述】:

我正在编写一个基于回合的纸牌游戏(在线扑克)。我有使用 Rails 的经验,所以我想将它用于大多数逻辑,例如使用硬币和统计数据管理用户、管理房间和游戏。我打算使用node js + socket.io + redis来提供实时消息服务器->客户端(基本上使用rails中的redis来发布消息,在node.js端监听它们并通过socket.io发布到客户端)和使用 REST API 从客户端 -> 服务器进行通信。

我坚持的部分是尝试管理 Rails 中的实际游戏逻辑。对于正在进行的每场比赛,我都需要一个游戏管理器来评估游戏中发生的所有事情(发牌、接受投注、通过玩家轮次、评估结果等)。有两件事对我来说似乎有点不可能,这是我迄今为止使用 Rails 构建 web 应用程序的经验:

  • 将游戏管理器作为内存中的单个共享对象: 我在想这可能是一个 redis 缓存对象,并且会在每次状态更改时重新加载,并使用新状态再次保存,这似乎是一个很大的开销。 我正在考虑的另一件事是保存游戏管理器对象的哈希值,每个正在进行的游戏作为一个静态对象,可以从 rails 应用程序中的任何位置访问。我在这里缺少什么吗?这可以通过某种方式改进或任何其他方法来执行此类功能吗?

  • 有一个计时器在等待玩家移动时会滴答作响 像任何基于回合的游戏一样,我需要等待特定的秒数,直到玩家做出反应,如果玩家在 20 秒内没有采取行动,那么服务器应该自动移动到下一个玩家。 我真的不知道如何在rails中做到这一点。我正在考虑的一种方法是延迟任务,该任务将在 20 秒后运行,如果用户在它之前采取行动,则玩家轮流或被取消。 (例如使用 sidekiq 来完成这些任务)。

编辑

我一直在设计如何实现实际的游戏逻辑,这就是我需要游戏管理器的原因,需要为每个活动游戏(至少有 2 名玩家的游戏)每 1 秒设置一个计时器,需要如果玩家没有轮到移动到下一个玩家,则在 x 秒后回调。由于每个请求的无状态性质,我不知道如何在 Rails 中做到这一点,我需要将游戏状态存储在内存中并以某种方式运行计时器。 我确实相信我可以解决 node.js 中围绕游戏逻辑的这个特定问题,但我宁愿使用 node.js 来管理套接字连接并通过 redis pub/sub 接收事件。

【问题讨论】:

  • 不错 - 在 Rails 中制作回合制游戏是一个很棒的项目 :)

标签: ruby-on-rails ruby node.js multiplayer


【解决方案1】:

这会很抽象,希望你不要介意。


游戏管理器

game manager 实际上会做什么?

您说您希望它在内存中运行 - 为什么?应用程序基于输入/输出运行。除非您想以某种定时响应格式(发送通知消息等)使用它,否则游戏管理器的想法真的没用。

您需要一种方法来处理系统上的单个游戏。这可能需要大量的 javascript 实现,但从 Rails 的角度来看,没有必要在后端过度使用。

请记住,您只是在寻找实时逻辑。这并不意味着您必须在服务器上运行实时应用程序。相反,您可以在后端使用 Rails 的模型和业务逻辑来处理它。

这只是一个基本的例子:

#app/models/game.rb
class Game < ActiveRecord::Base
   #columns id | name | active (bool) | created_at | updated_at
   has_many :players
end

#app/models/player.rb
class Player < ActiveRecord::Base
   #columns id | game_id | user_id | created_at | updated_at
   belongs_to :game
   belongs_to :user

   alias_attribute :joined, :created_at
end

#app/models/user.rb
class User < ActiveRecord::Base
   has_many :players
   has_many :games, through: :players
end

这是一个非常基本的示例,但它应该为您提供以下内容:

#config/routes.rb
resources :games, only: [:index, :show] do
    resources :sessions, path: "", path_names: { new: "join", destroy: "leave" show: "" }, only: [:new, :destroy] #-> url.com/games/:game_id/join
end

#app/controllers/games_controller.rb
class SessionsController < ApplicationController
   def new
      @game = Game.find params[:game_id]
      @session = @game.players.new player_params
      if @session.save
         redirect_to @game #-> takes you to url.com/game/23
      else
         redirect_to root_url, notice: "Sorry, you cannot join this game"
      end
   end

   private

   def player_params
      params.require(:user).permit(:x, :y, :z)
   end
end

我知道这不是严格意义上的 CRUD,但我希望你能欣赏它的工作原理。

然后你可以在你的模型中创建你的逻辑:

#app/models/player.rb
class Player < ActiveRecord::Base
    belongs_to :game
    belongs_to :user

    alias_attribute :joined, :created_at

    validates :user, uniqueness: { scope: :game, message: "You're already in this game!" } 
end

这方面的实时性将来自您的服务器对请求的响应速度。如果您有一个 JS 前端(使其看起来更漂亮),您将能够使用 JSON(如 API)ping 后端,获取响应并在前端使用它们。

--

消息

将Pusher 与Redis 一起使用。

实时通知的实现会有点复杂,不是以编程方式,而是通过资源实现。

向连接的客户端发送推送通知相对简单——只需在 Redis 中对消息进行排队,然后使用 Pusher 将它们发送出去。

但是,如果您想在没有输入的情况下调用消息(IE,如果有时间更新等),您需要在服务器上每隔 xseconds 运行某种 CRON 脚本。

这是您可能需要一些单独功能的地方,尽管我认为 Rails 可以使用一些rake 命令来处理它。必须了解拥有此类功能的资源负载。

【讨论】:

  • 编辑了答案。实际的游戏管理几乎正是我认为我会做的。有一个 API 可以调用,后端将管理一切。我正在苦苦挣扎的是在哪里为每场比赛实施实际时间记录器。我认为我不能通过 cron 工作很好地解决它。
  • 是的,cron 可能不是最好的方法。我在想一个服务器上的应用程序可以写成与 Rails 应用程序一起运行,使用应用程序的数据和服务器上的应用程序的实时性
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-26
  • 2013-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多