I started off by generating a tilemap using this method:
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
The problem with this is that it merely generated a map that was just randomly chosen tiles, and didn't generate a map that resembled a realistic island shape.
So I then decided to use Perlin noise to generate random island shapes like this: A randomly generated island with Perlin noise
This is the section of code which generates the 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]
This is the part of the code which I tried to make it so that it set the tiles in the tilemap to the right tiles.
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()
The problem I have is that when I run the code, it is extremely laggy, and just displays my character over a screen of water tiles. I did try doing a separate code to set the tiles:
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
When I did this though, I got a strange error:
if color_world == blue:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
I've been messing around with my code for ages and I can't see what I've done wrong - someone please help it would be greatly appreciated :)
Just a quick update, turns out it isn't rendering just a blue screen because I saw a sand tile rendered so it must be to do with the placement of the player, but it is extremely laggy and unplayable.