2009-08-08 44 views
16

Tôi nghe nói rằng coroutines là một cách tốt để cấu trúc trò chơi (ví dụ: PEP 342: "Coroutines là một cách tự nhiên thể hiện nhiều thuật toán, chẳng hạn như mô phỏng, trò chơi ...") nhưng tôi đang gặp khó khăn khi đóng gói đầu của tôi xung quanh cách này thực sự sẽ được thực hiện.Coroutines cho thiết kế trò chơi?

Tôi thấy từ đây article rằng coroutines có thể đại diện cho các trạng thái trong một máy trạng thái chuyển đổi với nhau bằng cách sử dụng bộ lập lịch, nhưng nó không rõ ràng với tôi như thế nào áp dụng cho một trò chơi mà trạng thái trò chơi đang thay đổi dựa trên di chuyển từ nhiều người chơi.

Có ví dụ đơn giản nào về trò chơi được viết bằng coroutines có sẵn không? Hoặc ai đó có thể cung cấp một bản phác thảo về cách nó có thể được thực hiện?

Trả lời

7

Một cách coroutines có thể được sử dụng trong trò chơi là chủ đề trọng lượng nhẹ trong một diễn viên như mô hình, như trong Kamaelia.

Mỗi đối tượng trong trò chơi của bạn sẽ là thành phần Kamaelia '. Một thành phần là một đối tượng có thể tạm dừng thực thi bằng cách sinh lợi khi nó cho phép tạm dừng. Các thành phần này cũng có một hệ thống nhắn tin cho phép chúng giao tiếp an toàn với nhau một cách không đồng bộ.

Tất cả các đối tượng sẽ đồng thời làm việc riêng của họ, với các tin nhắn được gửi cho nhau khi tương tác xảy ra.

Vì vậy, nó không thực sự cụ thể đối với trò chơi, nhưng bất cứ điều gì khi bạn có vô số các thành phần giao tiếp diễn xuất đồng thời có thể hưởng lợi từ coroutines.

9

coroutines cho phép tạo ra một lượng lớn rất nhẹ "microthreads "với đa nhiệm hợp tác xã (tức là microthreads đình chỉ chính họ cố ý để cho phép các microthread khác chạy). Hãy đọc trong số article của Dave Beazley về chủ đề này.

Bây giờ, rõ ràng cách các microthread có thể hữu ích cho lập trình trò chơi. Hãy xem xét một trò chơi chiến lược thời gian thực, nơi bạn có hàng chục đơn vị - mỗi người đều có tâm trí riêng. Nó có thể là một sự trừu tượng thuận tiện cho AI của mỗi đơn vị để chạy như một microthread trong môi trường đa nhiệm mô phỏng của bạn. Đây chỉ là một ví dụ, tôi chắc chắn có nhiều hơn.

Tìm kiếm "lập trình trò chơi coroutine" trên Google dường như mang lại kết quả thú vị.

8

Trường hợp nổi bật nhất của coroutines là điểm đồ họa cũ bằng đồ họa & nhấp vào trò chơi phiêu lưu, nơi chúng được sử dụng để cắt cảnh và đoạn hoạt hình khác trong trò chơi. Một mã ví dụ đơn giản sẽ trông như thế này:

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

toàn bộ chuỗi này không thể được viết dưới dạng mã bình thường, khi bạn muốn xem bob làm phim hoạt hình đi bộ của mình sau khi bạn đã làm bob.walkto(jane) thay vì nhảy ngay đến dòng kế tiếp . Đối với các hoạt hình đi bộ để chơi bạn tuy nhiên cần phải cung cấp cho kiểm soát trở lại với các công cụ trò chơi và đó là nơi mà coroutines đi vào chơi.

Toàn bộ chuỗi này được thực hiện dưới dạng coroutine, nghĩa là bạn có khả năng tạm ngưng và tiếp tục nó theo ý muốn.Một lệnh như bob.walkto(jane) do đó nói với đối tượng bob bên động cơ mục tiêu của nó và sau đó đình chỉ coroutine, chờ đợi một cuộc gọi wakeup khi bob đã đạt được mục tiêu của mình.

Trên mọi thứ bên cơ thể trông như thế này (pseudo code):

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() 

Một từ litte cảnh báo tuy nhiên, trong khi coroutines làm cho mã hóa các chuỗi rất đơn giản, không phải mọi hiện thực bạn sẽ tìm thấy trong số họ sẽ được xây dựng với serialization trong tâm trí, do đó, tiết kiệm trò chơi sẽ trở thành một vấn đề rắc rối nếu bạn sử dụng nhiều coroutines.

Ví dụ này cũng chỉ là trường hợp cơ bản nhất của coroutine trong trò chơi, bản thân coroutine cũng có thể được sử dụng cho nhiều tác vụ và thuật toán khác.

1

Khá phổ biến khi muốn sử dụng coroutines để đại diện cho các tập lệnh AI của từng diễn viên. Thật không may mọi người có xu hướng quên rằng coroutines có tất cả cùng một đồng bộ và các vấn đề loại trừ lẫn nhau mà các chủ đề có, chỉ ở một mức độ cao hơn. Vì vậy, trước tiên bạn cần phải làm nhiều nhất có thể để loại bỏ trạng thái cục bộ, và thứ hai viết các cách mạnh mẽ để xử lý các lỗi trong một coroutine phát sinh khi một cái gì đó bạn đang đề cập đến không tồn tại. Vì vậy, trong thực tế, họ rất khó có được lợi ích từ đó, đó là lý do tại sao các ngôn ngữ như UnrealScript sử dụng một số semblance coroutines thúc đẩy nhiều logic hữu ích cho các sự kiện nguyên tử. Một số người có được tiện ích tốt từ họ, ví dụ như. người EVE Online, nhưng họ phải có khá nhiều kiến ​​trúc sư toàn bộ hệ thống của họ xung quanh khái niệm. (Và cách họ xử lý tranh chấp trên các tài nguyên được chia sẻ không được ghi lại đầy đủ.)

+0

Coroutines có một số vấn đề về đồng bộ hóa, nhưng chỉ khi trạng thái của chúng không thể nhất quán giữa các lệnh gọi yield(). Có một khóa ẩn xung quanh tất cả các mã giữa các cuộc gọi yield() có thể đơn giản hóa rất nhiều thứ. Bíp lớn nhất là bất kỳ khi nào một thói quen được tạo ra, người ta nên quyết định sau đó và ở đó liệu thường trình sẽ luôn có thể hoàn thành trước khi nó có năng suất(). Nếu người gọi thường xuyên không mong đợi một thói quen sinh lợi, nó có thể không có những thứ trong trạng thái phù hợp khi thói quen được gọi. Thêm một lợi nhuận() sẽ là một thay đổi phá vỡ. – supercat

+0

Vấn đề là bạn thường muốn có khả năng mang lại tất cả các nơi cho các thói quen như vậy (như trong UnrealScript, nơi mà 'hàm tiềm năng' tiềm ẩn), nhưng điều này dẫn đến sự kết hợp của coroutines tương tác theo những cách không thể đoán trước. ví dụ. Nếu một là một coroutine tuần tra nói "đi về phía bắc; nhìn; đi về phía nam; nhìn; lặp lại;" và người kia là một thói quen phản ứng nói "nếu (nghe thấy tiếng tây) {đi về phía tây; nhìn; đi về phía đông;}" thì xen kẽ cả hai có thể dẫn đến việc diễn viên di chuyển khá khó lường. Đó là lý do tại sao UnrealScript chỉ cho phép các chức năng như vậy trong chính xác một 'coroutine'. – Kylotan

+0

Và ngay cả khi bạn chỉ có 1 coroutine cho mỗi diễn viên, điều đó vẫn chưa đủ để đảm bảo logic luôn hoạt động ở cấp độ ngôn ngữ: nếu coroutine của bạn nói: "rút gươm; chờ 1 giây; tấn công đối thủ bằng kiếm" sẽ xảy ra nếu thanh kiếm biến mất do bạn bị người chơi khác giải giáp? Đặc biệt, nếu ngôn ngữ của bạn thực hiện coroutine đó bằng cách sử dụng một biến cục bộ cho một thanh kiếm mà bây giờ đề cập đến một đối tượng null? Rất khó để xem xét tất cả các trường hợp này nếu bạn đang sử dụng một ngôn ngữ mục đích chung theo cách thông thường. – Kylotan

Các vấn đề liên quan