2009-08-08 108 views
16

我聽說過,協程是構建遊戲的好方法(例如,PEP 342:「協程是一種表達許多算法的自然方式,比如模擬,遊戲......」),但我很難包裝我的腦袋圍繞着這將如何實際完成。遊戲設計的協程?

我從這個article可以看出,協程可以代表一個狀態機中的狀態,這個狀態機使用調度器相互轉換,但我不清楚這是如何適用於遊戲狀態根據多個移動而變化的遊戲玩家。

有使用協程編寫的遊戲的簡單例子嗎?或者有人可以提供一個如何完成的草圖?你可能會發現有趣的

回答

7

遊戲中可以使用單向協同程序,就像模型中的演員中的輕量級線程一樣,如Kamaelia

遊戲中的每個對象都是Kamaelia的「組件」。組件是一個可以暫停執行的對象,當它允許暫停時,可以通過讓步來暫停執行。這些組件還有一個消息傳遞系統,可以讓他們安全地異步通信。

所有的對象將同時做自己的事情,發生互動時互相發送消息。

所以,它並不是特定於遊戲,但是當您有多個通信組件同時運行時,任何事情都可以從協同程序中受益。

9

協同程序允許創建大量的非常輕量級的「微線程「與合作多任務(即微螺紋懸掛自己故意讓其他微螺紋運行)。在這個問題上閱讀Dave Beazley的article

現在,很明顯這種微螺紋如何能夠用於遊戲編程。考慮一個實時策略遊戲,你有幾十個單位 - 每個單位都有自己的想法。對於每個單位的AI來說,在模擬多任務環境中運行這樣一個微線程可能是一個方便的抽象。這只是一個例子,我相信還有更多。

在Google上的「協同遊戲編程」搜索似乎帶來了有趣的結果。

8

協程最突出的例子是有點老的圖形點&點擊冒險遊戲,在那裏他們用來編寫遊戲中的過場動畫和其他動畫序列。一個簡單的代碼示例是這樣的:

# script_file.scr 
bob.walkto(jane) 
bob.lookat(jane) 
bob.say("How are you?") 
wait(2) 
jane.say("Fine") 
... 

這整個序列不能被寫爲正常代碼,只要你想看到鮑勃做他的步行動畫你做的不是右跳到下一行bob.walkto(jane)後。對於步行動畫來說,你需要將控制權交還給遊戲引擎,這就是協程的作用。

這整個序列作爲協同程序執行,這意味着您可以隨意暫停和恢復它。像bob.walkto(jane)這樣的命令因此告知引擎方bob對象它的目標,然後暫停協程,等待bob到達目標時的喚醒調用。

發動機側的事情可能是這樣的(僞代碼):

class Script: 
    def __init__(self, filename): 
     self.coroutine = Coroutine(filename) 
     self.is_wokenup = True 

    def wakeup(self): 
     self.is_wokenup = False; 

    def update(): 
     if self.is_wokenup: 
      coroutine.run()    


class Character: 
    def walkto(self, target, script): 
     self.script = script 
     self.target = target 

    def update(self): 
     if target: 
      move_one_step_closer_to(self.target) 
      if close_enough_to(self.target): 
       self.script.wakeup() 

       self.target = None 
       self.script = None 

objects = [Character("bob"), Character("jane")] 
scripts = [Script("script_file.scr")] 

while True: 
    for obj in objects: 
     obj.update() 

    for scr in scripts: 
     scr.update() 

警告豆蔻詞然而,儘管協程使編碼這些序列很簡單,不是每一個實現你會發現他們的意志在考慮序列化的情況下構建,所以如果大量使用協程,節約遊戲將成爲一個相當麻煩的問題。

這個例子也是一個協程在遊戲中最基本的情況,協程本身也可以用於很多其他的任務和算法。

1

想要使用協程來表示個人角色AI腳本是很常見的。不幸的是,人們往往會忘記,只有在更高層次上,協程才具有線程所具有的所有同步和互斥問題。因此,您經常需要首先儘可能多地去消除本地狀態,然後編寫可靠的方法來處理協同程序中出現的錯誤,這些錯誤在您所指的內容不再存在時就會出現。

所以在實踐中他們很難從中受益,這就是爲什麼像UnrealScript這樣的語言使用一些協程的外表將大部分有用的邏輯推出到原子事件。有些人從他們身上獲得很好的效用,例如。 EVE在線人員,但他們不得不圍繞這個概念設計他們的整個系統。 (以及它們如何處理共享資源上的爭用沒有很好的文檔記錄。)

+0

協同程序有一些同步問題,但只有當它們的狀態在yield()調用之間不能一致時。對yield()調用之間的所有代碼進行隱式鎖定可以大大簡化事情。 最大的問題是,任何時候創建一個例程時,都應該決定這個和那個例程在它必須yield()之前是否總能完成。如果一個例程的調用者不希望某個例程產生,那麼在調用該例程時它可能沒有一致的狀態。添加一個yield()將是一個重大改變。 – supercat 2010-07-14 15:10:25

+0

問題在於,你通常希望能夠讓所有這些例程都可以被使用(就像在UnrealScript中'隱式函數'隱含地產生的那樣),但是這導致了以不可預知的方式進行交互的協同程序的組合。例如。如果一個巡邏隊說「往北走,看看,往南走,看,重複」。另一個是反應例程,說「如果(聽到西方的聲音){去西部,看看,去東部}}」然後交錯兩者可能導致演員移動相當不可預測。這就是爲什麼UnrealScript只能在一個「協同程序」中允許這些功能。 – Kylotan 2010-07-15 09:35:14

+0

即使每個演員只有一個協程,但仍然不足以確保邏輯始終在語言層面上工作:如果您的協同程序說:「畫劍;等待1秒;用劍攻擊對手」,那麼是什麼如果因爲你被另一名玩家解除了劍而消失了,會發生什麼?特別是,如果您的語言通過使用局部變量來實現該協程,那麼現在引用空對象的劍是什麼?考慮所有這些情況是非常棘手的,如果你正常使用通用語言。 – Kylotan 2010-07-15 09:40:24