# Slots game project - Social iOS App 為例 ```flow st=>start: main enter=>operation: AppDelegate::applicationDidFinishLaunching() isLogin=>condition: 曾經登入 login=>operation: Login Scene lobby=>operation: Lobby Scene select=>operation: Select Game e=>end: Enter Game st->enter->isLogin isLogin(no)->login->lobby isLogin(yes)->lobby->select->e ``` ## Client 和 Server 之間的溝通 一般來說傳輸資料的兩端會分為 客戶端 ( Client ) 跟 伺服器端 ( Server ) Client: 主要會發送 「 請求 request 」到 Server 端 Server: 收到 request 開始處理資料,完成後會回傳 「回應 response 」到 Client 端 ```sequence Clent->Server: 發送 HttpRequest Server->Clent: 回傳 HttpResponse ``` ### Login Phase ```sequence Clent->Server: PreConfigurationRequest Note right of Server: PreConfigurationServlet Server->Clent: PreConfigurationResponse Note left of Clent: 畫面導到Login Scene Clent->Server: LoginRequest Note right of Server: LoginServlet Server->Clent: LoginResponse Clent->Server: GameListRequest Note right of Server: GameListServlet Server->Clent: GameListResponse Note left of Clent: 畫面進入Lobby ``` ### Select Game Phase ```sequence Note left of Clent: 點擊遊戲Icon Clent->Server: 發送 SelectGameRequest Note right of Server: SelectGameServlet Server->Clent: SelectGameResponse Note left of Clent: 從SelectGameResponse取得PlayerMathData, PaytableData等資料並進入遊戲畫面 ``` ```c++= //每次spin都會產生一筆PlayerMathData紀錄. class PlayerMathData : public Payload { } ``` ```c++= //賠付表 class PaytableData { } ``` ## Project 架構 - Game Releated ```graphviz digraph hierarchy { nodesep=1.0 // increases the separation between nodes node [color=Red,fontname=Courier,shape=box] //All nodes will this shape and colour edge [color=Blue, style=dashed] //All the lines look like this GameFactory->{IntroAnimation OutroAnimation GameBackground GameLayer Paytable GameReels GameIcon}[label="create", fontcolor=darkgreen] GameReels->{GameReel GameSymbol}[label="create", fontcolor=darkgreen] } ``` ### GameFactory 主要功能為創建遊戲相關的元件和預載資源(圖資/音效). ### GameBackground 設定一般遊戲以及免費遊戲的背景. ### GameIcon 都用Spine產生Icon居多, 故可繼承**SpineIcon** class省去大量的common code ```c++= class SpineIcon : public GameIcon { } ``` ### GameLayer ```flow st=>start: GameLayer::load() enter=>operation: GameLayer::onEnter() spin=>operation: 玩家按下spin(GameLayer::spin()) spinCallback=>operation: 收到Server回覆後, 通知輪軸停下的符號(stops), 當輪軸停到正確位置後 setEndSpinState=>operation: GameLayer::setEndSpinState() st->enter->spin->spinCallback->setEndSpinState ``` ```c++= void GameLayer::load() { //載入資源 //加入Background //加入Reels //加入Game Control以及設定相關Callback } ``` ```c++= void GameLayer::onEnter() { //SelectGameResponse回傳上次遊戲的PlayerMathData, client根據此PlayerMathData設定遊戲畫面 } ``` ```c++= void GameLayer::spin() { //通知輪軸開始滾動 reels->spin([=] { }); //發送SpinRequest to Server GameManager::spin(_game, _selections, _creditPerSelection, _anteBetLevel, [=] (std::shared_ptr<SlotSpinResponse> response) { //等到收到Server回覆後通知Reels設定Stops rls->setStops(mathData->getStops(), mathData, response->getLevelsPassed().size() > 0 || ProgressiveState::getTotalQueuedProgressiveWinTotal() > 0); }); } ``` ```c++= void GameLayer::setEndSpinState() { if(_mathData->isTriggeredFreeGamesFromBaseGame()) { //一般遊戲觸發免費遊戲流程: //如果有win進行賠付 //顯示Intro Animation //Intro Animation顯示後, 則開始免費遊戲 } else if(_mathData->isTriggeredBonusPick()) { //觸發Bonus Pick(小遊戲)流程: //如果有win進行賠付 //顯示Intro Animation //Intro Animation顯示後, 則開始小遊戲 } else if(this->isFreeSpin() || _mathData->isLastFreeGame()) { //免費遊戲流程 } else if(this->isAutoSpin()) { //一般遊戲且在自動模式下的流程 } else { //一般遊戲且非自動模式下的流程 } // 根據以上不同的情境, 有win會進行賠付, 反之則在免費遊戲或自動遊戲時會自行下一場遊戲 } ``` ### GameReels, GameReel, GameSymbol ![](https://i.imgur.com/mVmXquN.jpg) 此GameReels上有5個GameReel, 每個GameReel上顯示3個GameSymbol. ```c++= void NutcrackerReels::setStops(const std::vector<int>& stops, std::shared_ptr<PlayerMathData> mathData, bool jackpotWonOrLevelUp) { //根據Reel狀態插入Symbol for(int column = 0; column < NUM_COLUMNS; column++) { auto reel = getReel(column); if(reel->getStatus() == Reel::ReelStatus::Stopped) { // 當Reel為停止狀態 for(int row = 0; row < NUM_ROWS; row++) { int symbolidx = stops[column + (row * NUM_COLUMNS)]; auto symbol = NutcrackerSymbol::create(symbolidx, mathData); reel->insertSymbol(symbol, row); } } else { // 當Reel在滾動時 // 設定stops, 並讓Reel控制stops停在正確的位置 reel->setStopSymbols(stopsForReel, bounceForReel); } } } ``` ```c++= void NutcrackerReels::spin(std::function<void()> spinComplete, std::shared_ptr<PlayerMathData> mathData) { // GameLayer通知Reels開始滾動, 此時Reels會將之前Server提供的Display reel strip隨機取段插入Reel並開始滾動. // 直到GameLayer收到Server spin response, 並且Reels設定stops後. // Reel會依序停下. 當全部Reel都停下後會通知GameLayer } ``` ```c++= void NutcrackerReels::showSelectionWin(int selection, long long symbolMask, int multiplier) { // 顯示哪條賠付線(組合), 哪個Symbol贏得獎金. } ``` ### GameMultiplier - in GameReels.cpp ### IntroAnimation and OutroAnimation - **Intro Animation**: 進入Free game前的動畫, 通知玩家贏得幾場免費遊戲 ![](https://i.imgur.com/O0cWRdK.jpg) - **Outro Animation**: Free game結束後的動畫, 通知玩家在免費遊戲期間總共贏得多少獎金 ![](https://i.imgur.com/h1SZQiv.jpg) ### Paytable Game Feature, Wild/Scatter敘述, Paytable, Lines等遊戲介紹