Currently, my game involves a player collecting shapes of a certain color a random number of times. The shapes will randomly spawn all over the screen, with ten shapes in all. The shapes will stay in for fifteen seconds before new shapes appear and the old ones disappear.
I am currently trying to make the shapes spawn in different places. The places don't need to be on random -- I don't know how to set the shapes to a different point without changing the size. I also need a way to switch the shapes' colors every 15 seconds.
Here is my current code:
import pygame
import random
import time
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
size = ((300,250,50,50))
clock = pygame.time.Clock()
FPS = 150
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Game")
#colors
black = (0,0,0)
white = (255,255,255)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
random_color = [red, green, blue]
#random
shape_number = random.randint (1,5)
shape_color = random.choice(random_color)
#shapes
player = pygame.Rect(size)
shape = pygame.Rect(size)
shape1 = pygame.Rect(size)
shape2 = pygame.Rect(size)
shape3 = pygame.Rect(size)
shape4 = pygame.Rect(size)
shape5 = pygame.Rect(size)
shape6 = pygame.Rect(size)
shape7 = pygame.Rect(size)
shape8 = pygame.Rect(size)
shape9 = pygame.Rect(size)
shape10 = pygame.Rect(size)
shape_color = random.choice(random_color)
counter = "You have to get ", shape_number, " ", shape_color, " colored shapes"
runWindow = True
while runWindow:
pygame.draw.rect(screen, (white), player)
pygame.draw.rect(screen, (shape_color), shape)
pygame.draw.rect(screen, (shape_color), shape1)
pygame.draw.rect(screen, (shape_color), shape2)
pygame.draw.rect(screen, (shape_color), shape3)
pygame.draw.rect(screen, (shape_color), shape4)
pygame.draw.rect(screen, (shape_color), shape5)
pygame.draw.rect(screen, (shape_color), shape6)
pygame.draw.rect(screen, (shape_color), shape7)
pygame.draw.rect(screen, (shape_color), shape8)
pygame.draw.rect(screen, (shape_color), shape9)
pygame.draw.rect(screen, (shape_color), shape10)
key = pygame.key.get_pressed()
if key[pygame.K_a] == True:
player.move_ip(-1, 0)
if key[pygame.K_w] == True:
player.move_ip(0, -1)
if key[pygame.K_d] == True:
player.move_ip(1, 0)
if key[pygame.K_s] == True:
player.move_ip(0, 1)
if player == shape:
pygame.draw.rect(screen, (shape_color), shape)
for event in pygame.event.get():
if event.type == pygame.QUIT:
runWindow = False
clock.tick(FPS)
pygame.display.update()
screen.fill(black)
continue
pygame.quit()
The current code spawns in 10 different shapes and the player. However, as you can see if you run the code, the shapes are all clumped together, and I do not know how to set different spawnpoints. If you could also explain everything to me, I would be grateful as I am new to pygame.
Thank you for responding to this question if you do!
To spawn your shapes in a random position, you can modify the Rect virtual attributes, x, y, top, left, bottom, …
etc.
With minimal modifications to your code:
shape1 = pygame.Rect(size)
shape1.x = random.randint(0, SCREEN_WIDTH-1) # randint includes the endpoint.
shape1.y = random.randint(0, SCREEN_HEIGHT-1)
You might want to further limit the range so your shapes aren't touching the borders of your window.
As others have suggested, you should be creating your shapes in a loop. I also recommend you use sprites and store them in sprite groups to make things cleaner and easier.
EDIT: Here's an example that uses sprites and groups for collision detection. It also uses KEYDOWN
events to move the player sprite rather than checking which keys are currently pressed. I used a match statement to allow easy support for WASD and ↑←↓→ keys.
import random
import pygame
from collections import Counter
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
FPS = 150
my_colors = ["red", "green", "blue"]
move_keys = [pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN, pygame.K_a, pygame.K_d, pygame.K_s, pygame.K_w, pygame.K_SPACE]
class Shape(pygame.sprite.Sprite):
def __init__(self, size, pos, color=None):
pygame.sprite.Sprite.__init__(self)
self.size = size
self.image = pygame.Surface([size[0], size[1]])
if color:
self.color = color
else:
self.color = random.choice(my_colors)
self.image.fill(self.color)
self.rect = self.image.get_rect()
self.rect.center = pos
# uncomment to add some randomness to the reset interval
self.reset_time = pygame.time.get_ticks() # + random.randint(0, 5_000)
def update(self):
"""Randomize the color after fifteen seconds"""
if pygame.time.get_ticks() - self.reset_time > 15_000:
self.color = random.choice(my_colors)
self.image.fill(self.color)
self.reset_time = pygame.time.get_ticks()
class Player(Shape):
"""A moving shape"""
def __init__(self, pos):
super().__init__((10, 10), pos, "firebrick")
self.stop() # initialised the speed to zero
def stop(self):
self.speedx = 0
self.speedy = 0
def move(self, key):
"""adjust speed in the direction of the key press"""
match key:
case pygame.K_LEFT | pygame.K_a:
self.speedx -= 1
case pygame.K_RIGHT | pygame.K_d:
self.speedx += 1
case pygame.K_UP | pygame.K_w:
self.speedy -= 1
case pygame.K_DOWN | pygame.K_s:
self.speedy += 1
case pygame.K_SPACE:
self.stop()
case _:
print(f"Unsupported move key {key}")
def update(self):
"""move the sprite according to its speed, bouncing off walls"""
width, height = screen.get_size()
if self.rect.left < 0:
self.speedx *= -1 # reverse direction
self.rect.left = 0
elif self.rect.right > width:
self.speedx *= -1
self.rect.right = width
self.rect.x += self.speedx
if self.rect.top < 0:
self.speedy *= -1 # reverse direction
self.rect.top = 0
elif self.rect.bottom > height:
self.speedy *= -1
self.rect.bottom = height
self.rect.y += self.speedy
def spawn_shapes(sprite_group, n=10):
"""Create a number of sprites at a random position and add them to the group"""
for _ in range(n):
position = random.randint(50, SCREEN_WIDTH-100) , random.randint(50, SCREEN_HEIGHT-100)
shape = Shape(shape_size, position)
sprite_group.add(shape)
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()
scores = Counter()
shape_size = 50, 50
shapes = pygame.sprite.Group()
spawn_shapes(shapes)
# create the player sprite
player = pygame.sprite.GroupSingle()
player.add(Player(screen.get_rect().center))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key in move_keys:
player.sprite.move(event.key)
# refresh background
screen.fill("black")
# update game state
shapes.update()
player.update()
# check for collisions, destroying collided Shape sprites
collisions = pygame.sprite.groupcollide(player, shapes, False, True)
if collisions:
for collided_shapes in collisions.values():
for collided_shape in collided_shapes:
# print(f"Collided with {collided_shape.color} shape")
scores[collided_shape.color] += 1
player.sprite.stop()
# update score # TODO: draw on the screen instead of the title bar.
score_texts = [f"Score: {scores.total()}"]
for color, score in scores.most_common(): # use most_common for sorted results
score_texts.append(f"{color} : {score}")
pygame.display.set_caption(" ".join(score_texts))
if len(shapes) == 0:
spawn_shapes(shapes)
# draw sprites
shapes.draw(screen)
player.draw(screen)
# update screen
pygame.display.update()
clock.tick(FPS) # limit FPS
pygame.quit()
Python has a bunch of named colors, so you can use names in your code that can be more readable than a bunch of numbers.