单机游戏架构
游戏逻辑开发进度:□□□□□□□□□□□□
本章结束开发进度:■■■■□□□□□□□□
项目代码
- Github地址:github.com/Zhao-666/Hi…
在Github
上代码有两个分支,master
分支为赵童鞋实际开发时的提交分支,teach
分支为根据课程内容,每章结束时提交的代码。同学们主要可以参考teach
分支,每一次commit
都是每章结束时的项目代码状态。
为什么会有两个分支呢?实际项目开发的时候都是往一个大方向走,总有考虑不周的情况,所以代码就会删删减减的,用来教学就会前后代码不一样,并不适合于编写教程。但是这样的代码提交却更加真实,有兴趣的童鞋可以试着阅读master
分支的代码。
开发环境
教程需要PHP-7.x
版本支持,PHP
环境需要童鞋们自行安装配置,以下是一些有可能有帮助的资料:
Windows:www.apachefriends.org/index.html
Linux:lnmp.org/install.htm…
Mac:不存在的。。赵童鞋没玩过
引入Composer
在合适的位置新建一个文件夹HideAndSeek
作为我们的项目根目录。
为了后续开发的方便,我们需要为我们的项目引入composer
的自动加载机制,并在项目根目录运行以下命令:
composer init
小提示:没有安装
composer
的童鞋需要自行安装喔:pkg.phpcomposer.com/#how-to-ins…启用国内镜像地址,下载速度更快。
国内镜像一:
composer config -g repo.packagist composer https://packagist.phpcomposer.com
国内镜像二:
composer config -g repo.packagist composer https://packagist.laravel-china.org
经过几次回车之后,composer
就会为我们生成一个composer.json
文件,需要在这个文件中增加以下代码:
"autoload": {
"psr-4": {
"App\\": "app"
}
},
再运行一次composer
命令:
composer install
composer
就会生成vendor
文件夹,里面会有一个autoload.php
文件,这个文件就是用来实现类自动加载机制。
建立项目结构
下一步就是编写游戏的逻辑,实现一个单机版的捉迷藏。
在上面创建的文件夹HideAndSeek
中新建一个test.php
文件
HideAndSeek
└─test.php
为什么要新建这个test.php
呢?因为我们现在对整个项目的架构毫无头绪,所以需要将这个游戏逻辑拆分成几个步骤,并且将逻辑预先写在test.php
文件中。
赵童鞋设想的游戏逻辑是这样的:
- 每个玩家要有一个ID,用来区别玩家。
- 要有一个游戏控制器,用来创建玩家、执行移动逻辑、判断游戏是否结束。
- 使用游戏控制器创建玩家,满足人数后游戏开始。
- 使用游戏控制器控制某个玩家进行移动。
test.php
文件:
<?php
$redId = "red_player";
$blueId = "blue_player";
//创建游戏控制器
$game = new Game();
//添加玩家
$game->createPlayer($redId, 6, 1);
//添加玩家
$game->createPlayer($blueId, 6, 10);
//移动坐标
$game->playerMove($redId, 'up');
现在就很明显了,我们首要任务就是先实现这样一个游戏控制器。
在HideAndSeek
文件夹中创建app
文件夹,app
文件夹用来存放我们项目的各种类文件。并在app
文件夹中创建Manager
文件夹,用来存放所有管理者类的类文件,在Manager
文件夹中创建Game
游戏控制器类。
为了composer
能够自动加载类文件,需要在Game
类中加入命名空间:namespace App\Manager
。细心的童鞋已经发现了,我们上面在composer.json
中新增的代码里就为app
文件夹注册了命名空间。
不了解自动加载机制的童鞋可以自行搜索一下
composer psr-4
。
<?php
namespace App\Manager;
class Game
{
}
我们现在要思考一下游戏还需要哪些实体类,我们捉迷藏游戏有玩家,有地图,所以游戏还需要两个实体类:一个是玩家类
,另一个是地图类
,没错,这就是面向对象编程,而不是面向运气编程。
在app
文件夹下新建Model
文件夹,用来存放各种游戏实体类,并在其中新建Player
类和Map
类:
<?php
namespace App\Model;
class Player
{
}
<?php
namespace App\Model;
class Map
{
}
完善各类代码
现在我们需要思考一下,这三个类各自的属性和方法需要有哪些。
Map类
我们先从最简单的Map
类开始:
做题时间
Map
对象应该在创建的时候可以指定长和宽,并生成一个地图。Map
对象中应该有一个数组,用来保存完整的地图数据,我们假设这个数组中,0是墙,1是路。Map
类中需要有一个方法来获取地图数据。
由于生成一个地图的算法有点复杂,我们现在的重点只在于编写游戏逻辑,所以地图数据可以先写死。
<?php
namespace App\Model;
class Map
{
private $width;
private $height;
private $map = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0],
[0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0],
[0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0],
[0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0],
[0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0],
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
];
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
public function getMapData()
{
return $this->map;
}
}
Player类
第二个轮到我们的Player
类:
做题时间
Player
对象应该有一个自己的唯一ID。Player
对象需要有自己的坐标,用来标识他在地图的位置。Player
对象需要有自己的类型,分为寻找者
和躲藏者
。Player
类中需要有四个方向常量用来控制当前坐标,分别是上
下
左
右。
<?php namespace App\Model; class Player {
const UP = 'up';
const DOWN = 'down';
const LEFT = 'left';
const RIGHT = 'right';
const PLAYER_TYPE_SEEK = 1;
const PLAYER_TYPE_HIDE = 2;
private $id;
private $type = self::PLAYER_TYPE_SEEK;
private $x;
private $y;
public function __construct($id, $x, $y)
{
$this->id = $id;
$this->x = $x;
$this->y = $y;
}
public function setType($type)
{
$this->type = $type;
}
public function getId()
{
return $this->id;
}
}
Game类
最后轮到我们的游戏控制器Game
类啦~
做题时间
- 新建一个
Game
对象时需要生成一个地图并且保存地图数据。 Game
中需要一个数组保存两个玩家数据。Game
中需要实现createPlayer()
方法用来添加玩家。Game
中需要实现playerMove()
方法操作玩家移动。<?php namespace App\Manager;
use App\Model\Map;
class Game {
private $gameMap = [];
private $players = [];
public function __construct()
{
$this->gameMap = new Map(12, 12);
}
public function createPlayer($playerId, $x, $y)
{
}
public function playerMove($playerId, $direction)
{
}
}
童鞋们先尝试实现一下createPlayer()
方法和playerMove()
方法应该怎么实现,我们下一章再来揭秘。
本章对应Github Commit
:第二章结束
当前目录结构:
HideAndSeek
├── app
│ ├── Manager
│ │ └── Game.php
│ └── Model
│ ├── Map.php
│ └── Player.php
├── composer.json
├── test.php
└── vendor
├── autoload.php
└── composer