É difícil encontrar as informações corretas sobre os recursos do idioma russo, talvez este material permita que você entenda alguns princípios básicos para a criação de jogos para vários jogadores e muito mais. Pretendo fazer uma série de artigos sobre a criação de MMORPG 2.5D, ou seja, em isometria, nosso mundo será dividido em partes geradas proceduralmente, compostas por títulos. O servidor será escrito na linguagem Golang, o que me parece perfeitamente adequado para isso, a parte do cliente será em JavaScript usando a estrutura - Phaser.jsCrie uma geração mundial
Portanto, neste artigo, escreveremos um gerador de partes para o MMO no Golang, não consideraremos a Phaser por enquanto. Para a geração procedural, precisamos de uma função de ruído, usaremos o Perlin Noise , recomendo que você leia este artigo e reescreva o código para Go ou pegue minha versão.Perlin.gopackage PerlinNoise
import (
"math"
"math/rand"
)
func Noise(x, y float32) float32 {
left := float32(math.Floor(float64(x)))
top := float32(math.Floor(float64(y)))
localPoinX := x - left
localPoiny := y - top
topLeft := getRandomVector(left, top)
topRight := getRandomVector(left+1, top)
bottomLeft := getRandomVector(left, top+1)
bottomRight := getRandomVector(left+1, top+1)
DtopLeft := []float32{localPoinX, localPoiny}
DtopRight := []float32{localPoinX - 1, localPoiny}
DbottomLeft := []float32{localPoinX, localPoiny - 1}
DbottomRight := []float32{localPoinX - 1, localPoiny - 1}
tx1 := dot(DtopLeft, topLeft)
tx2 := dot(DtopRight, topRight)
bx1 := dot(DbottomLeft, bottomLeft)
bx2 := dot(DbottomRight, bottomRight)
pointX := curve(localPoinX)
pointY := curve(localPoiny)
tx := lerp(tx1, tx2, pointX)
bx := lerp(bx1, bx2, pointX)
tb := lerp(tx, bx, pointY)
return tb
}
func getRandomVector(x, y float32) []float32 {
rand.Seed(int64(x * y))
v := rand.Intn(3)
switch v {
case 0:
return []float32{-1, 0}
case 1:
return []float32{1, 0}
case 2:
return []float32{0, 1}
default:
return []float32{0, -1}
}
}
func dot(a []float32, b []float32) float32 {
return (a[0]*b[0] + b[1]*a[1])
}
func lerp(a, b, c float32) float32 {
return a*(1-c) + b*c
}
func curve(t float32) float32 {
return (t * t * t * (t*(t*6-15) + 10))
}
Vamos criar um pequeno projeto em que testamos a funcionalidade de nossa função, aqui está a estrutura do meu projeto:
Adicione o seguinte ao arquivo main.go:func main() {
var a, b float32= 1330, 2500
v:= PerlinNoise.Noise(a/2500, b/2500)
fmt.Println(v)
}
Tenha cuidado com os tipos de números, sempre especifique os tipos explicitamente, isso evitará problemas no futuro, a saída da função:-0.23416707
E, portanto, temos uma função de ruído para gerar nossos mundos. Vamos começar a criar partes. Crie o diretório Chunk e o arquivo Chunk.go e defina imediatamente as constantes principais:var TILE_SIZE = 16
var CHUNK_SIZE = TILE_SIZE * TILE_SIZE
var PERLIN_SEED float32 = 150
TILE_SIZE é a resolução dos nossos futuros pedaços em pixelsCHUNK_SIZE é o tamanho do pedaço, neste caso 16 * 16PERLIN_SEED - aqui você pode colocar qualquer número, quanto maior, mais uniforme será o ruído, ou seja, se você quiser ilhas pequenas, coloque o número menos, se os grandes continentes forem mais altos.Em seguida, crie um tipo de dados para as coordenadas:type Coordinate struct {
X int
Y int
}
Esse tipo será muito útil para nós no futuro, e agora criaremos outra função importante, para determinar as coordenadas exclusivas de nosso bloco no futuro, que chamaremos de ID:func GetChunkID(x, y int) Coordinate {
tileX := float64(float64(x) / float64(TILE_SIZE))
tileY := float64(float64(y) / float64(TILE_SIZE))
var ChunkID Coordinate
if tileX < 0 {
ChunkID.X = int(math.Floor(tileX / float64(TILE_SIZE)))
} else {
ChunkID.X = int(math.Ceil(tileX / float64(TILE_SIZE)))
}
if tileY < 0 {
ChunkID.Y = int(math.Floor(tileY / float64(TILE_SIZE)))
} else {
ChunkID.Y = int(math.Ceil(tileY / float64(TILE_SIZE)))
}
if tileX == 0 {
ChunkID.X = 1
}
if tileY == 0 {
ChunkID.Y = 1
}
return ChunkID
}
A função para determinar o ID do bloco é bastante simples, apenas dividimos a posição no mapa pelo tamanho do bloco e, em seguida, dividimos o resultado novamente pelo tamanho do bloco com arredondamentos para cima ou para baixo, dependendo do ID do bloco desde nosso mundo será gerado infinitamente em qualquer direção.Em seguida, adicione nosso bloco de construção para criar o pedaço, este é o bloco e o próprio pedaço:type Chunk struct {
ChunkID [2]int
Map map[Coordinate]Tile
}
type Tile struct {
Key string
X int
Y int
}
O pedaço contém um mapa de blocos. Os ladrilhos armazenam suas coordenadas e teclas (a chave é o tipo do seu título: terra, água, montanhas etc.)Agora, vamos para as funções mais importantes para criar nosso pedaço, peguei minha função de trabalho no projeto e refiz um pouco para este artigo:func NewChunk ()func NewChunk(idChunk Coordinate) Chunk {
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 = "~"
case perlinValue >= -0.01 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
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 = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
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 = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
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 = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
chunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile
}
}
}
}
chunk.Map = chunkMap
return chunk
}
E assim, nessa função, ou melhor, no construtor de nosso pedaço, determinamos as coordenadas máximas do pedaço, para as quais iremos mover seqüencialmente, preenchendo os blocos com as informações necessárias. O ChunkMax também é determinado de maneira bastante simples. Para isso, multiplicamos o ID do chunk por seu tamanho (CHUNK_SIZE), ou seja, com o ID {1; 1} nossas coordenadas chunkXMax e chunkYMax serão 256.Em posX / posY, determinamos as coordenadas para inserir nossos gráficos: posX := float32(x + (TILE_SIZE / 2))
posY := float32(y + (TILE_SIZE / 2))
Usamos switch para selecionar a lógica, dependendo do valor do ID do nosso bloco (pode haver valores positivos e negativos). A chave do ladrilho determinará o ruído do perlin, por exemplo, se o ruído do perlin estiver abaixo de 0, será água, acima será terra. Vamos fazer o seguinte: case perlinValue < -0.12:
tile.Key = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
Vamos ver como nossa função funciona, substitua o código principal pelo seguinte conteúdo:func main() {
coord := Chunk.Coordinate{Y: 1, X: 1}
chunk := Chunk.NewChunk(coord)
m := chunk.Map
out := os.Stdout
for y := 8; y < 16*16; y += 16 {
for x := 8; x < 16*16; x += 16 {
c := Chunk.Coordinate{X: x, Y: y}
out.Write([]byte(m[c].Key))
}
out.Write([]byte("\n"))
}
}
Conclusão:11~~~11111111111
11~~~11111111111
11~~~~1111111111
11~~~~1111111111
11~~~~~111111111
11~~~~~~1111111~
11~~~~~~~~~11~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~~~~~
11~~~~~~~~~~1111
11~~~~~~~~~11111
Parece bom, você pode alterar a função de saída e brincar com os parâmetros:11111~~~~~~~~111111111111111111111111111111~~~~~~~11111111111111
11111~~~~~~~~111111111111111111111111111111~~~~~~~11111111111111
11111~~~~~~~~111111111111111111111111111111~~~~~~~11111111111111
11111~~~~~~~~111111111111111111111111111111~~~~~~~~1111111111111
11111~~~~~~~~11111111111111111111111111111~~~~~~~~~1111111111111
11111~~~~~~~~11111111111111111111111111111~~~~~~~~~1111111111111
11111~~~~~~~~~111111111111111111111111111~~~~~~~~~~~111111111111
11111~~~~~~~~~111111111111111111111111111~~~~~~~~~~~~11111111111
11111~~~~~~~~~~1111111111111111111111111~~~~~~~~~~~~~11111111111
11111~~~~~~~~~~~11111111111111111111111~~~~~~~~~~~~~~~1111111111
11111~~~~~~~~~~~1111111111111111111111~~~~~~~~~~~~~~~~~111111111
11111~~~~~~~~~~~~~11111111111111111111~~~~~~~~~~~~~~~~~111111111
11111~~~~~~~~~~~~~~111111111111111111~~~~~~~~~~~~~~~~~~~11111111
11111~~~~~~~~~~~~~~~~11111111111111~~~~~~~~~~~~~~~~~~~~~~1111111
11111~~~~~~~~~~~~~~~~~~11111111111~~~~~~~~~~~~~~~~~~~~~~~~111111
11111~~~~~~~~~~~~~~~~~~~~~111111~~~~~~~~~~~~~~~~~~~~~~~~~~~11111
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1111
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~111
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~11
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~1
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~~~1111111111~~~~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~~~111111111111111~~~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~~1111111111111111111~~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~~111111111111111111111~~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~~11111111111111111111111~~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~~1111111111111111111111111~~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~~111111111111111111111111111~~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~11111111111111111111111111111~~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~~111111111111111111111111111111~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~~1111111111111111111111111111111~~~~~~~~~~~
11111~~~~~~~~~~~~~~~~111111111111111111111111111111111~~~~~~~~~~
11111~~~~~~~~~~~~~~~~1111111111111111111111111111111111~~~~~~~~~
11111~~~~~~~~~~~~~~~~11111111111111111111111111111111111~~~~~~~~
11111~~~~~~~~~~~~~~~~11111111111111111111111111111111111~~~~~~~~
11111~~~~~~~~~~~~~~~~111111111111111111111111111111111111~~~~~~~
11111~~~~~~~~~~~~~~~~1111111111111111111111111111111111111~~~~~~
11111~~~~~~~~~~~~~~~~1111111111111111111111111111111111111~~~~~~
11111~~~~~~~~~~~~~~~~11111111111111111111111111111111111111~~~~~
11111~~~~~~~~~~~~~~~~11111111111111111111111111111111111111~~~~~
11111~~~~~~~~~~~~~~~~~11111111111111111111111111111111111111~~~~
11111~~~~~~~~~~~~~~~~~11111111111111111111111111111111111111~~~~
11111~~~~~~~~~~~~~~~~~~11111111111111111111111111111111111111~~~
1111~~~~~~~~~~~~~~~~~~~11111111111111111111111111111111111111~~~
1111~~~~~~~~~~~~~~~~~~~~1111111111111111111111111111111111111~~~
1111~~~~~~~~~~~~~~~~~~~~~111111111111111111111111111111111111~~~
1111~~~~~~~~~~~~~~~~~~~~~1111111111111111111111111111111111111~~
1111~~~~~~~~~~~~~~~~~~~~~~111111111111111111111111111111111111~~
1111~~~~~~~~~~~~~~~~~~~~~~~11111111111111111111111111111111111~~
1111~~~~~~~~~~~~~~~~~~~~~~~~1111111111111111111111111111111111~~
1111~~~~~~~~~~~~~~~~~~~~~~~~1111111111111111111111111111111111~~
1111~~~~~~~~~~~~~~~~~~~~~~~~~111111111111111111111111111111111~~
O código:Chunk.gopackage Chunk
import (
"PerlinNoise"
"math"
)
var TILE_SIZE = 16
var CHUNK_SIZE = 32 * 32
var PERLIN_SEED float32 = 600
type Coordinate struct {
X int `json:"x"`
Y int `json:"y"`
}
type Chunk struct {
ChunkID [2]int
Map map[Coordinate]Tile
}
type Tile struct {
Key string
X int
Y int
}
func GetChunkID(x, y int) Coordinate {
tileX := float64(x)
tileY := float64(y)
var ChunkID Coordinate
if tileX < 0 {
ChunkID.X = int(math.Floor(tileX / float64(TILE_SIZE)))
} else {
ChunkID.X = int(math.Ceil(tileX / float64(TILE_SIZE)))
}
if tileY < 0 {
ChunkID.Y = int(math.Floor(tileY / float64(TILE_SIZE)))
} else {
ChunkID.Y = int(math.Ceil(tileY / float64(TILE_SIZE)))
}
if tileX == 0 {
ChunkID.X = 1
}
if tileY == 0 {
ChunkID.Y = 1
}
return ChunkID
}
func NewChunk(idChunk Coordinate) Chunk {
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 = "~"
case perlinValue >= -0.01 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
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 = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
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 = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
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 = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
}
chunkMap[Coordinate{X: tile.X, Y: tile.Y}] = tile
}
}
}
}
chunk.Map = chunkMap
return chunk
}
Perlin.gopackage PerlinNoise
import (
"math"
"math/rand"
)
func Noise(x, y float32) float32 {
left := float32(math.Floor(float64(x)))
top := float32(math.Floor(float64(y)))
localPoinX := x - left
localPoiny := y - top
topLeft := getRandomVector(left, top)
topRight := getRandomVector(left+1, top)
bottomLeft := getRandomVector(left, top+1)
bottomRight := getRandomVector(left+1, top+1)
DtopLeft := []float32{localPoinX, localPoiny}
DtopRight := []float32{localPoinX - 1, localPoiny}
DbottomLeft := []float32{localPoinX, localPoiny - 1}
DbottomRight := []float32{localPoinX - 1, localPoiny - 1}
tx1 := dot(DtopLeft, topLeft)
tx2 := dot(DtopRight, topRight)
bx1 := dot(DbottomLeft, bottomLeft)
bx2 := dot(DbottomRight, bottomRight)
pointX := curve(localPoinX)
pointY := curve(localPoiny)
tx := lerp(tx1, tx2, pointX)
bx := lerp(bx1, bx2, pointX)
tb := lerp(tx, bx, pointY)
return tb
}
func getRandomVector(x, y float32) []float32 {
rand.Seed(int64(x * y))
v := rand.Intn(3)
switch v {
case 0:
return []float32{-1, 0}
case 1:
return []float32{1, 0}
case 2:
return []float32{0, 1}
default:
return []float32{0, -1}
}
}
func dot(a []float32, b []float32) float32 {
return (a[0]*b[0] + b[1]*a[1])
}
func lerp(a, b, c float32) float32 {
return a*(1-c) + b*c
}
func curve(t float32) float32 {
return (t * t * t * (t*(t*6-15) + 10))
}
main.gopackage main
import (
"fmt"
"habr/Chunk"
"os"
)
func main() {
coord:= Chunk.GetChunkID(0,0)
fmt.Println(coord)
chunk := Chunk.NewChunk(coord)
m := chunk.Map
out := os.Stdout
for y := 8; y < 32*32; y += 16 {
for x := 8; x < 32*32; x += 16 {
c := Chunk.Coordinate{X: x, Y: y}
out.Write([]byte(m[c].Key))
}
out.Write([]byte("\n"))
}
}
No próximo artigo , consideraremos trabalhar com HTTP e, se o afetamos, a conexão WS. Vamos criar um tipo de cartão de jogo, que serializaremos no formato json para renderização no cliente e, geralmente, veremos como interagimos com o cliente.