用Swoole來寫個聯機對戰遊戲呀!(三)完善遊戲功能

寫程式的趙童鞋發表於2019-04-25

遊戲邏輯開發進度:■■■■□□□□□□□□

本章結束開發進度:■■■■■■■■□□□□

上一章的答案

createPlayer方法其實就是建立一個Player物件,然後指定座標,放入$players陣列中,但是怎麼區分追捕者躲藏者呢?我們可以用最簡單粗暴的方法,先來後到。

Game類:

public function createPlayer($playerId, $x, $y)
{
    $player = new Player($playerId, $x, $y);
    if (!empty($this->players)) {
        $player->setType(Player::PLAYER_TYPE_HIDE);
    }
    $this->players[$playerId] = $player;
}
複製程式碼

第一個新增的將會使用Player類預設的追捕者,第二個新增的將$player物件設定為躲藏者

playerMove()方法也很簡單,通過傳入的$direction變數,增減對應$playerxy座標,應該直接呼叫$player的移動方法,所以需要新增兩部分程式碼:

Game類:

public function playerMove($playerId, $direction)
{
    $this->players[$playerId]->{$direction}();
}
複製程式碼

Player類:

public function up()
{
    $this->x--;
}

public function down()
{
    $this->x++;
}

public function left()
{
    $this->y--;
}

public function right()
{
    $this->y++;
}
複製程式碼

嘗試列印地圖

目前我們三個實體類的基礎遊戲邏輯就寫得差不多了,但是我們的遊戲到現在都還沒執行過,我們需要一個能直觀看到地圖、玩家的畫面。

請童鞋們自己嘗試在Game類中新增printGameMap()方法,列印遊戲地圖。

  1. Game類中有一個變數$gameMap就是我們的遊戲地圖物件。
  2. Map類中也有了getMapData()方法能夠獲取地圖陣列資料,

Game類:

public function printGameMap()
{
    $mapData = $this->gameMap->getMapData();
    foreach ($mapData as $line) {
        foreach ($line as $value) {
            if (empty($value)) {
                echo "牆,";
            } else {
                echo "    ";
            }
        }
        echo PHP_EOL;
    }
}
複製程式碼

列印地圖的程式碼很簡單,就是遍歷我們的地圖資料,當陣列裡的元素值為0的時候就是,否則就是就不用輸出文字啦~

回到我們的test.php,我們將在這裡呼叫新寫的printGameMap()方法輸出地圖資料。由於我們要使用了composer的自動載入機制,所以要先在test.php檔案的開頭加上以下程式碼:

require_once __DIR__ . '/vendor/autoload.php';
複製程式碼

引入autoload.php檔案後,我們就能愉快的使用名稱空間了,童鞋們記得要引入Game類哦。

test.php:

<?php
require_once __DIR__ . '/vendor/autoload.php';
use App\Manager\Game;

$redId = "red_player";
$blueId = "blue_player";

//建立遊戲控制器
$game = new Game();
//新增玩家
$game->createPlayer($redId, 6, 1);
//新增玩家
$game->createPlayer($blueId, 6, 10);
//移動座標
$game->playerMove($redId, 'up');
//列印地圖
$game->printGameMap();
複製程式碼

在控制檯輸入以下程式碼,執行test.php檔案:

php test.php
複製程式碼

如果童鞋們的程式碼沒問題的話,控制檯應該會輸出以下內容:

牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,
牆,                                    牆,
牆,    牆,                         牆,牆,
牆,牆,牆,牆,    牆,       牆,   牆,牆,
牆,        牆,                         牆,
牆,                          牆,牆,牆,牆,
牆,            牆,                     牆,
牆,        牆,牆,    牆,              牆,
牆,        牆,               牆,   牆,牆,
牆,        牆,牆,        牆,   牆,   牆,
牆,                                     牆,
牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,
複製程式碼

加入玩家座標

光輸出地圖的資料可是不夠的,我們還要把玩家的座標加在地圖裡面,請童鞋們優化printGameMap()方法,使他能夠輸出兩個玩家的位置。

  1. Game類中的變數$players儲存了兩個Player物件。
  2. Player類中的變數$x$y儲存了玩家的座標,$type儲存了該物件的型別,但是好像是私有變數?如何獲取類中的私有變數呢?

Player類:

public function getType()
{
    return $this->type;
}

public function getX()
{
    return $this->x;
}

public function getY()
{
    return $this->y;
}
複製程式碼

我們首先需要在Player類中新增一個方法getType()獲取物件的型別,getX()getY()獲取玩家的座標資料。

在列印地圖資料之前,將玩家的地圖座標,以及型別標識放進$mapData中,但由於我們的地圖裡1是路,玩家型別中1追捕者,直接放進去就會搞混了玩家和路的值,所以我們要在玩家型別的值上進行+1操作再放進地圖,並且增加一個文字對映陣列。

  • test.phpcreatePlayer()傳入的座標資料小心不要和地圖上的重疊了哦

Game類:

public function printGameMap()
{
    $mapData = $this->gameMap->getMapData();
    $font = [2 => '追', 3 => '躲'];
    /* @var Player $player */
    foreach ($this->players as $player) {
        $mapData[$player->getX()][$player->getY()] = $player->getType() + 1;
    }
    foreach ($mapData as $line) {
        foreach ($line as $item) {
            if (empty($item)) {
                echo "牆,";
            } elseif ($item == 1) {
                echo "    ";
            } else {
                echo $font[$item] . ',';
            }
        }
        echo PHP_EOL;
    }
}
複製程式碼

重新執行一次我們的test.php檔案,應該就會輸出以下內容:

牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,
牆,                                    牆,
牆,    牆,                         牆,牆,
牆,牆,牆,牆,    牆,       牆,   牆,牆,
牆,        牆,                         牆,
牆,追,                      牆,牆,牆,牆,
牆,            牆,                 躲,牆,
牆,        牆,牆,    牆,              牆,
牆,        牆,               牆,  牆,牆,
牆,        牆,牆,        牆,   牆,   牆,
牆,                                    牆,
牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,
複製程式碼

追捕者躲藏者就顯示出來啦,並且由於我們列印地圖前呼叫playerMove()方法移動追捕者並傳入了up追捕者的座標在地圖上往上走了一步。

增加地圖判斷

我們嘗試把追捕者再往上走兩步試試,在test.php檔案中再呼叫兩次playerMove()方法並列印地圖,執行test.php檔案:

牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,
牆,                                     牆,
牆,    牆,                         牆,牆,
牆,追,牆,牆,    牆,       牆,    牆,牆,
牆,        牆,                         牆,
牆,                          牆,牆,牆,牆,
牆,            牆,                  躲,牆,
牆,        牆,牆,    牆,              牆,
牆,        牆,              牆,    牆,牆,
牆,        牆,牆,      牆,    牆,    牆,
牆,                                     牆,
牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,牆,
複製程式碼

哦嚯,我們的追捕者走到上面了,這誰頂得住啊。目前的playerMove()方法是不完整的,需要在其中再加入一個方法canMoveToDirection()去判斷傳入的方向是否可以移動。

  1. 每個Player物件可以獲取當前座標。
  2. 根據傳入的$direction方向計算出目標座標。
  3. Game類中可以獲取到地圖的資料。

Game類:

public function playerMove($playerId, $direction)
{
    $player = $this->players[$playerId];
    if ($this->canMoveToDirection($player, $direction)) {
        $player->{$direction}();
    }
}

private function canMoveToDirection($player, $direction)
{
}
複製程式碼

本章的Homework就在這裡啦,請童鞋們一定要儘量獨立完成哦,我們將在下一章進行解答。

當前目錄結構:

HideAndSeek
├── app
│   ├── Manager
│   │   └── Game.php
│   └── Model
│       ├── Map.php
│       └── Player.php
├── composer.json
├── test.php
└── vendor
    ├── autoload.php
    └── composer
複製程式碼

相關文章