python - 我无法将我的 perlin 噪声图生成器变成我的游戏的 pygame 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 random generate 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()
多年来我一直在搞乱我的代码,我看不出我做错了什么 - 有人请帮助它,将不胜感激:)
只是一个快速更新,结果它不只是渲染蓝屏,因为我看到渲染的沙子,所以它必须与播放器的位置有关,但它非常滞后且无法播放。
解决方案
Tricky to answer since your answer lacks a runnable example, but two thing:
if color_world == blue:
It's not strange that you get an error here. The error message tells you what's wrong:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
You try to check if color_world
equals blue
, but color_world
is a multidimensional list, while blue
is a list of integers, so basically Python does now know what to. I suppose the line should be
if color_world[i][j] == blue
Also, remove this part:
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))
out of your main loop.
Run it once before and draw the background to a new Surface
, then use that new Surface
in your main loop, like this:
...
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()
so you don't have to loop over every row and column in tilesettings.tilemap
multiple times per second. You'll get the idea.
That should help you improve the performance.
推荐阅读
- arrays - 如何向数组添加附加值
- mysql - MySQL错误:ER_NOT_SUPPORTED_AUTH_MODE:客户端不支持服务器请求的身份验证协议;考虑升级 MySQL 客户端
- javascript - 如何渲染具有不同组件名称的多个组件?
- python - Spark:如何从 Spark 数据帧行解析和转换 json 字符串
- bash - 如何在motd中获得正确的字符串长度?
- matlab - MATLAB 将 2 个水平数组作为标签和一行添加到表中,而不是 2 列
- c++ - 防止孙子调用其祖父母的方法
- xquery - 如何通过 XQuery 获取所有元素及其属性的列表
- firebase - 如果在哪里使用 Flutter,我不能使用来自 firestore 的 orderBy 查询
- java - 为什么比较法违反总合同?