台科大 多媒體導論期末專案
- 王正宏 B11015020
- 楊芷安 B11015033
- 林信佑 B11015034 (2023/06 換到其他組別)
- 吳丰荏 B11015051
- 許誠恩 B11030031
- 廖宣瑜 B11032001
- 簡呈翰 B11032007
- 李宇哲 B11033035
你必須先安裝 nodejs, 並且你電腦的命令列能夠吃到 npm
這個指令,推薦安裝穩定版即可。
npm run install
npm run dev
npm run socket-server
npm run build
@TODO: 請 Kinect 負責人將資訊填入
- 2023-05-12 14:20:00
- 2023-05-19 13:30:00
- 2023-05-19 工作詳細事項
- 2023-05-30 工作詳細事項
- 2023-06-06 工作詳細事項
- 2023-06-09 會議記錄 13:30:00
- 2023-06-12 最後一周衝刺
Full TODO List (前方高能)
註記:
- 後方數字請參考上方新鮮的肝
- 做完後請發 PR 並找兩位組員當 Reviewer,請每次都找不一樣的,最後一位Reviewer 如果接受 PR,請合併並刪除 branch ,並請在下面的 TODO List 打勾
嚴禁躺分🙃
請有決心這東西可能每禮拜花掉你10小時以上的時間。
fullDrive
Desktop Drive, iPadOS, iOS Safari(螢幕方向為直)
mobile
iPadOS, iOS Safari,所有移動設備(除平板外)須包含橫、豎畫面設計。
- figma 使用
- figma 專案建置
- color & component & font library
- 所有按鈕、圖標、角標、開關、單、複選匡設計樣式總覽與對應名稱(僅能為英文小寫與
-
符號) - 彈出式視窗與交互方式設計 -
fullDrive
- Prompt style -
fullDrive
- Succsss & Error(Danger) & Warning & Info 彈出式訊息提示視窗設計 -
fullDrive
- Game logo
- Game name
- 遊戲流程
- 遊戲初始化畫面與流程(nickname, 遊戲模式選擇等等) -
fullDrive
- 遊戲大廳(包含各個prototype) -
fullDrive
- 新手引導(包含各個prototype) -
fullDrive
- 遊戲畫面 -
fullDrive
- 氮氣加速按紐 -
mobile
- 設定菜單
- 網路品質狀態
- 小地圖視窗
- 現在名次
- 當前時速
- 遊戲時間
- 生命值
- Turbo 剩餘量
- Turbo 加速效果
- 名次變化提示
- 碰撞效果
- 氮氣加速按紐 -
- 遊戲結束畫面 -
fullDrive
- 跑道選擇畫面 -
fullDrive
- 搖桿設計 -
mobile
- 氮氣加速控制按鈕 -
mobile
- 帶有進度的 Loading 動畫樣式
- 純 Loading 動畫樣式
- mobile, desktop 遊戲設定畫面 -
fullDrive
- 新手引導跑道樣式(包含指引提示,須根據不同裝置設計對應畫面) -
fullDrive
- Carmara 設定精靈 -
fullDrive
- 性能管理精靈(解析度與 refresh fps) -
fullDrive
- 車身樣式設計工具 -
fullDrive
- 動作定義
- 聲音控制相關偵測
- 臉部偵測與拍照
- 傳送照片到網頁端
- 控制信號定義
- 左轉偵測
- 右轉偵測
- 相機角度調整
- WebSocket Server
- 接入控制
- Turbo 偵測
⎋ | ⇤ | ⇌ | ⌘ |
---|---|---|---|
架構優化 | 底層程序 | 需配合美術 | 重要觀念 |
- Github 專案建置 (1) -
⌘
- Debug tips (All) -
⌘
- Project exec (All) -
⌘
- Github 操作 (All) -
⌘
- html 與 css 知識(All) -
⌘
- Vue, Pinia 學習(All) -
⌘
- API(socket) 流程(All Coding 組,請參閱 06/09 會議記錄) -
⇤
- runningConfig 與 API 制定(All Coding 組) -
⇤
- .env 遷移 (1, 3) -
⇤
- 遷移至 Vue (1, 3, 6) -
⎋
⇤
- Vue Component 規劃 (1, 3) -
⎋
⇤
- 遊戲變數(參數)與 Pinia 變數映射(3) -
⎋
⇤
- 玩家車輛選擇,並能夠控制對應車輛(指定跑道上哪輛車是玩家的)(4) -
⇤
- 動態調整指定車輛的速度、方向、位置 (4) -
⇤
- bug solve - 車輛重新繪製導致無法單獨控制的問題 (All)
- 取得指定車輛或所有車輛狀態(4) -
⇤
- 用戶群組策略管理功能實現 (4) -
⇤
- 後端 API 開發 (1, 4) -
⇤
- 小地圖獨立渲染畫布 (4) -
⇤
- 將 base64 圖片渲染於車身後面 (4) -
⇤
- 文字顯示由 Canvas 畫布改為 標準 HTML 顯示 (2) -
⎋
⇤
⇌
- Vue3 & Pinia support (響應式 DOM 支持) (1, 2) -
⎋
⇤
- Camera, Track, Race, Car 的 Prototype to OOP (6) -
⎋
⇤
- 剩餘的Prototype to OOP(3) -
⎋
⇤
- Camera, Track, Race, Car 的
var
tolet
(6) -⎋
⇤
-
var
tolet
(3, 6) -⎋
⇤
- 遊戲引擎重構(轉換到 ES6 Module 形式),並解決 EsLint 報錯(3, 6) -
⎋
- Remove all the useless args, fn,但不要移除到組員寫的 function (3, 6) -
⌘
⇤
- Camara 視角調整工具 (6) -
⇌
⇤
- 移動端搖桿支持 (7) -
⇌
(joyStick Branch) - 移除搖桿與刪除對應套件,並合併分支 (7)
- 新增function,執行後可以讓車只使用左右轉時也可以前進,再次執行後可以取消這樣的設定(toggle),並且有一變數可以取得當前狀態 (7)
- 車與車碰撞偵測 (7) -
⇤
- 車與建築物碰撞偵測 (7) -
⇤
- 超出跑道偵測 (7) -
⇤
- 跑完一圈 callback (7) -
⇤
- 到達終點 callback (7) -
⇤
- 玩家行駛方向改變 callback(7) -
⇤
- 玩家速度改變 callback(7) -
⇤
- 移動端、Kinect 端自動前進支援(7) -
⇤
- WebSocket 支持 (1, 4, 6, 7) -
⇤
- 多人模式同步其他玩家狀態 (6, 7)
- Canvas 實時自適應渲染 (1) -
⇤
- 後端 API 規劃 (1) -
⇤
- WebSocket 指令定義 (1) -
⇤
- WebSocket 廣播模組 (1, 2) -
⇤
- 多人模式雛形:兩台車可以正常前進與停下,並且同步對方的動作 (6, 7)
- 多人模式身份可識別化 (player_id, socket.id) (6, 7)
- 多人模式 x,y,z 軸同步更新 (6, 7)
- 遊戲大廳設計實現 (1, 2) -
⇤
⇌
- 遊戲主畫面設計實現 (1, 2) -
⇤
⇌
- 遊戲結束畫面設計實現 (1, 2) -
⇤
⇌
- 錯誤顯示 callback 與彈窗設計實現 (1, 2) -
⇤
⇌
- v新手跑道設計 (2) -
⇌
- 可以切換視角到指定車輛 (4) -
⇤
- 遊戲延遲檢測工具 -
⇤
- 設備類型偵測 (1, 2) -
⇤
- Domain & SSL 證書
- Socket Server 部署
- Socket Load Balancer
- 起跑位置不同的公平性問題解決方案 (6)
- 遊戲規則定案 (All)
- 遊戲流程圖 (2)
- i18n 多語系支援 config(1, 7)
event type: command | sync | result | error 注意:為了縮減資料傳輸量,請 client 端將非必要不要將自己的 player_id 加上去
function name | type | sender | broadcast |
---|---|---|---|
set-nickname | command | client -> server | all user |
join-event | command | client -> server | all user |
game-start | command | administer -> server | all user |
game-ranking | sync | server->client | same group |
game-rise | sync | server->client | all user |
alert-client-amount | sync | server->client | all user |
game-end | command | client->server | - |
get-users | command | client->server | - |
car-ranking | command | client->server | same group |
car-straight | command | client->server | same group |
car-straight-cancel | command | client->server | same group |
car-left | command | client->server | same group |
car-left-cancel | command | client->server | same group |
car-right | command | client->server | same group |
car-right-cancel | command | client->server | same group |
car-turbo | command | client->server | same group |
car-turbo-cancel | command | client->server | same group |
car-collision | command | client->server | same group |
car-collision-cancel | command | client->server | same group |
car-collision-cancel | command | client->server | same group |
- | error | server->client | one user |
{
"type": "error",
"data": {
"reasonKey": "..."
}
}
join-event 加入活動
預設活動名稱:花錢的凱子一條龍
代碼:pipeline-of-richer-pay
{
"type": "command",
"data": {
"command": "join-event",
"code": "pipeline-of-richer-pay"
}
}
error
不存在的活動
{
"type": "error",
"data": {
"reasonKey": "ERR_EVENT_NOT_FOUND"
}
}
error
活動尚未開始
{
"type": "error",
"data": {
"reasonKey": "ERR_EVENT_HAVE_NOT_START_YET"
}
}
error
超過本次活動選手上線
{
"type": "error",
"data": {
"reasonKey": "ERR_OVER_CLIENT_AMOUNT"
}
}
set-nickname 設置暱稱
command
client send:
{
"type": "command",
"data": {
"command": "set-nickname",
"nickname": "string"
}
}
error
重複的暱稱
{
"type": "error",
"data": {
"reasonKey": "ERR_DUPLICATED_NICKNAME"
}
}
error
不合法的暱稱
{
"type": "error",
"data": {
"reasonKey": "ERR_NICKNAME_NOT_VALID"
}
}
alert-client-amount 同步當前用戶數
{
"type": "sync",
"data": {
"command": "alert-client-amount",
"clientAmount": 38
}
}
game-start 遊戲開始
command
administer send
{
"type": "command",
"data": {
"command": "game-start"
}
}
error
The game has started
{
"type": "error",
"data": {
"reasonKey": "ERR_GAME_HAS_STARTED"
}
}
error
權限非法
{
"type": "error",
"data": {
"reasonKey": "ERR_PERMISSION_DENY"
}
}
sync
server send to all client
註記: 服務端會根據現在的人數與場次直接分配四組,兩組,一組。members需要根據用戶所在的組別提供對應的組別名單。
rank 在這邊是指你是跑道上的第幾台車。
{
"type": "sync",
"data": {
"command": "game-start",
"members":[
{
"nickname": "B11015020",
"player_id": "blablablablabla",
"rank": 0
},
{
"nickname": "B11015033",
"player_id": "ccccccccccccCat",
"rank": 1
}
]
}
}
game-ranking 遊戲排名
註記:遊戲排名會在該組最後一位發送 `game-end` 後自動向客戶端發送本場遊戲的排名sync
server send to all client (group by userGroup)
註記: 服務端會根據現在的人數與場次直接分配四組,兩組,一組。members需要根據用戶所在的組別提供對應的組別名單。
{
"type": "sync",
"data": {
"command": "game-ranking",
"members":[
{
"nickname": "B11015020",
"player_id": "blablablablabla",
"rank": 1,
"rise": true
},
{
"nickname": "B11015033",
"player_id": "ccccccccccccCat",
"rank": 1,
"rise": false
}
]
}
}
game-rise 遊戲晉級
command
administer send
{
"type": "command",
"data": {
"command": "game-rise"
}
}
error
Previous haven't finish
{
"type": "error",
"data": {
"reasonKey": "ERR_PREVIOUS_GAME_HAVE_NOT_END"
}
}
sync
server send to all client
註記: 服務端會根據場次重新分組,並且移除未晉級的玩家連線,並將有晉級的玩家重新組隊。
rank 在這邊是指你是跑道上的第幾台車。
{
"type": "sync",
"data": {
"command": "game-rise",
"members":[
{
"nickname": "B11015020",
"player_id": "blablablablabla",
"rank": 0
},
{
"nickname": "B11015033",
"player_id": "ccccccccccccCat",
"rank": 1
}
]
}
}
game-end 某玩家跑完了兩圈(結束了這回合)
command
client send to server
rank 在這邊是指你在這回合中的第幾名
{
"type": "command",
"data": {
"command": "game-end",
"position": {
"x": 0,
"y": 0,
"z": 0
},
"rank": 1
}
}
sync
server 廣播給同組的 client
{
"type": "sync",
"data": {
"command": "game-end",
"player_id": ".......",
"position": {
"x": 0,
"y": 0,
"z": 0
},
"rank": 1
}
}
car-* (car-ranking, car-straight, car-left, car-left-cancel...)
- car-ranking: 車輛變換名次時發出
- car-straight: 車輛直走
- car-straight-cancel:車輛取消直走
- car-left: 車輛左轉
- car-left-cancel: 車輛左轉取消
- car-right: 車輛右轉
- car-right-cancel: 車輛右轉取消
- car-turbo: 車輛加速
- car-turbo-cancel: 車輛加速取消
- car-collision: 車輛碰撞
- car-collision-cancel: 車輛碰撞取消
command
client send to server
備註: socket.id = player_id
let socketClients = [
"ojIckSD2jqNzOqIrAGzL",
"blablablablabla"
];
// 取得現在所有連線的使用者(回傳 socket)
const allClientsID = await io.fetchSockets();
// 取得在 "groupX" 範圍的使用者(你想把他理解成房間還是組別都一樣)
const allClientsIdWhoInGroupX = await io.in("groupX").fetchSockets();
// 將 groupX 範圍的使用者都加到 groupY 群組
io.in("groupX").socketsJoin("groupY");
// 將 groupX 範圍的使用者都加到 groupY 與 groupZ 群組
io.in("groupX").socketsJoin(["groupY", "groupZ"]);
// 將 socketClients 陣列中的使用者都加到 groupY 群組
io.in(socketClients).socketsJoin("groupY");
// 將 socketClients 陣列中的使用者從連線中移除
io.in(socketClients).disconnectSockets(true);
// 切斷所有用戶的連線
io.disconnectSockets();
// 廣播一則訊息給除了指定範圍的用戶
io.except("groupX").emit("foo", "bar");
io.except(["groupX", "groupY"]).emit("foo", "bar");