【问题标题】:In a NodeJS game with each object as a class, how should events be treated?在一个以每个对象为一个类的 NodeJS 游戏中,应该如何处理事件?
【发布时间】:2011-08-06 21:57:13
【问题描述】:

在 Javascript/NodeJS 游戏中处理多个类时,我无法确定哪个类应该发出事件以及哪些类应该监听。我正在按照本指南创建事件驱动游戏:http://pragprog.com/magazines/2011-08/decouple-your-apps-with-eventdriven-coffeescript

我正在编写一个小游戏,并将我的类拆分为以下控制器:

世界 - 创建游戏世界并通过多个“回合”来确定一些简单的游戏逻辑(即角色应该移动,塔应该射击)。

塔 - 塔位于 10x10 的网格上,并有一个范围。当一个物体进入射程时,它可以射击。

生物(敌人) - 生物在 10x10 网格上生成,每 3 秒移动一次。在某个时刻,它会在塔的范围内游荡。

我整天都在阅读有关 EventEmitters 的信息,但似乎无法找出构建事件的正确方法。生物在移动时是否应该触发事件,而塔是否应该监听“移动”事件?还是应该由世界控制所有事件,而塔/生物应该听从世界?

参见下面的示例代码。

背景:我一直在为 NodeJS 开发一个简单的 TowerD 游戏,并决定首先实现服务器。我将所有实体存储在 MongoDB 中,并使用地理空间计算来确定对象是否在拍摄范围内。目前我正在使用一个基本的 3 秒循环来“勾选”游戏和进度逻辑,但我想转向一个真正的事件驱动模型并且正在苦苦挣扎。

世界:

exports.World = class World extends EventEmitter

  constructor: ->
    ### Initial config ###
    @gameTime = 3000  # every 3000ms, the game progresses

    ### Start the game!! ###
    @game = setInterval ->
      world.gameLoop()
    , @gameTime

    ### Load the map ###
    # First level: Hidden Valley
    @maps = []
    @maps.push new map 'hiddenvalley'

### Load the mobs ###
    # First map has one mob: Warrior
    @mobs = []

    # Let's create two of them  
    @mobs.push new mob @maps[0].mobs[0]
    @mobs.push new mob @maps[0].mobs[0]

(查看完整的 world.coffee:https://github.com/bdickason/node-towerd/blob/master/controllers/world.coffee

塔:

exports.Tower = class Tower
  constructor: (name) ->
    name = name.toLowerCase() # In case someone throws in some weird name

  # Check for anything within range
  checkTargets: (callback) ->
    mobModel.find { loc : { $near : @loc , $maxDistance : @range } }, (err, hits) -> 
      if err
        console.log 'Error: ' + err
      else
        callback hits

(查看完整的 towers.coffee:https://github.com/bdickason/node-towerd/blob/master/controllers/towers.coffee

生物:

exports.Mob = class Mob extends EventEmitter

  move: (X, Y, callback) ->
    @loc = [@loc[0] + X, @loc[1] + Y]
    newloc = @loc
    mobModel.find { uid: @uid }, (err, mob) ->
      if(err)
        console.log 'Error finding mob: {@uid} ' + err
      else
        mob[0].loc = newloc
        mob[0].save (err) ->
          if (err)
            console.log 'Error saving mob: {@uid} ' + err
    console.log 'MOB ' + @uid + ' [' + @id + '] moved to (' + @loc[0] + ',' + @loc[1] + ')'

(查看 mob.coffee 的完整来源:https://github.com/bdickason/node-towerd/blob/master/controllers/mobs.coffee

项目完整来源:https://github.com/bdickason/node-towerd

任何活动帮助将不胜感激。我已经在 github 上倾倒了大约 15 个 nodejs 游戏,但还没有发现有人使用这种模式:(

【问题讨论】:

    标签: javascript node.js coffeescript eventemitter


    【解决方案1】:

    我会使用支持“父母”的自定义 EventEmitter,例如冒泡事件传播。然后我会这样做:

    • 当一个生物移动时,它会在自己身上触发一个“移动”事件,其参数类似于 {mob: @,x: x, y: y}(该事件随后会冒泡到全世界)。
    • 世界监听“移动”事件。当它收到一个时,它会检查数据库以查找需要通知的塔并在它们上发出事件。

    【讨论】:

    • 啊哈哈,可爱的父事件发射器:D 确保你花一些时间在系统的设计上。例如给出对象的组,这样你就可以在世界上收听“golbin.move”,并且每上一层,你就会在地精、世界等中取消转移到回调参数中。
    • 感谢 thejh 和 Ivo,这些都是很棒的建议!我对“冒泡”概念有了一点了解,但其他一切都很清楚。你能用一个简单的例子来阐明地精或世界中的“不转变”吗?
    • 当然,想象一下让妖精开火。 globin 上的听众看起来像 goblin.bind('move', function(x, y) { 现在世界上的听众看起来像 world.bind('goblin.move', function(goblin, x, y) { 等等
    • 感谢 Ivo,非常感谢。把一个简单的流程图和一些场景放在一起,然后我就开始破解了!
    猜你喜欢
    • 2021-08-29
    • 1970-01-01
    • 1970-01-01
    • 2015-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多