Dans le dernier article, nous avons fait un blanc avec vous, pour ainsi dire, la base sur laquelle notre univers sera créé, la visualisation à l'aide de la console peut sembler bonne, mais les caractères du texte sont ennuyeux et pas très beaux, dans cet article, nous nous concentrerons sur la visualisation de nos carreaux à l'aide Phaser.jsDans un article précédent, notre projet ressemblait à ceci:
Maintenant, nous allons utiliser d'autres outils pour le développement web, j'espère que vous avez installé Node.js et npm, sinon installez-le de toute urgence. Et donc nous ouvrons le terminal et commençons:$ npm install phaser@3.22.0
Une fois l'équipe terminée avec succès, nous devrions voir ce qui suit:+ phaser@3.22.0
added 15 packages from 48 contributors and audited 20 packages in 4.38s
Tellement génial, des modules sont apparus, maintenant nous allons créer un répertoire pour notre client
Dans le contenu, nous allons stocker des ressources de jeu, c'est-à-dire nos sprites. Nous allons également créer deux fichiers game.js et MainScene.js, dans le répertoire racine (où se trouve le fichiermain.go ) créer index.html game.js - stocke les paramètres principaux du jeuMainScene.js - contiendra la classe de la scène principale du jeuindex.html - la page où la scène sera rendueConnectez immédiatement nos scripts à index.html et nous ne reviendrons plus sur ce fichier: <script src="node_modules/phaser/dist/phaser.js" type="module"></script>
<script src="Client/game.js" type="module"></script>
Dans MainScene.js, nous créerons un petit modèle de classe pour notre future scène:export {MainScene}
class MainScene extends Phaser.Scene{
constructor() {
super({key: 'MainScene'})
}
preload() {
}
create() {
}
update() {
}
}
Dans game.js ajoutez des paramètres typiques à votre goût, voici les miens: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);
Maintenant, nous avons besoin d'un serveur HTTP, cela se fait en quelques lignes. Accédez à main.go et créez un serveur: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())
}
}
Eh bien, nous avons notre propre serveur Web et client! Commençons! Ouvrez la console:$ go run main.go
Nous ouvrons le navigateur et essayons de nous connecter à notre serveur, dans mon cas c'estlocalhost: 8080
Si vous avez vu un écran noir, vous avez tout fait correctement.Et donc, créons un autre gestionnaire par lequel nous recevrons notre bloc au format json. Créez un répertoire séparé et appelez-le GameController, ici nous aurons tous les gestionnaires travaillant avec les données du jeu, créez le fichier Map_Controller.goNous avons également besoin d'une version amélioréeChunk.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
}
Nous venons d'ajouter des clés json à nos structures et d'améliorer un peu la création de morceaux. Nousrevenons à 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))
}
et ajoutez une ligne à main.go http.HandleFunc("/map", GameController.Map_Handler)
Essayons de démarrer le serveur et allons sur localhost: 8080 / map.Sortie dans le terminal:New Chank {1 1}
json: unsupported type: map[Chunk.Coordinate]Chunk.Tile
Oui, nous avons oublié qu'à Golang, lors de la sérialisation, les clés de carte doivent être une chaîne. Pour la sérialisation, Go vérifie si le type correspond à l'interface TextMarshaler et appelle sa méthode MarshalText (), il nous suffit de créer la méthode MarshalText () pour notre type de coordonnées. Nousrevenons à Chunk.go et ajoutons le code suivant:func (t Coordinate) MarshalText() ([]byte, error) {
return []byte("[" + strconv.Itoa(t.X) + "," + strconv.Itoa(t.Y) + "]"), nil
}
Vous pouvez écrire votre implémentation, le plus important est que cette méthode retourne une chaîne unique. Nous allons utiliser cette clé pour gérer les morceaux sur le client, maintenant vérifions le fonctionnement de notre contrôleur, réexécutons le serveur et voyons la sortie vers la console.
Oui, tout va bien, faisons maintenant une conclusion au flux, ajoutons deux lignes à la fin de notre contrôleur:
w.Header().Set("Content-Type", "application/json")
w.Write(js)
Pour l'instant, terminez avec Golang et revenez au client. nous aurons besoin de trois titres, bien qu'en fait nous en ayons 4, mais pour l'instant nous en avons trois, voire deux.

Ajoutez nos tuiles au répertoire Content et commencez à travailler avec MainScene.js, pour les premiers résultats nous avons besoin de quelques fonctions: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)
}
}
}
Le serveur nous rend notre morceau sous la forme d'un objet json, vous pouvez regarder sa structure dans la console du navigateur:
Et donc Phaser l'a rendu dans le navigateur:
Nous avons examiné le travail le plus simple entre le serveur et le client, dans le prochain article, nous allons immédiatement dessiner 9 morceaux et naviguer au monde. Voir tout le code et les ressources de l'article ici .