核心要点
我从决定尝试使用PHP和React构建游戏的那一刻起,就开始思考这个问题。“我想制作一个多人经济类游戏,类似于《星露谷物语》,但没有交友方面的内容,并且拥有玩家驱动的经济系统。” 问题是,我对多人游戏的动态性,或者如何思考和实现基于玩家的经济系统一无所知。
我甚至不确定自己是否了解足够的React知识来证明使用它的合理性。我的意思是,我最初的界面——我非常关注服务器和游戏的经济方面——非常适合React。但是当我开始制作耕作/互动方面的内容时呢?我喜欢围绕经济系统构建等距界面的想法。
我曾经观看过dead_lugosi的演讲,她描述了用PHP构建中世纪游戏的过程。Margaret激励了我,那次演讲是我写一本关于JS游戏开发书籍的原因之一。我决心要写下我的经验。也许其他人也可以从我的错误中学习。
(本部分的代码可在以下地址找到:github.com/assertchris-tutorials/sitepoint-making-games/tree/part-1。我已经在PHP 7.1和最新版本的Google Chrome中对其进行了测试。)
后端设置
我首先搜索的是关于构建多人经济系统的指导。我找到一个优秀的Stack Overflow帖子,其中人们解释了需要考虑的各种事情。在我意识到我可能从错误的地方开始之前,我已经看了一半了。“首先:我需要一个PHP服务器。我将有一堆React客户端,所以我想要一个能够处理高并发(甚至可能是WebSockets)的东西。它需要是持久性的:即使玩家不在线,事情也必须发生。”
我开始设置一个异步PHP服务器——来处理高并发并支持WebSockets。我添加了我最近使用PHP预处理器的工作,使事情更清晰,并创建了前几个端点。
来自config.pre
:
<code class="language-php">$host = new Aerys\Host(); $host->expose("*", 8080); $host->use($router = Aerys\router()); $host->use($root = Aerys\root(.."/public")); $web = process .."/routes/web.pre"; $web($router); $api = process .."/routes/api.pre"; $api($router);</code>
我决定对应用程序的HTTP和WebSocket部分使用Aerys。这段代码与Aerys文档看起来非常不同,但这是因为我对所需内容有很好的了解。
运行Aerys应用程序的通常过程是使用类似这样的命令:
<code class="language-bash">vendor/bin/aerys -d -c config.php</code>
有很多代码需要重复,而且它没有处理我想使用PHP预处理的事实。我创建了一个加载器文件。
来自loader.php
:
<code class="language-php">return Pre\processAndRequire(__DIR__ . "/config.pre");</code>
然后我安装了我的依赖项。这是来自composer.json
:
<code class="language-json">"require": { "amphp/aerys": "dev-amp_v2", "amphp/parallel": "dev-master", "league/container": "^2.2", "league/plates": "^3.3", "pre/short-closures": "^0.4.0" }, "require-dev": { "phpunit/phpunit": "^6.0" },</code>
我想使用amphp/parallel
将阻塞代码从异步服务器中移出,但它无法与amphp/aerys
的稳定标签一起安装。这就是我使用dev-amp_v2
分支的原因。
我认为包含某种模板引擎和服务定位器是个好主意。我选择了PHP League的每个版本。最后,我添加了pre/short-closures
,既用于处理config.pre
中的自定义语法,也用于我之后计划使用的短闭包……
然后我开始创建路由文件。来自routes/web.pre
:
<code class="language-php">use Aerys\Router; use App\Action\HomeAction; return (Router $router) => { $router->route( "GET", "/", new HomeAction ); };</code>
以及来自routes/api.pre
:
<code class="language-php">use Aerys\Router; use App\Action\Api\HomeAction; return (Router $router) => { $router->route( "GET", "/api", new HomeAction ); };</code>
虽然是简单的路由,但这有助于我测试config.pre
中的代码。我决定让这些路由文件返回闭包,这样我就可以向它们传递一个类型化的$router
,它们可以向其中添加自己的路由。最后,我创建了两个(类似的)操作。
来自app/Actions/HomeAction.pre
:
<code class="language-php">namespace App\Action; use Aerys\Request; use Aerys\Response; class HomeAction { public function __invoke(Request $request, Response $response) { $response->end("hello world"); } }</code>
最后的润色是添加快捷脚本,以启动Aerys服务器的开发和生产版本。
来自composer.json
:
<code class="language-json">"scripts": { "dev": "vendor/bin/aerys -d -c loader.php", "prod": "vendor/bin/aerys -c loader.php" }, "config": { "process-timeout": 0 },</code>
完成所有这些后,我可以启动一个新的服务器,只需键入以下命令即可访问http://127.0.0.1:8080:
<code class="language-bash">composer dev</code>
前端设置
“好的,既然我已经让PHP方面的事情相对稳定了;我该如何构建ReactJS文件呢?也许我可以使用Laravel Mix……?”
我不太想创建一个全新的构建链,而且Mix也已被重建为可在非Laravel项目中良好工作。虽然配置和扩展相对容易,但它默认情况下更偏向VueJS。
我首先要做的是安装一些NPM依赖项。来自package.json
:
<code class="language-json">"devDependencies": { "babel-preset-react": "^6.23.0", "bootstrap-sass": "^3.3.7", "jquery": "^3.1.1", "laravel-mix": "^0.7.5", "react": "^15.4.2", "react-dom": "^15.4.2", "webpack": "^2.2.1" },</code>
Mix使用Webpack来预处理和捆绑JS和CSS文件。我还需要安装React和相关的Babel库来构建jsx文件。最后,我添加了Bootstrap文件,以获得一些默认样式。
Mix自动加载自定义配置文件,所以我添加了以下内容。来自webpack.mix.js
:
<code class="language-javascript">let mix = require("laravel-mix") // load babel presets for jsx files mix.webpackConfig({ "module": { "rules": [ { "test": /jsx$/, "exclude": /(node_modules)/, "loader": "babel-loader" + mix.config.babelConfig(), "query": { "presets": [ "react", "es2015", ], }, }, ], }, }) // set up front-end assets mix.setPublicPath("public") mix.js("assets/js/app.jsx", "public/js/app.js") mix.sass("assets/scss/app.scss", "public/css/app.css") mix.version()</code>
我需要告诉Mix如何处理jsx文件,所以我添加了与通常放在.babelrc
中的配置相同的配置。我计划让单个JS和CSS入口点进入应用程序的各个部分。
注意:未来版本的Mix将内置支持构建ReactJS资产。届时,可以删除mix.webpackConfig
代码。
再一次,我创建了一些快捷脚本,以节省大量的打字工作。来自package.json
:
<code class="language-php">$host = new Aerys\Host(); $host->expose("*", 8080); $host->use($router = Aerys\router()); $host->use($root = Aerys\root(.."/public")); $web = process .."/routes/web.pre"; $web($router); $api = process .."/routes/api.pre"; $api($router);</code>
所有三个脚本都使用了Webpack变量命令,但它们在除此之外的操作方面有所不同。dev
构建了JS和CSS文件的调试版本。-w
开关启动了Webpack监视器(以便可以部分重建捆绑包)。-p
开关启用了精简的生产版本的捆绑包。
由于我使用了捆绑版本控制,所以我需要一种方法来引用类似/js/app.60795d5b3951178abba1.js
的文件,而无需知道哈希值。我注意到Mix喜欢创建清单文件,所以我制作了一个辅助函数来查询它。来自helpers.pre
:
<code class="language-bash">vendor/bin/aerys -d -c config.php</code>
Aerys知道如何在它们以$val = yield $promise
的形式出现时处理promise,所以我使用了Amp的Promise实现。读取并解码文件后,我可以查找匹配的文件路径。我调整了HomeAction
。来自app/Actions/HomeAction.pre
:
<code class="language-php">return Pre\processAndRequire(__DIR__ . "/config.pre");</code>
我意识到我可以继续创建返回promise的函数,并以这种方式使用它们来保持代码的异步性。这是我的JS代码,来自assets/js/component.jsx
:
<code class="language-json">"require": { "amphp/aerys": "dev-amp_v2", "amphp/parallel": "dev-master", "league/container": "^2.2", "league/plates": "^3.3", "pre/short-closures": "^0.4.0" }, "require-dev": { "phpunit/phpunit": "^6.0" },</code>
……以及来自assets/js/app.jsx
:
<code class="language-php">use Aerys\Router; use App\Action\HomeAction; return (Router $router) => { $router->route( "GET", "/", new HomeAction ); };</code>
毕竟,我只是想看看Mix是否会编译我的jsx文件,以及我是否可以使用异步mix
函数再次找到它们。事实证明它有效!
注意:每次都使用mix
函数是很昂贵的,特别是如果我们正在加载相同的文件。相反,我们可以在服务器引导阶段加载所有模板,并在需要时从操作内部引用它们。我们启动Aerys的配置文件可以返回一个promise(例如Amp\all
给我们的那种),因此我们可以在服务器启动之前解析所有模板。
使用WebSockets连接
我几乎已经设置好了。最后要做的是通过WebSockets连接后端和前端。我发现这相对简单,使用一个新类。来自app/Socket/GameSocket.pre
:
<code class="language-php">use Aerys\Router; use App\Action\Api\HomeAction; return (Router $router) => { $router->route( "GET", "/api", new HomeAction ); };</code>
……以及对web路由的轻微修改(来自routes/web.pre
):
<code class="language-php">namespace App\Action; use Aerys\Request; use Aerys\Response; class HomeAction { public function __invoke(Request $request, Response $response) { $response->end("hello world"); } }</code>
现在,我可以更改JS以连接到此WebSocket,并将消息发送到连接到它的每个人。来自assets/js/component.jsx
:
<code class="language-json">"scripts": { "dev": "vendor/bin/aerys -d -c loader.php", "prod": "vendor/bin/aerys -c loader.php" }, "config": { "process-timeout": 0 },</code>
当我创建一个新的Component
对象时,它将连接到WebSocket服务器,并为新消息添加一个事件监听器。我添加了一些调试代码——以确保它能够正确连接,并发送新的消息。
我们稍后会详细介绍PHP和WebSockets,别担心。
总结
在本部分中,我们研究了如何设置一个简单的异步PHP Web服务器,如何在非Laravel项目中使用Laravel Mix,甚至如何使用WebSockets将后端和前端连接在一起。
哇!涵盖了很多内容,而且我们还没有编写一行游戏代码。加入我在第二部分,我们将开始构建游戏逻辑和React界面。
(本文由Niklas Keller同行评审。感谢所有SitePoint的同行评审者,使SitePoint的内容达到最佳状态!)
使用ReactJS和PHP进行游戏开发的常见问题解答(FAQ)
ReactJS和PHP在游戏开发中具有高度的兼容性。ReactJS是一个JavaScript库,非常适合构建用户界面,尤其适用于单页应用程序。它允许快速、响应迅速的网页设计。另一方面,PHP是一种服务器端脚本语言,非常适合后端开发。它可以处理数据库、用户身份验证和服务器端逻辑。当一起使用时,ReactJS可以处理前端,创建动态且交互式用户界面,而PHP则管理后端。
是的,你可以在ReactJS游戏中使用PHP进行游戏逻辑。虽然ReactJS处理用户界面,但PHP可以在服务器端管理游戏逻辑。这包括处理数据、管理用户会话和控制游戏规则。这种关注点分离允许更井然有序且高效的开发过程。
ReactJS为游戏开发提供了许多好处。它的虚拟DOM允许高效的更新和渲染,使游戏运行更流畅。它还支持可重用的组件,这可以大大加快开发时间。此外,ReactJS拥有庞大的社区和丰富的资源,使查找问题的解决方案或学习新技术更容易。
PHP在游戏开发中具有多项优势。它是一种服务器端语言,这意味着它可以处理数据管理、用户身份验证和服务器端游戏逻辑。PHP也很容易学习,语法简单,并且拥有庞大的开发者社区。它也具有高度的可扩展性,使其适合可能需要处理大量用户的游戏。
要开始使用ReactJS和PHP开发游戏,你首先需要学习这两种语言的基础知识。有很多在线资源和教程可用。一旦你熟悉了这些语言,你可以从构建简单的游戏开始。这可以是一个基本的文本游戏或一个简单的益智游戏。随着你获得更多经验,你可以开始构建更复杂的游戏。
是的,有几个资源和库可以帮助使用ReactJS和PHP进行游戏开发。对于ReactJS,像React Game Kit和React Game Engine这样的库非常有用。对于PHP,你可能会发现像PHP-SDL或Wyvern这样的库很有用。此外,在线还有很多教程、指南和论坛,你可以在那里学习更多知识并获得帮助。
是的,你可以使用ReactJS和PHP构建多人游戏。ReactJS可以处理用户界面,而PHP可以管理服务器端逻辑,包括管理玩家会话和跨多个客户端同步游戏状态。
使用ReactJS和PHP,你可以构建各种各样的游戏。这包括简单的文本游戏、益智游戏、平台游戏、角色扮演游戏,甚至是多人在线游戏。可能性是巨大的,限制实际上是你的想象力和技能水平。
在一个使用ReactJS和PHP开发的游戏中,可以使用服务器端的PHP处理数据。这可以包括玩家数据、游戏状态、分数等等。这些数据可以存储在数据库中,并且可以使用PHP与这个数据库进行交互,根据需要检索和更新数据。
在一个使用ReactJS开发的游戏中,可以使用React的事件处理系统处理用户输入。这可以包括鼠标点击、键盘按键和触摸事件。React的事件处理系统功能强大且灵活,允许你轻松控制游戏如何响应用户输入。
以上是与React和PHP的游戏开发:它们的兼容性如何?的详细内容。更多信息请关注PHP中文网其他相关文章!