线程游戏“事件循环”中的演员/消息传递

时间:2013-01-17 04:13:35

标签: android multithreading scala actor game-loop

我正在构建一个Android应用程序(使用Scala 2.9)并使用一个呈现给SurfaceView的Thread;这是一个游戏,所以它应该尽可能多地更新。我想这个问题类似于其他游戏“事件循环”,其中输入来自不同的线程

以下是依赖于同步的当前方法的粗略近似值。它“运行得很好”,但我对使用显式同步和“绑定”视图/输入线程存在一般疑虑。

查看,“UI线程”:

def View.onTouchEvent(e) { // on UI thread
  Game.handleInput(e)
}

游戏,“游戏主题”:

def Game.handleInput(e) = S synchronized { // on UI thread
  alterStateBasedOnInput
}
def Game.run () { // on Game thread 
  while (running) {
    S synchronized { 
      doGameStuff
    }
    View.post(someStateRelayedViaRunnable)
    yield
  }
}

我希望有类似的东西,而不是明确地使用同步:

def View.onTouchEvent(e) { // on UI thread
   Game.sendMessage(e)
}
def Game.run () { // on Game thread 
  while (running) {
    processMessage
    doGameStuff
    View.sendMessage(someState) // hopefully same as Game.sendMessage
    yield
  }
}

现在,使用ConcurrentLinkedQueue或类似方法手动实现相对容易,但我真的不想在这里重新发明轮子。此外,使用这样的actor /队列回传到UI也是很好的 - 现在我正在使用Android的支持将(异步)Runnable发布到UI线程。

我简要介绍了几种不同的actor实现(主要是标准的Scala和Scalaz)和一些不同的Java“消息传递”库,例如Jetlang,但大多数似乎使用隐式线程或线程执行器服务。但是,在我的情况下,我希望[在特定线程上的特定时间运行actor和]处理消息。对于View.sendMessage,消息也应该在UI线程上处理,但是时间并不重要,可以捎带上面提到的Runnable执行。

然后,我想我的问题是,鉴于上述情况:

在这两个线程之间提供数据的方法有什么好处 - 如“高效”和惯用 - 吗?

(我也很乐意接受这样的建议:我完全无法理解Scala演员和/或Scalaz演员和/或其他消息传递库; Scalaz似乎可能能够像我想,但我很难跟随。)

1 个答案:

答案 0 :(得分:0)

好吧,虽然我仍然想知道上面的通用/可重用方法,但实用性要求。这也可以通过在游戏线程上运行Looper然后将游戏“事件循环内容”放在IdleHandler中来完成,但我不喜欢这种反转..

以下是我目前的实施方式:

游戏/线程类:

var handler: Handler = _ // handler created on View thread

// Send Message to Looper that exists on View thread
// (Created implicitly for all UI threads.)
def publishEvent(event: OutputEvent) {
  handler.obtainMessage(0, event).sendToTarget
}

protected val queue = new ConcurrentLinkedQueue[InputEvent]

def queueEvent(event: InputEvent) { // on UI thread
  queue.add(event)
}

def processQueuedEvents() { // on game Thread
  @tailrec
  def processNextEvent {
    val event = queue.poll
    if (event ne null) {
      doStuffWithInputEvent(event)
      processNextEvent
    }
  }    
  processNextEvent
}

override def run() { // on game Thread
  while (running) {
    processQueuedEvents
    doOtherGameStuff ~ call_publishEvent ~ etc
  }
}

查看课程:

// Created on UI thread, passed to Game instance
// (The Looper will dispatch Messages to Handlers.)
val handler = new Handler {
  override def handleMessage(m: Message) {
    val event = m.obj
    doStuffWithOutputEvent(event)
  }
}

// on UI thread
override def onTouch(v: View, ev: MotionEvent): Boolean = {
   // safely queued, will be processed at the start of each game loop
   game.queueEvent(InputEvent(..))
}