في المقالة الأخيرة ، قمنا بعمل فراغ معك ، إذا جاز التعبير ، الأساس الذي سيتم إنشاء كوننا عليه ، قد يبدو التصور باستخدام وحدة التحكم جيدًا ، لكن الأحرف النصية مملة وليست جميلة جدًا ، في هذه المقالة سنركز على تصور بلاطاتنا باستخدام Phaser.jsفي المقالة الأخيرة ، بدا مشروعنا كما يلي:
الآن سنستخدم أدوات أخرى لتطوير الويب ، آمل أن يكون لديك Node.js و npm مثبتًا ، إن لم يكن ، قم بتثبيته بشكل عاجل. وهكذا نفتح الصالة ونبدأ:$ npm install phaser@3.22.0
عند الانتهاء بنجاح من الفريق ، يجب أن نرى ما يلي:+ phaser@3.22.0
added 15 packages from 48 contributors and audited 20 packages in 4.38s
حسنًا ، ظهرت الوحدات ، الآن سنقوم بإنشاء دليل لعملائنا
في المحتوى سنقوم بتخزين موارد اللعبة ، أي العفاريت لدينا. سنقوم أيضًا بإنشاء ملفين game.js و MainScene.js ، في الدليل الجذر (حيث يوجد ملف main.go) إنشاء index.htmlgame.js - لتخزين الإعدادات الرئيسية للعبةMainScene.js - سيحتوي على فئة مشهد اللعبة الرئيسيindex.html - الصفحة التي سيتم فيها عرض المشهد ،قم بربط نصوصنا على الفور بـ index.html ولن نعود إلى هذا الملف بعد الآن: <script src="node_modules/phaser/dist/phaser.js" type="module"></script>
<script src="Client/game.js" type="module"></script>
في MainScene.js سنقوم بعمل قالب فئة صغير لمشهدنا المستقبلي:export {MainScene}
class MainScene extends Phaser.Scene{
constructor() {
super({key: 'MainScene'})
}
preload() {
}
create() {
}
update() {
}
}
في game.js أضف الإعدادات النموذجية حسب رغبتك ، إليك الإعدادات:import {MainScene} from "./MainScene.js";
let config = {
type: Phaser.AUTO,
width: 800,
height: 600,
disableContextMenu: true,
background: 'black',
physics: {
default: 'arcade',
arcadePhysics: {
overlapBias: 1
}
},
scene:[MainScene],
pixelArt: true,
roundPixels: true,
antialias: true
}
let game = new Phaser.Game(config);
الآن نحن بحاجة إلى خادم HTTP ، يتم ذلك في بضعة أسطر. انتقل إلى main.go وأنشئ خادمًا:package main
import (
"fmt"
"html/template"
"net/http"
)
func main() {
http.HandleFunc("/", indexHandler)
http.Handle("/node_modules/phaser/dist/", http.StripPrefix("/node_modules/phaser/dist/", http.FileServer(http.Dir("./node_modules/phaser/dist/"))))
http.Handle("/Client/", http.StripPrefix("/Client/", http.FileServer(http.Dir("./Client/"))))
http.Handle("/Client/Content/", http.StripPrefix("/Client/Content/", http.FileServer(http.Dir("./Client/Content/"))))
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err.Error())
}
}
func indexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Println("indexAction")
t, _ := template.ParseFiles("index.html")
err := t.Execute(w, "index")
if err != nil {
fmt.Println(err.Error())
}
}
حسنًا ، لدينا خادم الويب والعميل الخاص بنا! دعنا نبدأ! افتح وحدة التحكم:$ go run main.go
نفتح المتصفح ونحاول الاتصال بخادمنا ، في حالتيالمضيف المحلي: 8080
إذا رأيت شاشة سوداء ، فأنت فعلت كل شيء بشكل صحيح.لذا ، دعنا ننشئ معالجًا آخر نتلقى من خلاله مقطعنا بتنسيق json. قم بإنشاء دليل منفصل وأطلق عليه GameController ، وهنا سيكون لدينا جميع المعالجات التي تعمل مع بيانات اللعبة ، وإنشاء ملف Map_Controller.goكما نحتاج إلى تحسينChunk.gopackage Chunk
import (
"exampleMMO/PerlinNoise"
"fmt"
)
var TILE_SIZE = 16
var CHUNK_SIZE = 16 * 16
var PERLIN_SEED float32 = 160
type Chunk struct {
ChunkID [2]int `json:"chunkID"`
Map map[Coordinate]Tile `json:"map"`
}
type Tile struct {
Key string `json:"key"`
X int `json:"x"`
Y int `json:"y"`
}
type Coordinate struct {
X int `json:"x"`
Y int `json:"y"`
}
func NewChunk(idChunk Coordinate) Chunk {
fmt.Println("New Chank", idChunk)
chunk := Chunk{ChunkID: [2]int{idChunk.X, idChunk.Y}}
var chunkXMax, chunkYMax int
var chunkMap map[Coordinate]Tile
chunkMap = make(map[Coordinate]Tile)
chunkXMax = idChunk.X * CHUNK_SIZE
chunkYMax = idChunk.Y * CHUNK_SIZE
switch {
case chunkXMax < 0 && chunkYMax < 0:
{
for x := chunkXMax + CHUNK_SIZE; x > chunkXMax; x -= TILE_SIZE {
for y := chunkYMax + CHUNK_SIZE; y > chunkYMax; y -= TILE_SIZE {
posX := float32(x - (TILE_SIZE / 2))
posY := float32(y + (TILE_SIZE / 2))
tile := Tile{}
tile.X = int(posX)
tile.Y = int(posY)
perlinValue := PerlinNoise.Noise(posX/PERLIN_SEED, posY/PERLIN_SEED)
switch {
case perlinValue < -0.01:
tile.Key = "Water"
case perlinValue >= -0.01 && perlinValue < 0:
tile.Key = "Sand"
case perlinValue >= 0 && perlinValue <= 0.5:
tile.Key = "Ground"
case perlinValue > 0.5:
tile.Key = "Mount"
}
chunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile
}
}
}
case chunkXMax < 0:
{
for x := chunkXMax + CHUNK_SIZE; x > chunkXMax; x -= TILE_SIZE {
for y := chunkYMax - CHUNK_SIZE; y < chunkYMax; y += TILE_SIZE {
posX := float32(x - (TILE_SIZE / 2))
posY := float32(y + (TILE_SIZE / 2))
tile := Tile{}
tile.X = int(posX)
tile.Y = int(posY)
perlinValue := PerlinNoise.Noise(posX/PERLIN_SEED, posY/PERLIN_SEED)
switch {
case perlinValue < -0.12:
tile.Key = "Water"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "Ground"
case perlinValue > 0.5:
tile.Key = "Mount"
}
chunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile
}
}
}
case chunkYMax < 0:
{
for x := chunkXMax - CHUNK_SIZE; x < chunkXMax; x += TILE_SIZE {
for y := chunkYMax + CHUNK_SIZE; y > chunkYMax; y -= TILE_SIZE {
posX := float32(x + (TILE_SIZE / 2))
posY := float32(y - (TILE_SIZE / 2))
tile := Tile{}
tile.X = int(posX)
tile.Y = int(posY)
perlinValue := PerlinNoise.Noise(posX/PERLIN_SEED, posY/PERLIN_SEED)
switch {
case perlinValue < -0.12:
tile.Key = "Water"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "Ground"
case perlinValue > 0.5:
tile.Key = "Mount"
}
chunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile
}
}
}
default:
{
for x := chunkXMax - CHUNK_SIZE; x < chunkXMax; x += TILE_SIZE {
for y := chunkYMax - CHUNK_SIZE; y < chunkYMax; y += TILE_SIZE {
posX := float32(x + (TILE_SIZE / 2))
posY := float32(y + (TILE_SIZE / 2))
tile := Tile{}
tile.X = int(posX)
tile.Y = int(posY)
perlinValue := PerlinNoise.Noise(posX/PERLIN_SEED, posY/PERLIN_SEED)
switch {
case perlinValue < -0.12:
tile.Key = "Water"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "Ground"
case perlinValue > 0.5:
tile.Key = "Mount"
}
chunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile
}
}
}
}
chunk.Map = chunkMap
return chunk
}
لقد أضفنا للتو مفاتيح json إلى هياكلنا وتحسين إنشاء القطعة.ونعود إلى Map_Controller ،package GameController
import (
"encoding/json"
"exampleMMO/Chunk"
"fmt"
"net/http"
)
func Map_Handler(w http.ResponseWriter, r *http.Request) {
c:= Chunk.NewChunk(Chunk.Coordinate{1,1})
js, e :=json.Marshal(c)
if e!= nil {
fmt.Println(e.Error())
}
fmt.Println(string(js))
}
وإضافة سطر إلى main.go http.HandleFunc("/map", GameController.Map_Handler)
دعنا نحاول بدء الخادم ونذهب إلى localhost: 8080 / mapالإخراج في المحطة:New Chank {1 1}
json: unsupported type: map[Chunk.Coordinate]Chunk.Tile
نعم ، نسينا أنه في تسلسل Golang ، يجب أن تكون مفاتيح الخريطة سلسلة. للتسلسل ، يتحقق Go ما إذا كان النوع يطابق واجهة TextMarshaler ، ويستدعي طريقة MarshalText () ، نحتاج فقط إلى إنشاء طريقة MarshalText () لنوع الإحداثيات الخاص بنا.نعود إلى Chunk.go ونضيف الكود التالي:func (t Coordinate) MarshalText() ([]byte, error) {
return []byte("[" + strconv.Itoa(t.X) + "," + strconv.Itoa(t.Y) + "]"), nil
}
يمكنك كتابة التنفيذ الخاص بك ، والأهم هو أن هذه الطريقة ترجع سلسلة فريدة. سنستخدم هذا المفتاح لإدارة الأجزاء على العميل ، دعنا الآن نتحقق من كيفية عمل وحدة التحكم الخاصة بنا ، ونبدأ الخادم مرة أخرى ونرى الإخراج إلى وحدة التحكم.
نعم ، كل شيء على ما يرام ، دعنا الآن ننتهي إلى الدفق ، أضف سطرين في نهاية وحدة التحكم لدينا:
w.Header().Set("Content-Type", "application/json")
w.Write(js)
في الوقت الحالي ، انتهي مع Golang وعد إلى العميل. سنحتاج إلى ثلاثة ألقاب ، على الرغم من أن لدينا في الواقع 4 منها ، لكن لدينا الآن ثلاثة أو حتى اثنين.

أضف مربعاتنا إلى دليل المحتوى وابدأ العمل مع MainScene.js ، للحصول على النتائج الأولى ، نحتاج إلى بعض الوظائف:class MainScene extends Phaser.Scene{
constructor() {
super({key: 'MainScene'})
}
preload() {
this.load.image("Ground", "Client/Content/sprGrass.png")
this.load.image("Water", "Client/Content/sprWater1.png")
this.load.image("Sand", "Client/Content/sprGrass.png")
}
create() {
this.getGameMap()
}
update() {
}
async getGameMap() {
let res = await fetch("/map")
let result = await res.json()
this.drawChunk(result.map)
}
drawChunk(map) {
for (let chunkKey in map) {
this.add.image(map[chunkKey].x,map[chunkKey].y, map[chunkKey].key)
}
}
}
يقوم الخادم بإعادة القطعة الخاصة بنا إلينا في شكل كائن json ، يمكنك إلقاء نظرة على هيكله في وحدة تحكم المتصفح:
وهكذا قام Phaser بتقديمه في المتصفح:
قمنا بفحص أبسط عمل بين الخادم والعميل ، في المقالة التالية سنقوم على الفور برسم 9 قطع والتنقل إلى العالم. انظر جميع التعليمات البرمجية والموارد من المقالة هنا .