我无法将我的 perlin 噪声贴图生成器变成我游戏的 pygame tilemap
I can't turn my perlin noise map generator into a pygame tilemap for my game
我首先使用这种方法生成了一个 tilemap:
for rw in range(tilesettings.mapheight):
for cl in range(tilesettings.mapwidth):
randomNumber = random.randint(0,15)
if randomNumber == 0:
tile = tilesettings.COAL
elif randomNumber == 1 or randomNumber == 2:
tile = tilesettings.WATER
elif randomNumber >= 3 and randomNumber <= 14:
tile = tilesettings.GRASS
else:
tile = tilesettings.DIRT
tilesettings.tilemap[rw][cl] = tile
问题是它只生成了一张随机选择的图块的地图,并没有生成类似于现实岛屿形状的地图。
所以我决定使用 Perlin 噪声来生成这样的随机岛形状:
A randomly generated island with Perlin noise
这是产生噪音的代码部分:
import pygame, sys
import noise
import numpy as np
from scipy.misc import toimage
from settings import Settings
from tilemap import Tilemap
from player import Player
from cursor import Cursor
from biome import Biome
from axe import Axe
import game_functions as gf
import random
def run_game():
tilesettings = Tilemap()
colours = {
tilesettings.DIRT: tilesettings.BROWN,
tilesettings.GRASS: tilesettings.GREEN,
tilesettings.WATER: tilesettings.BLUE,
tilesettings.COAL: tilesettings.BLACK,
tilesettings.SAND : tilesettings.SAND,
tilesettings.STONE: tilesettings.GREY,
tilesettings.SNOW: tilesettings.WHITE,
}
resources = [tilesettings.DIRT, tilesettings.GRASS,
tilesettings.WATER, tilesettings.COAL]
shape = (500, 500)
scale = 300
octaves = 6
persistence = 0.5
lacunarity = 2.0
seed = np.random.randint(0, 100)
world = np.zeros(shape)
for i in range(shape[0]):
for j in range(shape[1]):
world[i][j] = noise.pnoise2(i / scale,
j / scale,
octaves=octaves,
persistence=persistence,
lacunarity=lacunarity,
repeatx=1024,
repeaty=1024,
base=seed)
blue = [65, 105, 225]
green = [34, 139, 34]
beach = [238, 214, 175]
snow = [255, 250, 250]
mountain = [139, 137, 137]
def add_color(world):
color_world = np.zeros(world.shape + (3,))
for i in range(shape[0]):
for j in range(shape[1]):
if world[i][j] < -0.05:
color_world[i][j] = blue
elif world[i][j] < 0:
color_world[i][j] = beach
elif world[i][j] < .20:
color_world[i][j] = green
elif world[i][j] < 0.35:
color_world[i][j] = mountain
elif world[i][j] < 1.0:
color_world[i][j] = snow
return color_world
color_world = add_color(world)
a, b = shape[0] / 2, shape[1] / 2
n = 1024
r = 125
y, x = np.ogrid[-a:n - a, -b:n - b]
# creates a mask with True False values
# at indices
mask = x ** 2 + y ** 2 <= r ** 2
black = [0, 0, 0]
island_world = np.zeros_like(color_world)
for i in range(shape[0]):
for j in range(shape[1]):
if mask[i][j]:
island_world[i][j] = color_world[i][j]
else:
island_world[i][j] = black
import math
center_x, center_y = shape[1] // 2, shape[0] // 2
circle_grad = np.zeros_like(world)
for y in range(world.shape[0]):
for x in range(world.shape[1]):
distx = abs(x - center_x)
disty = abs(y - center_y)
dist = math.sqrt(distx * distx + disty * disty)
circle_grad[y][x] = dist
# get it between -1 and 1
max_grad = np.max(circle_grad)
circle_grad = circle_grad / max_grad
circle_grad -= 0.5
circle_grad *= 2.0
circle_grad = -circle_grad
# shrink gradient
for y in range(world.shape[0]):
for x in range(world.shape[1]):
if circle_grad[y][x] > 0:
circle_grad[y][x] *= 20
# get it between 0 and 1
max_grad = np.max(circle_grad)
circle_grad = circle_grad / max_grad
world_noise = np.zeros_like(world)
for i in range(shape[0]):
for j in range(shape[1]):
world_noise[i][j] = (world[i][j] * circle_grad[i][j])
if world_noise[i][j] > 0:
world_noise[i][j] *= 20
# get it between 0 and 1
max_grad = np.max(world_noise)
world_noise = world_noise / max_grad
lightblue = [0, 191, 255]
blue = [65, 105, 225]
green = [34, 139, 34]
darkgreen = [0, 100, 0]
sandy = [210, 180, 140]
beach = [238, 214, 175]
snow = [255, 250, 250]
mountain = [139, 137, 137]
这是我尝试编写的代码部分,以便将瓦片地图中的瓦片设置为正确的瓦片。
threshold = 0.005
def add_color2(world):
color_world = np.zeros(world.shape + (3,))
for i in range(shape[0]):
for j in range(shape[1]):
if world[i][j] < threshold + 0.05:
color_world[i][j] = blue
tile = tilesettings.WATER
elif world[i][j] < threshold + 0.055:
color_world[i][j] = sandy
tile = tilesettings.SAND
elif world[i][j] < threshold + 0.1:
color_world[i][j] = beach
tile = tilesettings.SAND
elif world[i][j] < threshold + 0.25:
color_world[i][j] = green
tile = tilesettings.GRASS
elif world[i][j] < threshold + 0.6:
color_world[i][j] = darkgreen
tile = tilesettings.GRASS
elif world[i][j] < threshold + 0.7:
color_world[i][j] = mountain
tile = tilesettings.GRASS
elif world[i][j] < threshold + 1.0:
color_world[i][j] = snow
tile = tilesettings.SNOW
tilesettings.tilemap[i][j] = tile
return color_world
island_world_grad = add_color2(world_noise)
toimage(island_world_grad).show()
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,
ai_settings.screen_height))
pygame.mouse.set_visible(True)
player = Player(ai_settings, screen, tilesettings)
cursor = Cursor(ai_settings, screen, tilesettings, player)
axe = Axe(ai_settings, screen, tilesettings, cursor)
while True:
gf.check_events(ai_settings, screen, player, cursor, axe)
player.update()
cursor.update()
gf.update_screen(ai_settings, screen, player)
for row in range (tilesettings.mapheight):
for column in range(tilesettings.mapwidth):
pygame.draw.rect(screen,
colours[tilesettings.tilemap[row][column]],(column*
tilesettings.tilesize, row* tilesettings.tilesize,
tilesettings.tilesize, tilesettings.tilesize))
biome.update(screen)
player.blitme()
axe.changeimage()
axe.blitme()
pygame.display.update()
run_game()
我遇到的问题是,当我 运行 代码时,它非常滞后,并且只在水砖屏幕上显示我的角色。我确实尝试过单独编写代码来设置图块:
color_world = np.zeros(world.shape + (3,))
for rw in range (shape[0]):
for cl in range(shape[1]):
if color_world == blue:
tile = tilesettings.WATER
elif color_world == sandy:
tile = tilesettings.SAND
elif color_world == beach:
tile = tilesettings.SAND
elif color_world == green:
tile = tilesettings.GREEN
elif color_world == darkgreen:
tile = tilesettings.GRASS
elif color_world == mountain:
tile = tilesettings.STONE
elif color_world == snow:
tile = tilesettings.SNOW
tilesettings.tilemap[rw][cl] = tile
当我这样做的时候,我得到了一个奇怪的错误:
if color_world == blue:
ValueError: 具有多个元素的数组的真值不明确。使用 a.any() 或 a.all()
多年来我一直在修改我的代码,但我看不出我做错了什么 - 如果有人能帮助我,我们将不胜感激:)
只是一个快速更新,事实证明它不只是呈现蓝屏,因为我看到呈现了沙子瓦片,所以这一定与播放器的位置有关,但它非常滞后且无法播放。
很难回答,因为您的回答缺少可运行的示例,但有两点:
if color_world == blue:
这里报错也不奇怪。错误信息告诉你出了什么问题:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
你尝试检查 color_world
是否等于 blue
,但是 color_world
是一个多维列表,而 blue
是一个整数列表,所以基本上 Python 现在知道该做什么了。我想这条线应该是
if color_world[i][j] == blue
此外,删除这部分:
for row in range (tilesettings.mapheight):
for column in range(tilesettings.mapwidth):
pygame.draw.rect(screen,
colours[tilesettings.tilemap[row][column]],(column*
tilesettings.tilesize, row* tilesettings.tilesize,
tilesettings.tilesize, tilesettings.tilesize))
脱离你的主循环。
运行 之前将背景绘制到新的 Surface
,然后在主循环中使用新的 Surface
,如下所示:
...
background = pygame.Surface((tilesettings.mapwidth*tilesettings.tilesize, tilesettings.mapheight*tilesettings.tilesize))
for row in range (tilesettings.mapheight):
for column in range(tilesettings.mapwidth):
pygame.draw.rect(background ,
colours[tilesettings.tilemap[row][column]],(column*
tilesettings.tilesize, row* tilesettings.tilesize,
tilesettings.tilesize, tilesettings.tilesize))
...
while True:
gf.check_events(ai_settings, screen, player, cursor, axe)
player.update()
cursor.update()
gf.update_screen(ai_settings, screen, player)
screen.blit(background, (0, 0))
biome.update(screen)
player.blitme()
axe.changeimage()
axe.blitme()
pygame.display.update()
因此您不必每秒多次遍历 tilesettings.tilemap
中的每一行和每一列。你会明白的。
这应该可以帮助您提高性能。
我首先使用这种方法生成了一个 tilemap:
for rw in range(tilesettings.mapheight):
for cl in range(tilesettings.mapwidth):
randomNumber = random.randint(0,15)
if randomNumber == 0:
tile = tilesettings.COAL
elif randomNumber == 1 or randomNumber == 2:
tile = tilesettings.WATER
elif randomNumber >= 3 and randomNumber <= 14:
tile = tilesettings.GRASS
else:
tile = tilesettings.DIRT
tilesettings.tilemap[rw][cl] = tile
问题是它只生成了一张随机选择的图块的地图,并没有生成类似于现实岛屿形状的地图。
所以我决定使用 Perlin 噪声来生成这样的随机岛形状: A randomly generated island with Perlin noise
这是产生噪音的代码部分:
import pygame, sys
import noise
import numpy as np
from scipy.misc import toimage
from settings import Settings
from tilemap import Tilemap
from player import Player
from cursor import Cursor
from biome import Biome
from axe import Axe
import game_functions as gf
import random
def run_game():
tilesettings = Tilemap()
colours = {
tilesettings.DIRT: tilesettings.BROWN,
tilesettings.GRASS: tilesettings.GREEN,
tilesettings.WATER: tilesettings.BLUE,
tilesettings.COAL: tilesettings.BLACK,
tilesettings.SAND : tilesettings.SAND,
tilesettings.STONE: tilesettings.GREY,
tilesettings.SNOW: tilesettings.WHITE,
}
resources = [tilesettings.DIRT, tilesettings.GRASS,
tilesettings.WATER, tilesettings.COAL]
shape = (500, 500)
scale = 300
octaves = 6
persistence = 0.5
lacunarity = 2.0
seed = np.random.randint(0, 100)
world = np.zeros(shape)
for i in range(shape[0]):
for j in range(shape[1]):
world[i][j] = noise.pnoise2(i / scale,
j / scale,
octaves=octaves,
persistence=persistence,
lacunarity=lacunarity,
repeatx=1024,
repeaty=1024,
base=seed)
blue = [65, 105, 225]
green = [34, 139, 34]
beach = [238, 214, 175]
snow = [255, 250, 250]
mountain = [139, 137, 137]
def add_color(world):
color_world = np.zeros(world.shape + (3,))
for i in range(shape[0]):
for j in range(shape[1]):
if world[i][j] < -0.05:
color_world[i][j] = blue
elif world[i][j] < 0:
color_world[i][j] = beach
elif world[i][j] < .20:
color_world[i][j] = green
elif world[i][j] < 0.35:
color_world[i][j] = mountain
elif world[i][j] < 1.0:
color_world[i][j] = snow
return color_world
color_world = add_color(world)
a, b = shape[0] / 2, shape[1] / 2
n = 1024
r = 125
y, x = np.ogrid[-a:n - a, -b:n - b]
# creates a mask with True False values
# at indices
mask = x ** 2 + y ** 2 <= r ** 2
black = [0, 0, 0]
island_world = np.zeros_like(color_world)
for i in range(shape[0]):
for j in range(shape[1]):
if mask[i][j]:
island_world[i][j] = color_world[i][j]
else:
island_world[i][j] = black
import math
center_x, center_y = shape[1] // 2, shape[0] // 2
circle_grad = np.zeros_like(world)
for y in range(world.shape[0]):
for x in range(world.shape[1]):
distx = abs(x - center_x)
disty = abs(y - center_y)
dist = math.sqrt(distx * distx + disty * disty)
circle_grad[y][x] = dist
# get it between -1 and 1
max_grad = np.max(circle_grad)
circle_grad = circle_grad / max_grad
circle_grad -= 0.5
circle_grad *= 2.0
circle_grad = -circle_grad
# shrink gradient
for y in range(world.shape[0]):
for x in range(world.shape[1]):
if circle_grad[y][x] > 0:
circle_grad[y][x] *= 20
# get it between 0 and 1
max_grad = np.max(circle_grad)
circle_grad = circle_grad / max_grad
world_noise = np.zeros_like(world)
for i in range(shape[0]):
for j in range(shape[1]):
world_noise[i][j] = (world[i][j] * circle_grad[i][j])
if world_noise[i][j] > 0:
world_noise[i][j] *= 20
# get it between 0 and 1
max_grad = np.max(world_noise)
world_noise = world_noise / max_grad
lightblue = [0, 191, 255]
blue = [65, 105, 225]
green = [34, 139, 34]
darkgreen = [0, 100, 0]
sandy = [210, 180, 140]
beach = [238, 214, 175]
snow = [255, 250, 250]
mountain = [139, 137, 137]
这是我尝试编写的代码部分,以便将瓦片地图中的瓦片设置为正确的瓦片。
threshold = 0.005
def add_color2(world):
color_world = np.zeros(world.shape + (3,))
for i in range(shape[0]):
for j in range(shape[1]):
if world[i][j] < threshold + 0.05:
color_world[i][j] = blue
tile = tilesettings.WATER
elif world[i][j] < threshold + 0.055:
color_world[i][j] = sandy
tile = tilesettings.SAND
elif world[i][j] < threshold + 0.1:
color_world[i][j] = beach
tile = tilesettings.SAND
elif world[i][j] < threshold + 0.25:
color_world[i][j] = green
tile = tilesettings.GRASS
elif world[i][j] < threshold + 0.6:
color_world[i][j] = darkgreen
tile = tilesettings.GRASS
elif world[i][j] < threshold + 0.7:
color_world[i][j] = mountain
tile = tilesettings.GRASS
elif world[i][j] < threshold + 1.0:
color_world[i][j] = snow
tile = tilesettings.SNOW
tilesettings.tilemap[i][j] = tile
return color_world
island_world_grad = add_color2(world_noise)
toimage(island_world_grad).show()
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width,
ai_settings.screen_height))
pygame.mouse.set_visible(True)
player = Player(ai_settings, screen, tilesettings)
cursor = Cursor(ai_settings, screen, tilesettings, player)
axe = Axe(ai_settings, screen, tilesettings, cursor)
while True:
gf.check_events(ai_settings, screen, player, cursor, axe)
player.update()
cursor.update()
gf.update_screen(ai_settings, screen, player)
for row in range (tilesettings.mapheight):
for column in range(tilesettings.mapwidth):
pygame.draw.rect(screen,
colours[tilesettings.tilemap[row][column]],(column*
tilesettings.tilesize, row* tilesettings.tilesize,
tilesettings.tilesize, tilesettings.tilesize))
biome.update(screen)
player.blitme()
axe.changeimage()
axe.blitme()
pygame.display.update()
run_game()
我遇到的问题是,当我 运行 代码时,它非常滞后,并且只在水砖屏幕上显示我的角色。我确实尝试过单独编写代码来设置图块:
color_world = np.zeros(world.shape + (3,))
for rw in range (shape[0]):
for cl in range(shape[1]):
if color_world == blue:
tile = tilesettings.WATER
elif color_world == sandy:
tile = tilesettings.SAND
elif color_world == beach:
tile = tilesettings.SAND
elif color_world == green:
tile = tilesettings.GREEN
elif color_world == darkgreen:
tile = tilesettings.GRASS
elif color_world == mountain:
tile = tilesettings.STONE
elif color_world == snow:
tile = tilesettings.SNOW
tilesettings.tilemap[rw][cl] = tile
当我这样做的时候,我得到了一个奇怪的错误:
if color_world == blue:
ValueError: 具有多个元素的数组的真值不明确。使用 a.any() 或 a.all()
多年来我一直在修改我的代码,但我看不出我做错了什么 - 如果有人能帮助我,我们将不胜感激:)
只是一个快速更新,事实证明它不只是呈现蓝屏,因为我看到呈现了沙子瓦片,所以这一定与播放器的位置有关,但它非常滞后且无法播放。
很难回答,因为您的回答缺少可运行的示例,但有两点:
if color_world == blue:
这里报错也不奇怪。错误信息告诉你出了什么问题:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
你尝试检查 color_world
是否等于 blue
,但是 color_world
是一个多维列表,而 blue
是一个整数列表,所以基本上 Python 现在知道该做什么了。我想这条线应该是
if color_world[i][j] == blue
此外,删除这部分:
for row in range (tilesettings.mapheight):
for column in range(tilesettings.mapwidth):
pygame.draw.rect(screen,
colours[tilesettings.tilemap[row][column]],(column*
tilesettings.tilesize, row* tilesettings.tilesize,
tilesettings.tilesize, tilesettings.tilesize))
脱离你的主循环。
运行 之前将背景绘制到新的 Surface
,然后在主循环中使用新的 Surface
,如下所示:
...
background = pygame.Surface((tilesettings.mapwidth*tilesettings.tilesize, tilesettings.mapheight*tilesettings.tilesize))
for row in range (tilesettings.mapheight):
for column in range(tilesettings.mapwidth):
pygame.draw.rect(background ,
colours[tilesettings.tilemap[row][column]],(column*
tilesettings.tilesize, row* tilesettings.tilesize,
tilesettings.tilesize, tilesettings.tilesize))
...
while True:
gf.check_events(ai_settings, screen, player, cursor, axe)
player.update()
cursor.update()
gf.update_screen(ai_settings, screen, player)
screen.blit(background, (0, 0))
biome.update(screen)
player.blitme()
axe.changeimage()
axe.blitme()
pygame.display.update()
因此您不必每秒多次遍历 tilesettings.tilemap
中的每一行和每一列。你会明白的。
这应该可以帮助您提高性能。