0

I am working on a game that features randomly generated caves. It starts by creating a 640x480 field of 16x16 blocks. Then 3 instances of CaveMaker are placed, and these destroy every block they touch, they are supposed to shift direction every few seconds to result in random cave like pathways, but with my code, they turn up like this rubbish:

Eeeewwww

And I believe it is because the very improvised code I wrote that is supposed to make it change direction:

class CaveMaker(object):
    def __init__(self):
        self.active=1
        self.x=randrange(1,640)
        self.y=randrange(1,480)
        #Choose a X speed and Y speed
        self.direction=(choice([20,-20,1,-1,15,0,-15]),choice([20,-20,1,-1,15,0,-15]))
        self.rect=pygame.Rect(self.x,self.y,75,75)
        #Set amount of time to move this direction
        self.timeout=choice([30,50,70,90,110])
        self.destroytime=randrange(200,360)
    def Update(self):
        if self.active==1:
            #Move in a certain direction?
            self.x+=self.direction[0]
            self.y+=self.direction[1]
            self.timeout-=1
            if self.timeout==0:
                #Change direction?
                self.direction=   (choice([20,-20,1,-1,15,0,-15]),choice([20,-20,1,-1,15,0,-15]))
                self.timeout=choice([30,50,70,90,110])
            self.destroytime-=1
            if self.destroytime==0:
                self.active=0
            self.rect=pygame.Rect(self.x,self.y,60,60)

So how do I tell the object to move random directions?

Here is my full code:

import pygame
from pygame.locals import *
from collections import namedtuple
from random import randrange,choice
pygame.init()
screen=pygame.display.set_mode((640,480))
Move = namedtuple('Move', ['up', 'left', 'right'])
max_gravity=50
class Block(object):
    def __init__(self,x,y):
        self.x=x
        self.y=y
        self.rect=pygame.Rect(self.x,self.y,16,16)
class CaveMaker(object):
    def __init__(self):
        self.active=1
        self.x=randrange(1,640)
        self.y=randrange(1,480)
        #Choose a X speed and Y speed
        self.direction=(choice([20,-20,1,-1,15,0,-15]),choice([20,-20,1,-1,15,0,-15]))
        self.rect=pygame.Rect(self.x,self.y,75,75)
        #Set amount of time to move this direction
        self.timeout=choice([30,50,70,90,110])
        self.destroytime=randrange(200,360)
    def Update(self):
        if self.active==1:
            #Move in a certain direction?
            self.x+=self.direction[0]
            self.y+=self.direction[1]
            self.timeout-=1
            if self.timeout==0:
                #Change direction?
                self.direction=(choice([20,-20,1,-1,15,0,-15]),choice([20,-20,1,-1,15,0,-15]))
                self.timeout=choice([30,50,70,90,110])
            self.destroytime-=1
            if self.destroytime==0:
                self.active=0
            self.rect=pygame.Rect(self.x,self.y,60,60)
class Player(object):
    def __init__(self, x, y):
        self.rect = pygame.Rect(x,y,16,16)
        self.on_ground = True
        self.xvel = 0
        self.yvel = 0
        self.jump_speed = 5
        self.move_speed = 2

    def update(self, move, blocks):

        if move.up and self.on_ground:
            self.yvel -= self.jump_speed

        if move.left:
                self.xvel = -self.move_speed
        if move.right:
                self.xvel = self.move_speed

        if not self.on_ground:
            self.yvel += 0.3
            if self.yvel > max_gravity: self.yvel = max_gravity

        if not (move.left or move.right):
            self.xvel = 0

        self.rect.left += self.xvel
        self.collide(self.xvel, 0, blocks)

        self.rect.top += self.yvel
        self.on_ground = False;
        self.collide(0, self.yvel, blocks)

    def collide(self, xvel, yvel, blocks):
        for block in [blocks[i] for i in self.rect.collidelistall(blocks)]:

            if xvel > 0:
                    self.rect.right = block.rect.left
            if xvel < 0:
                    self.rect.left = block.rect.right

            if yvel > 0:
                self.rect.bottom = block.rect.top
                self.on_ground = True
                self.yvel = 0
            if yvel < 0: self.rect.top = block.rect.bottom;self.yvel=0
blocks=[]
cavemakes=[]
gen=1
genx=0
geny=0
px=0
py=0
cavemakes.append(CaveMaker());cavemakes.append(CaveMaker());cavemakes.append(CaveMaker());cavemakes.append(CaveMaker());
while True:
    key=pygame.key.get_pressed()
    if gen==1:
        blocks.append(Block(genx,geny))
        geny+=16
        if geny>480:
            geny=0
            genx+=16
            if genx>640:
                gen=2
    elif gen==2:
        screen.fill((5,80,200))
        for b in blocks:
            pygame.draw.rect(screen, (90,90,90), b.rect, 0)
        for c in cavemakes:
            if c.active==0:
                gen='done'
                while any(b.rect.collidepoint(px, py) for b in blocks):
                    px=randrange(1,630)
                    py=randrange(1,470)
                player=Player(px,py)
            c.Update()
            for b in blocks:
                if b.rect.colliderect(c.rect):
                    blocks.remove(b) 
        pygame.display.flip()
    if gen=='done':
        screen.fill((5,80,200))
        for b in blocks:
            pygame.draw.rect(screen, (90,90,90), b.rect, 0)
        for e in pygame.event.get():
            if e.type==KEYUP:
                if e.key==K_r:
                    blocks=[]
                    cavemakes=[]
                    gen=1
                    genx=0
                    geny=0
                    px=0
                    py=0
                    cavemakes.append(CaveMaker());cavemakes.append(CaveMaker());cavemakes.append(CaveMaker());cavemakes.append(CaveMaker());
            if e.type==QUIT:
                exit()
        move = Move(key[K_w], key[K_a], key[K_d])
        player.update(move,blocks)
        pygame.draw.rect(screen, (5,200,5), player.rect, 3)
        pygame.display.flip()
Sam Tubb
  • 945
  • 3
  • 19
  • 40

2 Answers2

1

Some pseudo/C# code:

// lets say we have 4 directions
// we generate random number for it    

int randomDirection = Random.Next(0, 4);

// 0:MoveUp()
// 1:MoveDown()
// 2:MoveLeft()
// 3:MoveRight()

// then we check what random direction number we got 
// and execute specific method for it

switch(randomDirection)
{
    case 0:
    player.MoveUp();
    break;

    case 1:
    player.MoveDown();
    break;

    case 3:
    player.MoveDown();
    break;

    case 4:
    player.MoveDown();
    break;
}

I just found out that there is no case/switch statement in Python. Check this question to see how to replace it.

Community
  • 1
  • 1
martynaspikunas
  • 485
  • 5
  • 15
1

I don't quite understand what you want. Do you want a series of connected tunnels? Do you want a random set of unconnected cleared circles? Do you want cleared circles that are connected by tunnels?

Here's some general advice, though.

First, your code has far too many hard-coded numbers. You should make a class called Board or similar that holds all the numbers as constant variables, then use those numbers:

class Board(object):
    def __init__(self, width, height, block_size):
        assert width % block_size == 0
        assert height % block_size == 0
        self.width = width
        self.height = height
        self.block_size = block_size
        self.w = width // self.block_size
        self.h = height // self.block_size

Now, once you have the above, you can do something like this:

x = random.randint(0, board.w - 1)
y = random.randint(0, board.h - 1)
xpos = x * board.block_size
ypos = y * board.block_size

My suggestion would be to use code like the above to choose where the caves go, and as you add each cave draw a tunnel to connect it up. Instead of drawing a bunch of random lines, pick random caves and then connect the caves with lines. Get your code working with straight lines connecting the caves, and then if you don't like the straight lines, rework the code to draw lines that have some randomness.

steveha
  • 74,789
  • 21
  • 92
  • 117