من الصعب العثور على المعلومات الصحيحة حول موارد اللغة الروسية ، ربما ستسمح لك هذه المادة بفهم بعض الأساسيات لإنشاء ألعاب متعددة اللاعبين والمزيد. أخطط لصنع سلسلة من المقالات حول إنشاء 2.5D MMORPG ، أي في علم القياس ، سيتم تقسيم عالمنا إلى قطع متولدة إجرائيًا تتكون من عناوين. سيتم كتابة الخادم بلغة Golang ، والتي تبدو لي مناسبة تمامًا لهذا ، سيكون جزء العميل في JavaScript باستخدام إطار العمل - Phaser.jsإنشاء جيل عالمي
وهكذا في هذه المقالة سوف نكتب مولدًا للقطعة لـ MMO على Golang ، ولن نعتبر Phaser في الوقت الحالي. من أجل توليد الإجراءات ، نحتاج إلى وظيفة ضوضاء ، وسوف نستخدم Perlin Noise ، أوصي بقراءة هذه المقالة وإعادة كتابة الرمز لـ Go أو أخذ نسختي.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.go:func main() {
var a, b float32= 1330, 2500
v:= PerlinNoise.Noise(a/2500, b/2500)
fmt.Println(v)
}
كن حذرا مع أنواع الأرقام ، حدد دائما الأنواع بشكل صريح ، وهذا سيوفر عليك من المشاكل في المستقبل ، إخراج الوظيفة:-0.23416707
وبالتالي لدينا وظيفة ضوضاء لتوليد عوالمنا. لنبدأ في إنشاء قطع. قم بإنشاء دليل Chunk وملف Chunk.go فيه وحدد الثوابت الرئيسية على الفور:var TILE_SIZE = 16
var CHUNK_SIZE = TILE_SIZE * TILE_SIZE
var PERLIN_SEED float32 = 150
TILE_SIZE هو دقة قطعنا المستقبلية بالبكسلCHUNK_SIZE هو حجم القطعة ، في هذه الحالة 16 * 16PERLIN_SEED - هنا يمكنك وضع أي رقم ، وكلما كان أعلى ، كلما كان الضجيج أكثر اتساقًا ، أي إذا كنت تريد جزرًا صغيرة ، فضع الرقم أقل ، إذا كانت القارات الضخمة أعلى.بعد ذلك ، أنشئ نوع بيانات للإحداثيات:type Coordinate struct {
X int
Y int
}
سيكون هذا النوع مفيدًا جدًا لنا في المستقبل ، والآن سننشئ وظيفة مهمة أخرى ، لتحديد الإحداثيات الفريدة لمجموعتنا في المستقبل ، وسنتصل بمعرفتهم: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
}
إن وظيفة تحديد هوية القطعة بسيطة للغاية ، نقوم فقط بتقسيم الموضع على الخريطة حسب حجم البلاط ، ثم نقسم النتيجة مرة أخرى على حجم البلاط مع التقريب لأعلى أو لأسفل ، اعتمادًا على معرف القطعة منذ عالمنا سينتج إلى ما لا نهاية في أي اتجاه.بعد ذلك ، أضف كتلة البناء الخاصة بنا لإنشاء القطعة ، وهذا هو البلاط والجزء نفسه:type Chunk struct {
ChunkID [2]int
Map map[Coordinate]Tile
}
type Tile struct {
Key string
X int
Y int
}
تحتوي القطعة على خريطة تجانب. يقوم Tiles بتخزين إحداثياته ومفتاحه (المفتاح هو نوع عنوانك: الأرض ، الماء ، الجبال ، إلخ.)الآن دعنا ننتقل إلى أهم شيء ، وظائف إنشاء القطعة لدينا ، أخذت وظيفتي العملية من المشروع وأعدتها قليلاً لهذه المقالة: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
}
وهكذا ، في هذه الوظيفة أو بالأحرى مُنشئ القطعة ، نحدد الإحداثيات القصوى للقطعة ، والتي سننتقل إليها بالتتابع ، ونملأ البلاط بالمعلومات الضرورية. يتم تحديد ChunkMax أيضًا بكل بساطة ، لأننا نضرب معرف القطعة في حجمها (CHUNK_SIZE) ، أي بالمعرّف {1؛ 1} ، ستصبح إحداثياتنا chunkXMax و chunkYMax 256.في posX / posY ، نحدد إحداثيات إدراج رسوماتنا: posX := float32(x + (TILE_SIZE / 2))
posY := float32(y + (TILE_SIZE / 2))
نستخدم التبديل لاختيار المنطق اعتمادًا على قيمة معرف القطعة (قد تكون هناك قيم موجبة وسالبة). سيحدد مفتاح البلاط ضجيج البيرلين ، على سبيل المثال ، إذا كان ضجيج البيرلين أقل من 0 ، فسيكون الماء ، وفوق ذلك سيكون الأرض. سوف نفعل ذلك: case perlinValue < -0.12:
tile.Key = "~"
case perlinValue >= -0.12 && perlinValue <= 0.5:
tile.Key = "1"
case perlinValue > 0.5:
tile.Key = "^"
دعونا نرى كيف تعمل وظيفتنا ، استبدل الكود بشكل رئيسي بالمحتويات التالية: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"))
}
}
استنتاج: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
يبدو جيدًا ، يمكنك تغيير وظيفة الإخراج واللعب بالمعلمات: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~~
الرمز: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"))
}
}
في المقالة التالية ، سننظر في العمل مع HTTP ، وإذا أثرنا عليه ، فسيكون اتصال WS. لنقم بإنشاء نوع من بطاقة اللعبة ، والتي سنقوم بعمل تسلسل لها بتنسيق json لعرضها على العميل ونرى بشكل عام كيف نتفاعل مع العميل.