iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 22
0
自我挑戰組

卡牌遊戲開發日記v2020系列 第 22

Day22 實作玩家(用戶端)的訊息收發

https://blog.csdn.net/brucewong0516/article/details/84031715
【python】详解事件驱动event实现

以這個範本做基底,修改成自己想要的樣子。

主要精神:recv_cmd() 讀入資料,轉成event物件
由 Player 消化event

DONE:

  • 修改生成事件的方式,利用閉包機制把一個EventManager包起來,透過sender呼叫內部的SendEvent()
  • 重新定義事件物件,dict{}改成args[]
  • 定義完由系統發送的事件

TODO:

  • 把Queue改成socket
  • 先不做封包解析的動作。直接 recv(1024)
  • 以可讀字串方式接收進來的資料,暫時先用空白字元分隔資料。 split(" ")
  • 其中一個loop固定抓資料進來,然後轉手給其他handler處理
  • handler先不做任何處理,單純回覆 ACK_XXX
  • 加入狀態機,控制遊戲流程是規則設定的走向。
  • 加入更多判斷,排除不合法的行動。
  • 需要快速定義事件和事件處理函數的方法
    (從cmd定義)自動生成程式碼技術
from queue import Queue, Empty
from threading import Thread

class EventManager:
    def __init__(self):
        self.__eventQueue = Queue()
        self.__active = False
        self.__thread = Thread(target = self.__Run)
        self.count = 0
        self.__handlers = {}

    def __Run(self):
        print('{}_run'.format(self.count))
        while self.__active == True:
            try:
                event = self.__eventQueue.get(block = True, timeout = 1)
                self.__EventProcess(event)
            except Empty:
                pass
            self.count += 1

    def __EventProcess(self, event):
        print('{}_EventProcess'.format(self.count))
        if event.type_ in self.__handlers:
            for handler in self.__handlers[event.type_]:
                handler(event)
        self.count += 1

    def Start(self):
        print('{}_Start'.format(self.count))
        self.__active = True
        self.__thread.start()
        self.count += 1

    def Stop(self):
        print('{}_Stop'.format(self.count))
        self.__active = False
        self.__thread.join()
        self.count += 1

    def AddEventListener(self, type_, handler):
        print('{}_AddEventListener'.format(self.count))
        try:
            handlerList = self.__handlers[type_]
        except KeyError:
            handlerList = []
            self.__handlers[type_] = handlerList
        if handler not in handlerList:
            handlerList.append(handler)
        print(self.__handlers)
        self.count += 1

    def RemoveEventListener(self, type_, handler):
        print('{}_RemoveEventListener'.format(self.count))
        try:
            handlerList = self.handlers[type_]
            if handler in handlerList:
                handlerList.remove(handler)
            if not handlerList:
                del self.handlers[type_]
        except KeyError:
            pass
        self.count += 1

    def SendEvent(self, event):
        print('{}_SendEvent'.format(self.count))
        self.__eventQueue.put(event)
        self.count += 1

class Event:
    def __init__(self, type_=None, args_=None):
        self.type_ = type_
        self.args = args_

###############################################################################

# 生成 sender ,以此傳送事件
def make_sender(eventManager):
    em = eventManager
    def send(event):
        return em.SendEvent(event)
    return send

# 定義事件類型
EVENT_TURN_START = "Turn_start" # 回合開始
EVENT_BROADCAST = "Broadcast" # 廣播訊息
EVENT_UPDATE = "Update" # 更新(場面資料)
EVENT_DRAW_CARD = "Draw_card" # 玩家抽牌
EVENT_TURN_END = "Turn_end" # 回合結束
EVENT_HEARTBEAT = "Heartbeat" # 心跳訊號
# EVENT_ACTION = "Action" # 玩家行動
# EVENT_DISCARD = "Discard" # 玩家棄牌


# 事件處理函式 (玩家)
class Player:
    def __init__(self,id):
        self._id = id

    # recv
    def turn_start(self):
        print(f'{self._id} 回合開始')

    def broadcast(self, event):
        print(f'{self._id} 廣播訊息')
        
    def update(self, event):
        print(f'{self._id} 更新(場面資料)')

    def draw_card(self, event):
        print(f'{self._id} 玩家抽牌')

    def turn_end(self):
        print(f'{self._id} 回合結束')

    def heartbeat(self):
        print(f'{self._id} 心跳訊號')

    # send
    #def action(self, vector, zen):
    #def discard(self, vector):

def test():
    player1 = Player("player one")
    eventManager = EventManager()
    eventManager.AddEventListener(EVENT_TURN_START, player1.turn_start)
    eventManager.AddEventListener(EVENT_BROADCAST, player1.broadcast)
    eventManager.AddEventListener(EVENT_UPDATE, player1.update)
    eventManager.AddEventListener(EVENT_DRAW_CARD, player1.draw_card)
    eventManager.AddEventListener(EVENT_TURN_END, player1.turn_end)
    eventManager.AddEventListener(EVENT_HEARTBEAT, player1.heartbeat)
    eventManager.Start()

    send = make_sender(eventManager) # 建立sender傳送事件
    send(Event(type_=EVENT_TURN_START))
    send(Event(type_=EVENT_BROADCAST))
    send(Event(type_=EVENT_UPDATE))
    send(Event(type_=EVENT_DRAW_CARD))
    send(Event(type_=EVENT_TURN_END))
    send(Event(type_=EVENT_HEARTBEAT))

if __name__ == '__main__':
    test()

上一篇
Day21 一款卡牌遊戲的指令範例
下一篇
Day23 實作玩家(用戶端)的訊息收發-2
系列文
卡牌遊戲開發日記v202030
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言