Code Monkey home page Code Monkey logo

multi-bomb-test's Introduction

multi-bomb-test

簡單的傳炸彈小遊戲後端,練習寫 axum 跟 websocket 用。

遊戲說明

使用者界面分成 n 個區域,每個區域有一個**的指示區域,跟左右各兩個按鈕。

(n=3)
+-------+-------+---------------+-------+-------+
|  < 3  |  < 1  |     >!!!<     |  1 >  |  2 >  |
+-------+-------+---------------+-------+-------+
|  < 3  |  < 1  |    BOMB >>    |  1 >  |  2 >  |
+-------+-------+---------------+-------+-------+
|  < 3  |  < 1  |    << BOMB    |  1 >  |  2 >  |
+-------+-------+---------------+-------+-------+

兩側的按鈕分別代表往左邊或往右邊傳一二或三個人, 中間則指示使用者炸彈在使用者的左邊或是右邊。

根據收到炸彈跟傳走炸彈之間的時間間隔使用者會得到分數, 並會在側邊的記分板顯示每個用戶的得分。

Protocol

預設下,程式會在開啟後在 127.0.0.1:4568 接受 websocket 連線 使用者應該自行架設使用者代理

預設遊戲中有三顆炸彈,用戶端會在開啟連線之後收到一個文字訊息 HELLO = "hello\n" + count, 其中 count 為一個以十進位表示的 u32 數字,代表遊戲中炸彈的數量。

收到 HELLO 後,用戶端應該在可以準備開始遊戲後(如完成使用者界面的渲染),回應一個文字訊息 OLLEH = "olleh\n" + position, 其中 position 為一個以十進位表示的 i32 數字,提示伺服器用戶端相對其他用戶的位置。 伺服器 MAY 根據這個數字決定用戶端與其他使用者的排序。

回應後伺服器會向用戶端發送一個 NAME 封包指明伺服器產生的使用者的名字與顏色, count 個 STATUS 封包其中包含各個炸彈相對於用戶端的狀態,以及一個 BOARD 封包包含記分板上使用者的狀況。 在這之後,用戶端也會收到不同的 STATUS 和 BOARD 封包,並應根據收到的封包改動畫面渲染的內容。

每個 NAME 封包包含兩三行, 第一行是 "name", 第二行是使用者的名字, 第三行是一個以十六進位表示的色碼(six-digit RGB notation)。 用戶端 MAY 在螢幕上使用這些資料來幫助使用者辨認自己的螢幕/記分板名字。

每個 STATUS 封包包含 "status\n" ,一個 u32 數字 index 代表狀態所指的是哪個炸彈(從 0 開始計算,0 <= index < HELLO 封包的 count),和一個字母,代表炸彈編號與用戶端的相對位置 STATUS_BOMB = "X" STATUS_LEFT = "L" STATUS_RIGHT = "R" STATUS = "status\n" + index + " " + (STATUS_BOMB | STATUS_LEFT | STATUS_RIGHT)

每個 BOARD 封包包含數行以 "\n" 分隔的內容, 第一行包含 "board", 之後每三行構成一個記分板條目。 第一行為一個使用者名字, 第二行為一個以十六進位表示的色碼, 第三行為一個數字表示分數。 用戶端 MAY 使用這些資料來渲染一個記分板。

使用者在接到 STATUS_BOMB 封包後應該用最快的速度點下螢幕上的四個按鈕之一, 此時用戶端應該向使用者傳送一個 MOVE 封包。 用戶端 SHOULD 只在收到 STATUS_BOMB 之後才讓使用者點下按鈕或送出封包, 但伺服端 MUST 判斷用戶端的封包是否在適當的時間送出。

MOVE = "move\n" + index + " " + ("L3" | "L1" | "R1" | "R2") 代表把炸彈向左或右傳幾個使用者, 其中 index 代表要移動哪個炸彈。

ABNF ( RFC 5234 )

ALPHA        =  %x41-5A / %x61-7A
DIGIT        =  %x30-39
HEXDIG       =  DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
u32          =  1*9DIGIT
u32          =/ "4" ("0"/"1") 8DIGIT
u32          =/ "42" ("0"/"1"/"2"/"3"/"4"/"5"/"6"/"7"/"8") 7DIGIT
u32          =/ "429" ("0"/"1"/"2"/"3") 6DIGIT
u32          =/ "4294" ("0"/"1"/"2"/"3"/"4"/"5"/"6"/"7"/"8") 5DIGIT
u32          =/ "42949" ("0"/"1"/"2"/"3"/"4"/"5") 4DIGIT
u32          =/ "429496" ("0"/"1"/"2"/"3"/"4"/"5"/"6") 3DIGIT
u32          =/ "4294967" ("0"/"1") 2DIGIT
u32          =/ "42949672" ("0"/"1"/"2"/"3"/"4"/"5"/"6"/"7"/"8") 1DIGIT
u32          =/ "429496729" ("0"/"1"/"2"/"3"/"4"/"5")
COUNT        =  u32
PREID        =  u32
INDEX        =  u32
SCORE        =  u32
BOMBPOS      =  "L"/"X"/"R"
BOMBACTION   =  "L3"/"L1"/"R1"/"R2"
PLRNAME      =  1*32(ALPHA/DIGIT)
PLRCLR       =  "#" 6HEXDIG
HELLO        =  "hello\n" COUNT
OLLEH        =  "olleh\n" PREID
STATUS       =  "status\n" INDEX " " BOMBPOS
MOVE         =  "move\n" INDEX " " BOMBACTION
NAME         =  "name\n" PLRNAME "\n" PLRCLR
BOARD        =  "board\n" 1*(PLRNAME "\n" PLRCLR "\n" SCORE "\n")
CLIENTPACKET =  OLLEH / MOVE
SERVERPACKET =  HELLO / NAME / STATUS / BOARD

伺服器程式架構設計

版本1

(簡單版本:暫時只支援單一個遊戲中一個炸彈,也不處理只有一個玩家的狀況) 伺服器開始後,會生成一個 task 負責接收加入遊戲的申請。 接收到申請後,該 task 會回傳一個頻道讓該玩家的 task 聆聽狀態(其中一個狀態是用戶端接收到炸彈,此時 task 收到的狀態會包含一個回傳使用者動作的狀態),一個頻道讓該玩家的 task 聆聽記分板,跟一個頻道讓該玩家的 task 回傳用戶端離線了。

該 task 需要處理以下事件:

  • 新增的玩家(聆聽加入遊戲的申請)
  • 玩家的移動炸彈回應(聆聽所傳送的頻道的回應)
  • 玩家的離線(聆聽玩家離線)

以下是在之後的版本中可以增加的事物:

  • 在只有一個玩家時,那個玩家會一直拿到炸彈
    • 可以在遊戲內加上一個電腦玩家
    • 讓玩家不足時先在等待室等
  • 可以讓玩家連到不同的遊戲
  • 玩家太久沒傳炸彈可以被視為 AFK
  • 多於一個炸彈
    • 似乎比我想的麻煩很多

版本2 處理有多於一個炸彈的狀況

原本的設計中,玩家的 task 跟一場遊戲的 task 分開,玩家 task 收到「收到炸彈」的訊息後,會等待連到對應客戶端的 websocket 通道回應訊息或是斷線。在只有一個玩家的狀況下,這不是太大的問題,畢竟這時伺服器不會需要再傳送其他更新狀況的封包(因為炸彈只有一顆)。不過這個作法在有多於一顆炸彈的狀況下是行不通的,例如玩家可能在已經收到一顆炸彈的狀況下收到另外一顆炸彈。

一個可行的處理方式是以狀態機的方式重寫原本的玩家 task。 每個玩家 task 在加入一場遊戲之後進去狀態機的狀態,聆聽玩家的封包回應和遊戲狀態的更新。 玩家 task 本身紀錄自身每個位置的狀態,並根據遊戲狀態對封包做出回應。

另外一個可行的方式是玩家 task 召喚 COUNT 個 subtask 負責處理炸彈,而玩家 task 根據收到 MOVE 封包的 index 將封包分送給各個 task。 這個方法相較上面的方法需要多召喚 subtask,但是若需要修改程式,對各個炸彈進行處理可能更加輕鬆。

我先以第一個方法修改程式。

此外,要有多個炸彈,遊戲的 task 也需要進行修改。 在原本的設計中,遊戲 task 同時等待一個玩家藉由 oneshot 通道回應、任何玩家藉由 mpsc 通道通知自己離開、或任何新玩家想要加入。 在炸彈數量不只一個時,我們可以改使用 mpsc 通道聆聽回應,或 JoinSet 或 FuturesUnordered 來一次 COUNT 個 oneshot 通道。

multi-bomb-test's People

Contributors

edwar4rd avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.