完善游戏功能

游戏逻辑开发进度:■■■■□□□□□□□□

本章结束开发进度:■■■■■■■■□□□□

上一章的答案

createPlayer方法其实就是创建一个Player对象,然后指定坐标,放入$players数组中,但是怎么区分寻找者躲藏者呢?我们可以用最简单粗暴的方法,先来后到。

Game类:

  1. <?php
  2. ...
  3. class Game
  4. {
  5. ...
  6. public function createPlayer($playerId, $x, $y)
  7. {
  8. $player = new Player($playerId, $x, $y);
  9. if (!empty($this->players)) {
  10. $player->setType(Player::PLAYER_TYPE_HIDE);
  11. }
  12. $this->players[$playerId] = $player;
  13. }
  14. }

第一个添加的将会使用Player类默认的寻找者,第二个添加的将$player对象设置为躲藏者

playerMove()方法也很简单,通过传入的$direction变量,增减对应$playerxy坐标,应该直接调用$player的移动方法,所以需要新增两部分代码:

Game类:

  1. <?php
  2. ...
  3. class Game
  4. {
  5. ...
  6. public function playerMove($playerId, $direction)
  7. {
  8. $this->players[$playerId]->{$direction}();
  9. }
  10. }

Player类:

  1. <?php
  2. ...
  3. class Player
  4. {
  5. ...
  6. public function up()
  7. {
  8. $this->x--;
  9. }
  10. public function down()
  11. {
  12. $this->x++;
  13. }
  14. public function left()
  15. {
  16. $this->y--;
  17. }
  18. public function right()
  19. {
  20. $this->y++;
  21. }
  22. }

尝试打印地图

目前我们三个实体类的基础游戏逻辑就写得差不多了,但是我们的游戏到现在都还没运行过,我们需要一个能直观看到地图、玩家的画面。

做题时间

  1. Game类中新增printGameMap()方法,打印游戏地图。
  2. Game类中变量$gameMap就是我们的游戏Map对象。
  3. Map类中也有了getMapData()方法能够获取地图数组数据。

Game类:

  1. <?php
  2. ...
  3. class Game
  4. {
  5. ...
  6. public function printGameMap()
  7. {
  8. $mapData = $this->gameMap->getMapData();
  9. foreach ($mapData as $line) {
  10. foreach ($line as $value) {
  11. if (empty($value)) {
  12. echo "墙,";
  13. } else {
  14. echo " ";
  15. }
  16. }
  17. echo PHP_EOL;
  18. }
  19. }
  20. }

打印地图的代码很简单,就是遍历我们的地图数据,当数组里的元素值为0的时候就是,否则就是就不用输出文字啦~

回到我们的test.php,我们将在这里调用新写的printGameMap()方法输出地图数据。由于我们要使用了composer的自动加载机制,所以要先在test.php文件的开头加上以下代码:

  1. require_once __DIR__ . '/vendor/autoload.php';

引入autoload.php文件后,我们就能愉快的使用命名空间了,童鞋们记得要同时引入Game类哦。

test.php

  1. <?php
  2. require_once __DIR__ . '/vendor/autoload.php';
  3. use App\Manager\Game;
  4. $redId = "red_player";
  5. $blueId = "blue_player";
  6. //创建游戏控制器
  7. $game = new Game();
  8. //添加玩家
  9. $game->createPlayer($redId, 6, 1);
  10. //添加玩家
  11. $game->createPlayer($blueId, 6, 10);
  12. //移动坐标
  13. $game->playerMove($redId, 'up');
  14. //打印地图
  15. $game->printGameMap();

在控制台输入以下代码,运行test.php文件:

  1. php test.php

如果童鞋们的代码没问题的话,控制台应该会输出以下内容:

3 完善游戏功能 - 图1

加入玩家坐标

光输出地图的数据可是不够的,我们还要把玩家的坐标加在地图里面。

做题时间

  1. 优化printGameMap()方法,使他能够输出两个玩家的位置
  2. Game类中的变量$players保存了两个Player对象。
  3. Player类中的变量$x$y保存了玩家的坐标,$type保存了该对象的类型,但是好像是私有变量?如何获取类中的私有变量呢?

Player类:

  1. <?php
  2. ...
  3. class Player
  4. {
  5. ...
  6. public function getType()
  7. {
  8. return $this->type;
  9. }
  10. public function getX()
  11. {
  12. return $this->x;
  13. }
  14. public function getY()
  15. {
  16. return $this->y;
  17. }
  18. ...
  19. }

我们首先需要在Player类中新增一个方法getType()获取对象的类型,getX()getY()获取玩家的坐标数据。

在打印地图数据之前,将玩家的地图坐标,以及类型标识放进$mapData中,但由于我们的地图里1是路,玩家类型中1寻找者,直接放进去就会搞混了玩家和路的值,所以我们要在玩家类型的值上进行+1操作再放进地图,并且增加一个文字映射数组。

test.phpcreatePlayer()传入的坐标数据小心不要和地图上的重叠了哦

Game类:

  1. <?php
  2. ...
  3. class Game
  4. {
  5. ...
  6. public function printGameMap()
  7. {
  8. $mapData = $this->gameMap->getMapData();
  9. $font = [2 => '追', 3 => '躲'];
  10. /* @var Player $player */
  11. foreach ($this->players as $player) {
  12. $mapData[$player->getX()][$player->getY()] = $player->getType() + 1;
  13. }
  14. foreach ($mapData as $line) {
  15. foreach ($line as $item) {
  16. if (empty($item)) {
  17. echo "墙,";
  18. } elseif ($item == 1) {
  19. echo " ";
  20. } else {
  21. echo $font[$item] . ',';
  22. }
  23. }
  24. echo PHP_EOL;
  25. }
  26. }
  27. }

重新运行一次我们的test.php文件,应该就会输出以下内容:

3 完善游戏功能 - 图2

寻找者躲藏者就显示出来啦,并且由于我们打印地图前调用playerMove()方法移动寻找者并传入了up寻找者的坐标在地图上往上走了一步。

增加地图判断

我们尝试把寻找者再往上走两步试试,在test.php文件中再调用两次playerMove()方法并打印地图,运行test.php文件:

3 完善游戏功能 - 图3

哦嚯,我们的寻找者走到上面了,这谁顶得住啊。

目前的playerMove()方法是不完整的,需要再继续优化。

做题时间

  1. 加入一个方法canMoveToDirection()去判断传入的方向是否可以移动
  2. 每个Player对象可以获取当前坐标。
  3. 根据传入的$direction方向计算出目标坐标。
  4. Game类中可以获取到地图的数据。

Game类:

  1. <?php
  2. ...
  3. class Game
  4. {
  5. ...
  6. public function playerMove($playerId, $direction)
  7. {
  8. $player = $this->players[$playerId];
  9. if ($this->canMoveToDirection($player, $direction)) {
  10. $player->{$direction}();
  11. }
  12. }
  13. private function canMoveToDirection($player, $direction)
  14. {
  15. }
  16. }

本章的Homework就在这里啦,请童鞋们一定要尽量独立完成哦,我们将在下一章进行解答。

本章对应Github Commit第三章结束

当前目录结构:

  1. HideAndSeek
  2. ├── app
  3. ├── Manager
  4. └── Game.php
  5. └── Model
  6. ├── Map.php
  7. └── Player.php
  8. ├── composer.json
  9. ├── test.php
  10. └── vendor
  11. ├── autoload.php
  12. └── composer