Back to Question Center
0

Trải địa hình trò chơi được tạo thủ công với Phản ứng, PHP và WebSockets            Trải địa điểm trò chơi được tạo thủ công với React, PHP và WebSocketsRelated Topics: FrameworksAPIsSecurityPatterns & Thực tiễnDebugging & Semalt

1 answers:
Địa hình Game được tạo thủ công với React, PHP và WebSockets
(số 8)

Phát triển game với PHP và ReactJS

  • Phát triển trò chơi với Phản ứng và PHP: Làm thế nào tương thích được Họ?
  • Địa hình Game được tạo thủ công với React, PHP và WebSockets

Để có một bản giới thiệu về Phản ứng Chất lượng cao, chất lượng cao, bạn không thể đi qua nhà phát triển đầy đủ của nhà phát triển Wes Bos của Canada. Hãy thử khóa học tại đây và sử dụng mã SITEPOINT để nhận 25% giảm giá và để hỗ trợ SitePoint.

Lần trước, tôi bắt đầu kể cho bạn câu chuyện về cách tôi muốn làm một trò chơi - como crear un certificado ssl para iis. Tôi mô tả cách tôi thiết lập máy chủ PHP async, chuỗi xây dựng Laravel Mix, mặt trận phản ứng trước và WebSockets kết nối tất cả những điều này với nhau. Bây giờ, hãy để tôi nói cho bạn biết những gì đã xảy ra khi tôi bắt đầu xây dựng cơ chế trò chơi với sự kết hợp của React, PHP và WebSockets .


Mã cho phần này có thể được tìm thấy tại github. com / assertchris-hướng dẫn / sitepoint-làm-trò chơi / cây / phần-2. Tôi đã thử nghiệm nó với PHP 7. 1 , trong một phiên bản gần đây của Google Chrome.


Trải địa hình trò chơi được tạo thủ công với Phản ứng, PHP và WebSocketsTrải địa điểm trò chơi được tạo thủ công với React, PHP và WebSocketsRelated Topics:
Khung hìnhAPIsSecurityPatterns & PracticesDebugging & Semalt

Làm nông trại

"Semalt bắt đầu đơn giản. Chúng tôi có một 10 của 10 lưới gạch, đầy chứa các công cụ được tạo ngẫu nhiên. "

Tôi quyết định đại diện cho trang trại như là một trang trại , và mỗi ngói như là một Patch . Từ ứng dụng / Mô hình / Trang trại. trước :

  Không gian tên \ Mẫu;class Farm{chiều rộng riêng ${nhận được {return $ this-> width; }}chiều cao cá nhân{nhận được {return $ this-> height; }}công chức __construct (int $ width = 10,int $ chiều cao = 10){$ this-> width = $ width;$ this-> height = $ height;}}   

Tôi nghĩ rằng nó sẽ là một thời gian vui vẻ để thử các macro accessors lớp bằng cách tuyên bố tài sản cá nhân với getters công cộng. Đối với điều này tôi đã phải cài đặt trước / class-accessors (thông qua soạn nhạc yêu cầu ).

Tôi sau đó thay đổi mã socket để cho phép các trang trại mới được tạo ra theo yêu cầu. Từ ứng dụng / Socket / GameSocket. trước :

  không gian tên App \ Socket;sử dụng Aerys \ Yêu cầu;sử dụng Aerys \ Response;sử dụng Aerys \ Websocket;sử dụng Aerys \ Websocket \ Endpoint;sử dụng Aerys \ Websocket \ Message;sử dụng App \ Model \ FarmModel;lớp GameSocket thực hiện Websocket{cá nhân $ farms = [];chức năng công cộng onData (int clientId $,Message $ message){$ body = yield $ message;if ($ body === "trang trại mới") {$ farm = new FarmModel   ;$ payload = json_encode (["trang trại" => ["width" => $ farm-> chiều rộng,"height" => $ farm-> chiều cao,],]);yield $ this-> endpoint-> send ($ payload, $ clientId);$ this-> farms [$ clientId] = $ nông trại;}}chức năng công cộng onClose (int $ clientId,int $ code, string $ reason){unset ($ this-> connections [$ clientId]);unset ($ this-> farms [$ clientId]);}// .}   

Tôi nhận thấy gameSocket tương tự như thế này là trước đây - trừ, thay vì phát sóng tiếng vang, tôi đã kiểm tra trang trại mới và chỉ gửi lại một tin nhắn cho khách hàng đã hỏi.

"Có lẽ đó là thời điểm tốt để có ít nhận dạng hơn với mã React. Tôi sẽ đổi tên thành phần . jsx đến trang trại. jsx . "

Từ tài sản / js / trang trại. jsx :

  nhập Phản hồi từ "phản ứng"class Farm mở rộng phản ứng. socket = new WebSocket ("ws: // 127. 0. 0. 1: 8080 / ws")điều này. ổ cắm. addEventListener ("thông điệp", điều này. onMessage)/ DEBUGđiều này. ổ cắm. addEventListener ("open",    => {điều này. ổ cắm. gửi ("trang trại mới")})}}mặc định xuất khẩu   

Trên thực tế, điều duy nhất tôi thay đổi là gửi trang trại mới thay vì hello world . Mọi thứ khác cũng vậy. Tôi đã phải thay đổi ứng dụng . jsx mã mặc dù. Từ tài sản / js / app. jsx :

  nhập Phản hồi từ "phản ứng"nhập khẩu ReactDOM từ "react-dom"nhập trang trại từ "trang trại / trang trại"ReactDOM. render (,tài liệu. querySelector (". app"))   

Tôi đã ở xa nơi cần thiết, nhưng sử dụng những thay đổi này tôi có thể thấy các hành động của lớp học đang hoạt động, cũng như làm mẫu nguyên mẫu một mẫu yêu cầu / phản hồi cho tương tác WebSocket trong tương lai. Tôi mở bàn điều khiển và nhìn thấy {"trang trại": {"chiều rộng": 10, "chiều cao": 10}} .

"Tuyệt vời!"

Sau đó tôi tạo ra một lớp Patch để đại diện cho mỗi tile. Tôi đã nghĩ rằng đây là nơi mà rất nhiều trò chơi của logic sẽ xảy ra. Từ ứng dụng / Mô hình / PatchModel. trước :

  Không gian tên \ Mẫu;lớp học PatchModel{private $ x{nhận được {return $ this-> x; }}tư nhân $ y{get {return $ this-> y; }}hàm công cộng __construct (int $ x, int $ y){$ this-> x = $ x;$ this-> y = $ y;}}   

Tôi cần phải tạo ra nhiều bản vá lỗi vì có không gian trong một trang trại mới . Tôi có thể làm điều này như một phần của FarmModel xây dựng. Từ ứng dụng / Mô hình / Trang trại. trước :

  Không gian tên \ Mẫu;class FarmModel{chiều rộng riêng ${nhận được {return $ this-> width; }}chiều cao cá nhân{nhận được {return $ this-> height; }}miếng vá cá nhân ${nhận được {return $ this-> patches; }}công chức __construct ($ width = 10, $ height = 10){$ this-> width = $ width;$ this-> height = $ height;$ this-> createPatches   ;}hàm createPatches riêng tư   {for ($ i = 0; $ i <$ this-> width; $ i ++) {$ this-> patches [$ i] = [];for ($ j = 0; $ j <$ this-> height, $ j ++) {$ this-> patches [$ i] [$ j] =mới PatchModel ($ i, $ j);}}}}   

Đối với mỗi ô, tôi tạo một đối tượng mới PatchModel . Những điều này khá đơn giản để bắt đầu, nhưng họ cần một yếu tố ngẫu nhiên - một cách để trồng cây, cỏ dại, hoa .ít nhất là bắt đầu. Từ ứng dụng / Mô hình / PatchModel. trước :

  bắt đầu chức năng công cộng (int $ chiều rộng, chiều cao int,mảng $ bản vá lỗi){if ($ this-> started && random_int (0, 10)> 7) {$ this-> started = true;trở lại đúng;}trả lại giả;}   

Tôi nghĩ rằng tôi sẽ bắt đầu bằng cách phát triển ngẫu nhiên một miếng vá. Điều này đã không thay đổi trạng thái bên ngoài của miếng vá, nhưng nó đã cho tôi một cách để kiểm tra như thế nào họ đã được bắt đầu bởi trang trại. Từ ứng dụng / Mô hình / FarmModel. Đối với người mới bắt đầu, tôi giới thiệu một từ khóa chức năng async bằng cách sử dụng một macro. Bạn thấy đó, Amp xử lý từ khóa bằng cách giải quyết Promises. Thêm vào điểm: khi Amp thấy từ khóa , nó giả định những gì đang được yielded là một Coroutine (trong nhiều trường hợp).

chức năng bình thường, và chỉ cần trả lại một Coroutine từ nó, nhưng đó là một đoạn phổ biến của mã mà tôi cũng có thể đã tạo ra một macro đặc biệt cho nó. Đồng thời, tôi có thể thay thế mã tôi đã thực hiện trong phần trước. Từ người trợ giúp. trước :

  hỗn hợp chức năng async ($ path) {$ manifest = yield Amp \ File \ get (./ / công khai / mix-manifest.json ");$ manifest = json_decode ($ manifest, true);if (isset ($ manifest [$ path])) {return $ manifest [$ path];}ném ngoại lệ mới ("{$ path} not found");}   

Trước đây, tôi đã phải tạo ra một máy phát điện, và sau đó gói nó trong một Coroutine mới :

  sử dụng Amp \ Coroutine;hàm mix ($ path) {$ generator =    => {$ manifest = yield Amp \ File \ get (./ / công khai / mix-manifest.json ");$ manifest = json_decode ($ manifest, true);if (isset ($ manifest [$ path])) {return $ manifest [$ path];}ném ngoại lệ mới ("{$ path} not found");};trả lại Coroutine mới ($ generator   );}   

Tôi đã bắt đầu createPatches phương pháp như trước, tạo mới PatchModel đối tượng cho mỗi x y trong lưới. Sau đó tôi bắt đầu một vòng lặp khác, để gọi phương thức trên mỗi miếng vá. Tôi đã làm những điều này trong cùng một bước, nhưng tôi muốn bắt đầu phương pháp của tôi để có thể kiểm tra các bản vá xung quanh. Điều đó có nghĩa là tôi sẽ phải tạo ra tất cả chúng trước tiên, trước khi làm việc mà các bản vá đã được xung quanh nhau.

Tôi cũng đã thay đổi FarmModel để chấp nhận việc đóng cửa onGrowth . Ý tưởng là tôi có thể gọi đó là sự đóng cửa nếu một miếng vá tăng lên (ngay cả trong giai đoạn bootstrapping).

Mỗi ​​lần vá tăng lên, tôi đặt lại biến đổi $ thay đổi . Điều này đảm bảo các miếng vá sẽ tiếp tục phát triển cho đến khi toàn bộ vượt qua trang trại không có thay đổi. Tôi cũng đã gọi phương thức đóng cửa onGrowth . Tôi muốn cho phép onGrowth là một đóng cửa bình thường, hoặc thậm chí để trả lại một Coroutine . Đó là lý do tại sao tôi cần tạo createPatches một async chức năng.

onGrowth coroutines những điều phức tạp một chút, nhưng tôi thấy nó là điều cần thiết cho phép hành động async khác khi một miếng vá phát triển. Có lẽ sau đó tôi muốn gửi một tin nhắn socket, và tôi chỉ có thể làm điều đó nếu sản lượng đã làm việc bên trong onGrowth . Tôi chỉ có thể sản lượng onGrowth nếu createPatches là một async chức năng. Và bởi vì createPatches là một chức năng async , tôi sẽ cần phải mang nó bên trong GameSocket .

"Thật dễ dàng để có được tắt bởi tất cả những điều cần học tập khi tạo một ứng dụng PHP đầu tiên của async. Semalt bỏ quá sớm! "

Đoạn mã cuối cùng tôi cần viết để kiểm tra xem tất cả các hoạt động này có được trong GameSocket hay không. Từ ứng dụng / Socket / GameSocket. trước :

  if ($ body === "trang trại mới") {$ patches = [];$ farm = new FarmModel (10, 10,(PatchModel $ patch) sử dụng (& $ patches) {array_push ($ patches, ["x" => $ patch-> x,"y" => $ patch-> y,]);});yield $ farm-> createPatches   ;$ payload = json_encode (["trang trại" => ["width" => $ farm-> chiều rộng,"height" => $ farm-> chiều cao,],"patches" => $ vá lỗi,]);yield $ this-> endpoint-> send ($ payload, $ clientId);$ this-> farms [$ clientId] = $ nông trại;}   

Điều này chỉ hơi phức tạp hơn so với mã trước đó tôi đã có. Sau đó, tôi chỉ cần thông qua một bản chụp của các bản vá lỗi cho tải trọng socket.

Trải địa hình trò chơi được tạo thủ công với Phản ứng, PHP và WebSocketsTrải địa điểm trò chơi được tạo thủ công với React, PHP và WebSocketsRelated Topics:
Khung hìnhAPIsSecurityPatterns & PracticesDebugging & Semalt

"Điều gì sẽ xảy ra nếu tôi bắt đầu mỗi miếng vá như bụi khô? Sau đó, tôi có thể làm cho một số vá có cỏ dại, và những người khác có cây ."

Tôi thiết lập về tùy chỉnh các bản vá lỗi. Từ ứng dụng / Mô hình / PatchModel. trước :

  cá nhân $ bắt đầu = sai;tư nhân $ ướt {nhận được {return $ this-> wet ?: false; }};private $ type {get {return $ this-> type?: "bẩn"; }};bắt đầu hàm công cộng (int $ width, int $ height,mảng $ bản vá lỗi){if ($ this-> started) {trả lại giả;}if (random_int (0, 100) <90) {trả lại giả;}$ this-> started = true;$ this-> type = "weed";trở lại đúng;}   

Tôi đã thay đổi trật tự logic xung quanh một chút, thoát ra sớm nếu bản vá đã được bắt đầu. Tôi cũng làm giảm cơ hội tăng trưởng. Nếu không có lối ra sớm, loại vá sẽ được thay đổi để cỏ dại.

Tôi sau đó có thể sử dụng loại này như là một phần của tải trọng tin nhắn socket. Từ ứng dụng / Socket / GameSocket. trước :

  $ trang trại = nông trại mới (10, 10,(PatchModel $ patch) sử dụng (& $ patches) {array_push ($ patches, ["x" => $ patch-> x,"y" => $ patch-> y,"ướt" => $ patch-> ướt,"type" => $ patch-> type,]);});   

Rendering trang trại

Đã đến lúc để hiển thị trang trại, sử dụng quy trình công việc phản hồi mà tôi đã thiết lập trước đây. Tôi đã nhận chiều cao của nông trại, vì vậy tôi có thể làm cho mọi khối bụi khô (trừ khi nó được cho là trồng một loại cỏ dại). Từ tài sản / js / app. jsx :

  nhập Phản hồi từ "phản ứng"class Farm mở rộng phản ứng. Hợp phần{constructor  {siêu  điều này. onMessage = này. onMessage. ràng buộc (điều này)điều này. state = {"nông trại": {"width": 0,"chiều cao": 0,},"bản vá lỗi": [],};}componentWillMount   {điều này. socket = new WebSocket ("ws: // 127. 0. 0. 1: 8080 / ws")điều này. ổ cắm. addEventListener ("thông điệp", điều này. onMessage)/ DEBUGđiều này. ổ cắm. addEventListener ("open",    => {điều này. ổ cắm. gửi ("trang trại mới")})}onMessage (e){hãy để dữ liệu = JSON. phân tích cú pháp (ví dụ dữ liệu);if (data. farm) {điều này. setState ({"trang trại": dữ liệu. trang trại})}if (data. patches) {điều này. setState ({"patches": data. patches})}}componentWillUnmount   {điều này. ổ cắm. removeEventListener (này. onMessage)điều này. socket = null}render    {để hàng = []để cho trang trại = điều này. tiểu bang. nông trạiđể statePatches = điều này. tiểu bang. bản vá lỗifor (let y = 0; y  {nếu (vá x === x && vá.y === y) {className + = "" + vá lỗi. kiểunếu (ướt) {className + = "" + ẩm ướt}}})bản vá lỗi. đẩy(
)}hàng. đẩy(
{bản vá lỗi}
)}trở về (
{hàng}
)}}mặc định xuất khẩu

Tôi đã quên giải thích phần lớn các thành phần trước đó Farm đang làm. Các thành phần Phản hồi là một cách suy nghĩ khác về cách xây dựng các giao diện. Tôi có thể sử dụng các phương pháp như componentWillMount componentWillUnmount để làm quen với các điểm dữ liệu khác (như WebSockets). Và khi tôi nhận được cập nhật thông qua WebSocket, tôi có thể cập nhật trạng thái của thành phần, miễn là tôi đã thiết lập trạng thái ban đầu trong hàm tạo.

Điều này dẫn đến một xấu xí, albeit chức năng thiết lập của divs. Tôi thiết lập thêm một số kiểu dáng. Từ ứng dụng / Hành động / Trang chủ. trước :

  không gian tên App \ Action;sử dụng Aerys \ Yêu cầu;sử dụng Aerys \ Response;lớp HomeAction{chức năng công cộng __invoke (Yêu cầu $ yêu cầu,Đáp ứng $ trả lời){$ js = yield mix ("/ js / app. js");$ css = yield mix ("/ css / app. css");$ response-> end ("
March 1, 2018