Random Line Generation For pygame

1.2k views Asked by At

My goal is to make a retro lunar lander game using pygame. Right now I'm trying to create the background of mountains and platforms to land on. I would like for every time a new game is started the platforms and mountains be different. My idea is to draw a random number of horizontal lines with random lengths as the platform. I have a few problems with this:

  1. How to make sure the horizontal lines don't overlap and are all accesible in regards of looking at it like you're landing.
  2. I think the best way to draw the mountains would be to connect the platforms with more lines that create triangles, but I have no idea where to begin to do that

the code I have been working for currently generates random lines, but I'm not sure how to develop the code further.

for platforms in range(1, random.randint(1, 10)):

            rand_x_start = random.randint(0, 400)
            rand_x_end = random.randint(0, 400)
            rand_y = random.randint(HEIGHT / 2, HEIGHT)

            pygame.draw.line(self.background, white, (rand_x_start, rand_y), (rand_x_end, rand_y), 2)

I've tried looking through many questions and tutorials about random generation, but none are remotely close to what I'm looking for.

A thought I had to fix the overlapping problem was if there was a way to "read" or "see" previously created lines and to limit drawing based on that some how...but I'm not sure of a way to do that.

1

There are 1 answers

7
Tagc On BEST ANSWER

I put together the following code as something that might help you out:

import random
from collections import namedtuple

from PIL import Image, ImageDraw

GaussianDistribution = namedtuple('GaussianDistribution', ['mu', 'sigma'])
Platform = namedtuple('Platform', ['start', 'end', 'height'])
Point = namedtuple('Point', ['x', 'y'])

PLATFORM_HEIGHT_DISTRIBUTION = GaussianDistribution(50, 10)
PLATFORM_WIDTH_DISTRIBUTION = GaussianDistribution(100, 10)
INTER_PLATFORM_DISTRIBUTION = GaussianDistribution(500, 20)

RANDOM = random.Random()


def sample_distribution(distribution):
    return RANDOM.normalvariate(distribution.mu, distribution.sigma)


def create_platforms(num_platforms):
    last_platform_end = 0

    for i in range(num_platforms):
        start = int(sample_distribution(INTER_PLATFORM_DISTRIBUTION) + last_platform_end)
        end = int(sample_distribution(PLATFORM_WIDTH_DISTRIBUTION) + start)
        height = int(sample_distribution(PLATFORM_HEIGHT_DISTRIBUTION))

        last_platform_end = end

        yield Platform(start, end, height)


def create_mountains_between_points(p1, p2):
    mountain_start = p1.x
    mountain_end = p2.x

    num_points = int((mountain_end - mountain_start) / 10)

    for i in range(num_points):
        # TODO: use 1D Perlin function to generate point.y
        yield Point(mountain_start + i * 10, RANDOM.random() * 100)


def create_terrain(platforms):
    origin = Point(0, 0)
    first_platform_start = Point(platforms[0].start, platforms[0].height)

    terrain = []
    terrain += list(create_mountains_between_points(origin, first_platform_start))

    for i, platform in enumerate(platforms):
        platform_starts_at = Point(platform.start, platform.height)
        platform_ends_at = Point(platform.end, platform.height)

        terrain.append(platform_starts_at)
        terrain.append(platform_ends_at)

        if i < len(platforms) - 1:
            next_platform = platforms[i + 1]
            next_platform_starts_at = Point(next_platform.start, next_platform.height)
            mountains = create_mountains_between_points(platform_ends_at, next_platform_starts_at)
            terrain += mountains

    return terrain


def draw_terrain(terrain):
    im = Image.new('RGBA', (4000, 200), (255, 255, 255, 0))

    draw = ImageDraw.Draw(im)
    draw.line(terrain, fill=(0, 0, 0, 255))

    im.show()


if __name__ == '__main__':
    platforms = list(create_platforms(num_platforms=10))
    terrain = create_terrain(platforms)
    draw_terrain(terrain)

This generates the following terrain. You can see that there are flat areas (platforms) separated by mountains. Platforms are guaranteed not to overlap. They are also guaranteed to be "accessible" in that there will never be any terrain generated over them.

Terrain

I generate the y ordinates for the mountains by sampling from a uniform distribution. You can probably make the mountains look better by using the Perlin noise algorithm I mentioned earlier. I found this attempt to use Perlin noise in a pygame application.