TheNoobiestCoder
TheNoobiestCoder

Reputation: 23

Pygame - Randomly Spawning Objects in Given Area

So I'm currently planning on making a relatively basic game which involves enemies making their way towards a player's "base" which will be located directly at the centre of the screen. I'm struggling to find a way in which I can spawn these enemies from all sides of the screen but only on the edges. Below is the basic class I have created for the enemy sprite and my attempt at trying to spawn them in a location that is on the outer part of the screen. For the most part it works, apart from the fact that it will never spawn any of the sprites at the bottom outer part of my screen since I'm unsure of how to make the Y coordinate a random number between 0,80 OR between 600,680. Also, this doesn't really seem like the most efficient way of assigning the X and Y values. Would appreciate any advice or help given. Screen dimensions I am using are 800x680, Thanks.

class Enemy(pygame.sprite.Sprite):
def __init__(self,x,y):
    pygame.sprite.Sprite.__init__(self)
    self.image = pygame.Surface((15,15))
    self.image.fill(RED)
    self.rect = self.image.get_rect()
    self.rect.x = x
    self.rect.y = y

all_sprites = pygame.sprite.Group()
mobs = pygame.sprite.Group()
for i in range (10):
    x = random.randint(0,800)
    if x < 100 or x > 700:
        y = random.randint(0,680)
    else:
        y = random.randint(0,80)
    m = Enemy(x,y)
    all_sprites.add(m)
    mobs.add(m)

Upvotes: 1

Views: 6675

Answers (3)

Felipeg2008
Felipeg2008

Reputation: 1

but when I execute that code combined with my code it never stops updating until I stop moving the mouse

import pygame as py
import random as ra


py.init()

RED = py.Color(255,0,0)
sw = 800
sh = 400
Screen = py.display.set_mode((sw, sh))
width, height = Screen.get_size()
clock = py.time.Clock()
done = False

Sides = ["top","bottom","left","right"]
Weights = [width,width,height,height]

py.display.set_caption("Spaceship")
icon = py.image.load('battleship.png')
py.display.set_icon(icon)

playerX = 400
playerY = 200
playerx_Change = 0
playery_Change = 0

enemyimg = py.image.load("meteor.png")

def Player(x,y):
    Screen.blit(icon, (x, y))
def Enemy(x,y):
    Screen.blit(enemyimg, (x, y))


running = True
while running or not done:

    for event in py.event.get():


        if event.type == py.QUIT :
            running = False
            done = True

        side = ra.choices(Sides, Weights)[0]

        if side == "top":
            y = 0
            x = ra.randrange(width-4)
        elif side == "bottom":
            y = height -4
            x = ra.randrange(width-4)
        elif side == "left":
            y = 0
            x = ra.randrange(height-4)
        elif side == "right":
            y = width-4
            x = ra.randrange(height-4)


        if event.type == py.KEYDOWN:
            if event.key == py.K_UP:
                playery_Change = -1
            if event.key == py.K_DOWN:
                playery_Change = 1
            if event.key == py.K_LEFT:
                print("La tecla izquierda se ha activado")
                playerx_Change = -1
            if event.key == py.K_RIGHT:
                playerx_Change = 1
                print("La tecla derecha se ha accionado")
        if event.type == py.KEYUP:
            if event.key == py.K_LEFT or event.key == py.K_RIGHT:
                playerx_Change = 0
            if event.key == py.K_DOWN or event.key == py.K_UP:
                playery_Change = 0


    Screen.fill((40,40,50))

    playerX += playerx_Change
    playerY += playery_Change

    if playerX <=0:
        playerX = 0
    if playerX >= sw -30:
        playerX = sw -30
    if playerY <=0:
        playerY=0
    if playerY >= sh -30:
        playerY = sh - 30


    Player(playerX,playerY)

    py.draw.rect(Screen, RED, (x, y, 4, 4))
    py.display.flip()
    clock.tick(30)
    py.display.update()

Upvotes: 0

skrx
skrx

Reputation: 20438

You could create a list of the sides (as strings), pick one with random.choice and then assign the coordinates depending on the chosen side.

sides = ['top', 'bottom', 'left', 'right']
while True:
side = random.choice(sides)

if side == 'top':
    y = 0
    x = random.randrange(screen_width-4)
# etc.

However, there's a problem because the density at the shorter edges will be higher. If you want to distribute the objects randomly along all edges, you can use random.choices (available in Python 3.6+) which makes selections according to weights. Just pass the lengths of the edges as the weights argument. Here's a short example (I just draw red rects):

import random
import pygame as pg

pg.init()
RED = pg.Color('red')
screen = pg.display.set_mode((800, 400))
width, height = screen.get_size()
clock = pg.time.Clock()
done = False

sides = ['top', 'bottom', 'left', 'right']
weights = [width, width, height, height]

while not done:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            done = True

    side = random.choices(sides, weights)[0]

    if side == 'top':
        y = 0
        x = random.randrange(width-4)
    elif side == 'bottom':
        y = height-4
        x = random.randrange(width-4)
    elif side == 'left':
        x = 0
        y = random.randrange(height-4)
    elif side == 'right':
        x = width-4
        y = random.randrange(height-4)

    pg.draw.rect(screen, RED, (x, y, 4, 4))
    pg.display.flip()
    clock.tick(30)

Upvotes: 1

DavidH
DavidH

Reputation: 451

You could let randint decide for you whether to put an enemy on top or bottom:

for i in range (10):
   x = random.randint(0,800)
   if x < 100 or x > 700:
       y = random.randint(0,680)
   else:
       bot_top = random.randint(0,1)
       if(bot_top == 0):
          y = random.randint(0,80)
       else:
          y = random.randint(600,680)
   m = Enemy(x,y)
   all_sprites.add(m)
   mobs.add(m)

Upvotes: 0

Related Questions