iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 10
0
Microsoft Azure

Azure Serverless 平步青雲,漫步雲端系列 第 10

Day 10- 丹脣外朗,皓齒內鮮:狼人殺 - 實戰 - 前端開發 (二)入口網站

今天直接進入Live Coding的部分,有關影片內容可以看

前言

前幾天帶大家理順專案的流程,昨天定義好前端資料格式後,然後進入正式開發流程。

從StackOverflow 複製程式碼,免費;知道貼到哪邊,無價。

入口網站 TYPESCRIPT

import {
  CreatRoomRequest,
  FindRoomRequest,
} from 'src/app/shared/api/api.interface';
import { ApiService } from 'src/app/shared/api/api.service';
import { TwmhCoreService } from 'src/app/shared/service/twmh-core.service';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { BehaviorSubject } from 'rxjs';
import { v4 as uuidv4 } from 'uuid';
import { Router } from '@angular/router';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss'],
})
export class HomeComponent implements OnInit {
  /**
   * 玩家唯一識別碼
   */
  uuid: string;

  /**
   * 表單送出識別
   * TODO 改為Form Submit
   */
  formSubmited = false;

  /**
   * 載入畫面中
   */
  pageLoading$ = new BehaviorSubject<boolean>(false);

  /**
   * 房間表單
   */
  roomForm: FormGroup;

  constructor(
    private fb: FormBuilder,
    private apiService: ApiService,
    private router: Router,
    private twmhCoreService: TwmhCoreService
  ) {
    // 先取得 LocalStorage 的UUID, 如果未取得就是Null
    this.uuid = localStorage.getItem('TWMHUUID');
    if (!!this.uuid) {
      // 有uuid的話,就檢查本玩家是否有已經在房間內。
      this.findUuidRoom(this.uuid);
    } else {
      // 沒有uuid的話,就生成一組並存入LocalStorage。
      this.uuid = uuidv4();
      localStorage.setItem('TWMHUUID', this.uuid);
    }
    // 將UUID存入共用Service
    this.twmhCoreService.uuid$.next(this.uuid);
  }

  ngOnInit(): void {
    // 初始化的時候建立表單
    // 表單的UUID用來傳送此玩家的識別碼並存入資料庫。
    // RoomID為用來搜尋房間用的。
    this.roomForm = this.fb.group({
      uuid: this.uuid,
      roomID: ['', [Validators.required, Validators.min(4)]],
    });
  }

  /**
   * 使用房間號碼來尋找房間的函數
   */
  findRoom(): void {
    // 跳出載入畫面
    this.pageLoading$.next(true);
    // 標示表單已送出
    this.formSubmited = true;
    // 整理請求的資料格式
    const requestData: FindRoomRequest = this.roomForm.value;
    // 送出資料
    this.apiService.findRoom$(requestData, 'success').subscribe(
      (roomData) => {
        // 將回傳回來的房間資料放入共用Service內
        this.twmhCoreService.room$.next(roomData);
        // 跳轉頁面到房間內的玩家頁面
        this.router.navigate(['room', 'player']);
      },
      (error) => {
        this.twmhCoreService.openSnackBar(error);
      }
    );
  }
  /**
   * 使用已經存在的UUID來尋找原本玩家是否有在房間的函數
   * @param uuid 玩家唯一識別碼
   */
  findUuidRoom(uuid: string): void {
    console.log(uuid);
  }

  /**
   * 創立房間
   */
  createRoom(): void {
    // 跳出載入畫面
    this.pageLoading$.next(true);
    // 標示表單已送出
    this.formSubmited = true;
    // 整理請求的資料格式
    const requestData: CreatRoomRequest = {
      uuid: this.uuid,
    };
    // 送出資料
    this.apiService.createRoom$(requestData, 'success').subscribe(
      (roomData) => {
        // 將回傳回來的房間資料放入共用Service內
        this.twmhCoreService.room$.next(roomData);
        // 跳轉頁面到房間內的玩家頁面
        this.router.navigate(['room', 'host']);
      },
      (error) => {
        this.twmhCoreService.openSnackBar(error);
      }
    );
  }
}

尋找房間功能

https://ithelp.ithome.com.tw/upload/images/20200925/20130168N0uSjZ2wZC.png

就像是前面所說的,有了介面要把後面資料理順,在填寫資料的部分我們需要限制使用者至少填入4個字才尋找房間,而按鈕需要先鎖定,創建房間的部分則是不用受到限制。
所以我們會需要先創建動態表單,我們要保持資料處理(Data)跟範本(HTML)分開的原則,所以定義出ReactiveForm

// 初始化的時候建立表單
// 表單的UUID用來傳送此玩家的識別碼並存入資料庫。
// RoomID為用來搜尋房間用的。
this.roomForm = this.fb.group({
  uuid: this.uuid,
  roomID: ['', [Validators.required, Validators.min(4)]],
});

定義好Room ID是必須要填入的就可以做驗證了!

接下來就直接看驗證流程
https://ithelp.ithome.com.tw/upload/images/20200925/20130168tSTZYZXhbA.png

接下來綁上按鈕的會觸發的函數之後,我們連接到findRoom這個函數,然後建立好之後,開始寫功能,我們寫功能之前會需要有一個API來做測試,而目前API也都還沒建立出來,於是我們使用Observable的特性來寫一個假的API,並且將API的Service給實作出來,並將測試用的假資料建立,定義好請求跟回傳的interface,

資料格式

export interface FindRoomRequest {
  roomID: string;
  uuid: string;
}

export interface Room {
  id: string;
  roomID: string;
  players: RoomPlayers[];
  currentRound: number;
  currentState?: RoomState;
}

我們預設送出跟回傳的格式為這樣,並寫好測試資料,

import { Room } from './api.interface';

// 測試用資料
const createRoomSuccess: Room = {
  id: '1',
  roomID: 'TWMH',
  players: [
    {
      uuid: '',
      isHost: true,
      playerNumber: 0,
      role: '主持人',
    },
  ],
  currentRound: 0,
};

export const createRoomTestingData = {
  success: createRoomSuccess,
};

然後在Api服務內引入測試資料來做假的API

findRoom$ = (requestData: FindRoomRequest, dev?: string): Observable<Room> =>
  of(dev ? apiTestData.createRoomTestingData[dev] : '沒有API').pipe(
    delay(1000)
  );

並加上 delay 延遲來檢查請求跟載入的過場時間,這樣我們就可以有假的API來做回傳的測試資料了。

填寫功能

  /**
   * 使用房間號碼來尋找房間的函數
   */
  findRoom(): void {
    // 跳出載入畫面
    this.pageLoading$.next(true);
    // 標示表單已送出
    this.formSubmited = true;
    // 整理請求的資料格式
    const requestData: FindRoomRequest = this.roomForm.value;
    // 送出資料
    this.apiService.findRoom$(requestData, 'success').subscribe(
      (roomData) => {
        // 將回傳回來的房間資料放入共用Service內
        this.twmhCoreService.room$.next(roomData);
        // 跳轉頁面到房間內的玩家頁面
        this.router.navigate(['room', 'player']);
      },
      (error) => {
        this.twmhCoreService.openSnackBar(error);
      }
    );
  }

秉持著程式碼就是文件的概念填寫,我們按下按鈕之後觸發載入畫面動畫,然後將表單標示為送出,並將請求資料整理好之後送出。
而回傳回來的Room資料放到共用的服務之後就可以跳轉頁面到房間內了!

程式碼就算寫得跟文件一樣,還是要寫文件,因為架構是你自己的世界。

創建房間功能

 /**
   * 創立房間
   */
  createRoom(): void {
    // 跳出載入畫面
    this.pageLoading$.next(true);
    // 標示表單已送出
    this.formSubmited = true;
    // 整理請求的資料格式
    const requestData: CreatRoomRequest = {
      uuid: this.uuid,
    };
    // 送出資料
    this.apiService.createRoom$(requestData, 'success').subscribe(
      (roomData) => {
        // 將回傳回來的房間資料放入共用Service內
        this.twmhCoreService.room$.next(roomData);
        // 跳轉頁面到房間內的玩家頁面
        this.router.navigate(['room', 'host']);
      },
      (error) => {
        this.twmhCoreService.openSnackBar(error);
      }
    );
  }

創建房間功能在畫面上就一個按鈕,我們按下按鈕之後觸發載入畫面動畫,然後將表單標示為送出,並將請求資料(也就是Host本身的UUID)整理好之後送出。
而回傳回來的Room資料放到共用的服務之後就可以跳轉頁面到房間內了!

本日小結

今天帶大家把入口頁面開發完成,接下來就是要帶大家進入房間廝殺!!也是本專案最複雜的地方,明天會帶大家玩主持人畫面開發!


上一篇
Day 09- 丹脣外朗,皓齒內鮮:狼人殺 - 實戰 - 前端開發 (一)
下一篇
Day 11- 掌中乾坤:狼人殺 - 實戰 - 前端開發 (三)主持畫面
系列文
Azure Serverless 平步青雲,漫步雲端30

尚未有邦友留言

立即登入留言