Pada artikel terakhir, kami membuat kekosongan dengan Anda, sehingga untuk berbicara, dasar di mana alam semesta kita akan dibuat, visualisasi menggunakan konsol mungkin terlihat baik, tetapi karakter teks membosankan dan tidak terlalu indah, dalam artikel ini kita akan fokus pada memvisualisasikan ubin kami menggunakan Phaser.jsDalam artikel sebelumnya, proyek kami terlihat seperti ini:
Sekarang kita akan menggunakan alat lain untuk pengembangan web, saya harap Anda memiliki Node.js dan npm diinstal, jika tidak, segera instal. Jadi kami membuka terminal dan mulai:$ npm install phaser@3.22.0
Setelah berhasil menyelesaikan tim, kita akan melihat yang berikut:+ phaser@3.22.0
added 15 packages from 48 contributors and audited 20 packages in 4.38s
Begitu bagus, modul muncul, sekarang kita akan membuat direktori untuk klien kita.
Dalam Konten kita akan menyimpan sumber daya game, mis. sprite kami. Kami juga akan membuat dua file game.js dan MainScene.js, di direktori root (di mana file main.go berada) buat index.htmlgame.js - menyimpan pengaturan utama untuk gameMainScene.js - ini akan berisi kelasindex.html adegan permainan utama - halaman tempat adegan akansegera sambungkan skrip kami ke index.html dan kami tidak akan kembali ke file ini lagi: <script src="node_modules/phaser/dist/phaser.js" type="module"></script>
<script src="Client/game.js" type="module"></script>
Di MainScene.js kita akan membuat templat kelas kecil untuk adegan masa depan kita:export {MainScene}
class MainScene extends Phaser.Scene{
constructor() {
super({key: 'MainScene'})
}
preload() {
}
create() {
}
update() {
}
}
Di game.js tambahkan pengaturan khas sesuai keinginan Anda, inilah milik saya: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);
Sekarang kita memerlukan server HTTP, pada ini dilakukan dalam beberapa baris. Buka main.go dan buat server: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())
}
}
Yah, kami memiliki server web dan klien kami sendiri! Mari kita memulainya! Buka konsol:$ go run main.go
Kami membuka browser dan mencoba untuk terhubung ke server kami, dalam kasus saya itulocalhost: 8080
Jika Anda melihat layar hitam, maka Anda melakukan semuanya dengan benar.Jadi, mari kita buat penangan lain dimana kita akan menerima potongan kita dalam format json. Buat direktori terpisah dan sebut itu GameController, di sini kita akan memiliki semua penangan yang bekerja dengan data game, membuat file Map_Controller.goJuga kita perlu ditingkatkanChunk.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
}
Kami baru saja menambahkan kunci json ke struktur kami dan sedikit memperbaiki kreasi. Kamikembali ke 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))
}
dan tambahkan baris ke main.go http.HandleFunc("/map", GameController.Map_Handler)
Mari kita coba untuk memulai server dan pergi ke localhost: 8080 / map.Output di terminal:New Chank {1 1}
json: unsupported type: map[Chunk.Coordinate]Chunk.Tile
Ya, kami lupa bahwa di Golang, ketika diserialisasi, kunci peta harus berupa string. Untuk serialisasi, Go memeriksa apakah jenisnya cocok dengan antarmuka TextMarshaler, dan memanggil metode MarshalText (), kita hanya perlu membuat metode MarshalText () untuk tipe Koordinat kita. Kitakembali ke Chunk.go dan menambahkan kode berikut:func (t Coordinate) MarshalText() ([]byte, error) {
return []byte("[" + strconv.Itoa(t.X) + "," + strconv.Itoa(t.Y) + "]"), nil
}
Anda dapat menulis implementasi Anda, yang paling penting adalah metode ini mengembalikan string unik. Kami akan menggunakan kunci ini untuk mengelola potongan pada klien, mari sekarang periksa cara kerja pengontrol kami, mulai server lagi dan lihat output ke konsol.
Ya, semuanya baik-baik saja, mari sekarang buat kesimpulan ke aliran, tambahkan dua baris di akhir pengontrol kami:
w.Header().Set("Content-Type", "application/json")
w.Write(js)
Untuk sekarang, selesaikan dengan Golang dan kembali ke klien. kita akan membutuhkan tiga judul, walaupun sebenarnya kita memiliki 4 judul, tetapi untuk saat ini kita memiliki tiga, atau bahkan dua.

Tambahkan ubin kami ke direktori Konten dan mulai bekerja dengan MainScene.js, untuk hasil pertama kami memerlukan beberapa fungsi: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)
}
}
}
Server mengembalikan bongkahan kami kepada kami dalam bentuk objek json, Anda dapat melihat strukturnya di konsol peramban:
Dan Phaser merendernya di peramban:
Kami memeriksa pekerjaan paling sederhana antara server dan klien, pada artikel berikutnya kami akan segera menggambar 9 bongkahan dan menavigasi ke dunia. Lihat semua kode dan sumber daya dari artikel di sini .