完善游戏功能
游戏逻辑开发进度:■■■■□□□□□□□□
本章结束开发进度:■■■■■■■■□□□□
上一章的答案
createPlayer方法其实就是创建一个Player对象,然后指定坐标,放入$players数组中,但是怎么区分寻找者和躲藏者呢?我们可以用最简单粗暴的方法,先来后到。
Game类:
<?php...class 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变量,增减对应$player的x或y坐标,应该直接调用$player的移动方法,所以需要新增两部分代码:
Game类:
<?php...class Game{...public function playerMove($playerId, $direction){$this->players[$playerId]->{$direction}();}}
Player类:
<?php...class Player{...public function up(){$this->x--;}public function down(){$this->x++;}public function left(){$this->y--;}public function right(){$this->y++;}}
尝试打印地图
目前我们三个实体类的基础游戏逻辑就写得差不多了,但是我们的游戏到现在都还没运行过,我们需要一个能直观看到地图、玩家的画面。
做题时间
- 在
Game类中新增printGameMap()方法,打印游戏地图。 Game类中变量$gameMap就是我们的游戏Map对象。Map类中也有了getMapData()方法能够获取地图数组数据。
Game类:
<?php...class 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:
<?phprequire_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()方法,使他能够输出两个玩家的位置 Game类中的变量$players保存了两个Player对象。Player类中的变量$x和$y保存了玩家的坐标,$type保存了该对象的类型,但是好像是私有变量?如何获取类中的私有变量呢?
Player类:
<?php...class 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.php中createPlayer()传入的坐标数据小心不要和地图上的墙重叠了哦
Game类:
<?php...class 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()去判断传入的方向是否可以移动 - 每个
Player对象可以获取当前坐标。 - 根据传入的
$direction方向计算出目标坐标。 Game类中可以获取到地图的数据。
Game类:
<?php...class Game{...public function playerMove($playerId, $direction){$player = $this->players[$playerId];if ($this->canMoveToDirection($player, $direction)) {$player->{$direction}();}}private function canMoveToDirection($player, $direction){}}
本章的Homework就在这里啦,请童鞋们一定要尽量独立完成哦,我们将在下一章进行解答。
本章对应Github Commit:第三章结束
当前目录结构:
HideAndSeek├── app│ ├── Manager│ │ └── Game.php│ └── Model│ ├── Map.php│ └── Player.php├── composer.json├── test.php└── vendor├── autoload.php└── composer
