I am trying to make a block spawner like thingy in pygame. I've used lists to store x and y variables, but I can't make rects with these without using variables like rect1, rect2 ... How can I use lists or something else to have infinite amounts of rects?
My code is looking like that:
import pygame
from pygame.locals import *
screen = pygame.display.set_mode((800,600))
kares = []
karx = [0]
kary = [0]
karposx = 0
karposy = 0
k = 0
running = True
while running:
# screen.fill((0,0,0))
if k == 1:
karx[0] = pygame.mouse.get_pos()[0]
for i in range(len(karx)):
a = [karx[i], kary[i]]
kares.append(a)
for i in kares:
karposx = i[0]
karposy = i[1]
print(kares)
k+=1
rect1 = pygame.Rect(karposx,200,64,64)
# for i in kares:
# kares[i][1] -= 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == KEYDOWN:
if event.key == K_RIGHT:
k += 1
if k >= 2:
k = 0
if k == 1:
pygame.draw.rect(screen, (255,0,0), rect1)
pygame.display.update()
Output
You have to create a list of rectangles. Create rectangles and add them to the list:
rect = pygame.Rect(x, 200, 64, 64)
rects.append(rect)
Draw the rectangles in a loop:
for rect in rects:
pygame.draw.rect(screen, (255,0,0), rect)
Minimal example based on your code:
import pygame
from pygame.locals import *
screen = pygame.display.set_mode((800,600))
clock = pygame.time.Clock()
rects = []
running = True
while running:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == MOUSEBUTTONDOWN:
if event.button == 3:
x, _ = event.pos
x = (x // 64) * 64
if not any(r for r in rects if r.x == x):
rect = pygame.Rect(x, 200, 64, 64)
rects.append(rect)
print(len(rects))
screen.fill((0,0,0))
for rect in rects:
pygame.draw.rect(screen, (255,0,0), rect)
pygame.display.update()
pygame.quit()
Related
This question already has answers here:
how to make image/images disappear in pygame?
(1 answer)
How to delete one object from a Surface instance?
(1 answer)
How to clean up sprites without covering other things?
(1 answer)
Closed 4 months ago.
I'm making my first pygame game, Plane Delivery game. I'm stuck at the menu. I created menu with my custom background image. Also, I created START button which is used to start the game. When player clicks the START button, I want to hide main menu background, and show the game's background image, world map. Thank you for help!
There's code:
import pygame
pygame.init()
window = pygame.display.set_mode((1920, 1080))
pygame.display.set_caption('Plane Delivery')
POZADINA = (254, 0, 60) # BOJA POZADINE
window.fill(POZADINA)
clock = pygame.time.Clock()
menu_img = pygame.image.load('Plane_Delivery2.jpg')
menu_img = pygame.transform.scale(menu_img, (1920, 1080))
bg_img = pygame.image.load('background.jpg')
bg_img = pygame.transform.scale(bg_img,(1920, 1080))
plane_sprite = pygame.image.load('avion3.png')
x2 = 960
y2 = 540
# -- Main Menu --
#button class
class Button():
def __init__(self, x, y, image, scale):
width = image.get_width()
height = image.get_height()
self.image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
self.rect = self.image.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
def draw(self, surface):
action = False
#get mouse position
pos = pygame.mouse.get_pos()
#check mouseover and clicked conditions
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
action = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
#draw button on screen
surface.blit(self.image, (self.rect.x, self.rect.y))
return action
start_img = pygame.image.load('start2.png').convert_alpha()
exit_img = pygame.image.load('exit2.png').convert_alpha()
start_button = Button(30, 400, start_img, 0.8)
exit_button = Button(200, 360, exit_img, 0.4)
run = True
while run:
clock.tick(40)
window.blit(menu_img, (0, 0))
if start_button.draw(window):
window.fill((255, 255, 0))
window.blit(bg_img, (0, 0))
pygame.display.flip()
window.blit(plane_sprite, (x2, y2))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
while 1:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
y2 += 20
if event.key == pygame.K_s:
y2 -= 20
if event.key == pygame.K_a:
x2 -= 20
if event.key == pygame.K_d:
x2 += 20
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if exit_button.draw(window):
pygame.quit()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.update()
Thank you for help! :D
I'm new to OOP and trying to get the gist of using Classes and Methods. In this particular case, I've used a class to create two red nodes and managed to use MOUSEBUTTONDOWN with my class.
However, when I try to use a MOUSEBUTTONDOWN event to draw a line, nothing seems to happen. I've
used test print statements in multiple places to ensure that I'm "reaching" my class and that
the method is executing. Nothing, however, can seem to make my red line appear.
I've also moved the draw statement out of the method to near the end of my game loop and it
appears correctly.
What am I misunderstanding about classes and methods?
import pygame
class Rnode():
def __init__(self, x, y, image_rednode):
self.x = x
self.y = y
self.image_rednode = image_rednode
self.rect = self.image_rednode.get_rect()
self.rect.topleft = (x, y)
self.clicked = False
self.wired = False
# draw node line
def put(self):
screen.blit(self.image_rednode, (self.x, self.y))
#get mouse position
pos = pygame.mouse.get_pos()
#check mouseover and clicked
if self.rect.collidepoint(pos):
if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False:
self.clicked = True
print('gotcha' + str(self))
self.wired = True
if pygame.mouse.get_pressed()[0] == 0:
self.clicked = False
def draw_line(self):
if pygame.mouse.get_pressed()[0]:
self.pos = pygame.mouse.get_pos()
pygame.draw.line(screen,red,(self.x + 15, self.y + 15),(self.pos), 3)
# these are the colors
green = (48, 141, 70)
grey = (211, 211, 211)
lime = (201, 223, 202)
purplish = (116,137,192)
orange = (234,168,0)
brown = (59,47,47)
blue = (0,91,150)
red = (255,8,0)
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption('Classy, Baby!')
running = 1
xb = pygame.image.load(r'xb7white.png').convert_alpha()
rednode = pygame.image.load('redhole.svg').convert_alpha()
rednode = pygame.transform.scale(rednode, (100, 100))
# make node instances
r1 = Rnode(300, 300, rednode)
r2 = Rnode(500, 300, rednode)
while running:
screen.fill((0, 0, 0))
event = pygame.event.poll()
if event.type == pygame.QUIT:
running = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
# if event.type == pygame.MOUSEBUTTONDOWN: # if the user pressed a mouse button
# pos = pygame.mouse.get_pos() # get the mouse pos
# if g1.rect.collidepoint(pos):
r1.put()
r2.put()
if r1.wired:
r1.draw_line()
pygame.display.flip()
pygame.mouse.get_pressed() is not an event, but gives the current state of the mouse buttons. Rnode represents a node and should not draw a line or handle the events. Handle the event in an event loop and add the lines to a list:
import pygame
class Rnode():
def __init__(self, x, y, image_rednode):
self.image_rednode = image_rednode
self.rect = self.image_rednode.get_rect(center = (x, y))
def put(self):
screen.blit(self.image_rednode, self.rect)
class Line():
def __init__(self, nodeFrom, nodeTo):
self.form = nodeFrom
self.to = nodeTo
def draw(self):
p1 = self.form.rect.center
p2 = self.to.rect.center
pygame.draw.line(screen, "yellow", p1, p2, 3)
screen = pygame.display.set_mode((300, 300))
pygame.display.set_caption('Classy, Baby!')
clock = pygame.time.Clock()
#rednode = pygame.image.load('redhole.svg').convert_alpha()
#rednode = pygame.transform.scale(rednode, (100, 100))
rednode = pygame.Surface((40, 40), pygame.SRCALPHA)
pygame.draw.circle(rednode, "red", (20, 20), 20)
nodes = [
Rnode(100, 100, rednode), Rnode(200, 100, rednode),
Rnode(100, 200, rednode), Rnode(200, 200, rednode)]
lines = []
start = None
running = 1
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = 0
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = 0
if event.type == pygame.MOUSEBUTTONDOWN:
for node in nodes:
if node.rect.collidepoint(event.pos):
if start and start != node:
lines.append(Line(start, node))
start = None
else:
start = node
break
screen.fill((0, 0, 0))
for line in lines:
line.draw()
if start:
pygame.draw.line(screen, "yellow", start.rect.center, pygame.mouse.get_pos(), 3)
for node in nodes:
node.put()
pygame.display.flip()
pygame.quit()
I am currently just testing the waters with Pygame display as I am extremely new to the module.
Here is the code:
import pygame
pygame.init()
SCALE = 1
display_width = int(1200 * SCALE)
display_height = int(800 * SCALE)
x = (display_width * 0.45)
y = (display_height * 0.8)
transparent = (0, 0, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
green = (44, 215, 223)
red = (255, 67, 34)
blue = (77, 77, 77)
count = 0
running = True
box1_image = True
box3_image = True
background = pygame.image.load('C:/Users/Justi/source/repos/03 Game/Game/assets/background.jpg')
dirty_spot = pygame.image.load('C:/Users/Justi/source/repos/03 Game/Game/assets/dirty.png')
background_resized = pygame.transform.scale(dirty_spot, (display_width, display_height))
background_rect = background_resized.get_rect()
gameDisplay = pygame.display.set_mode(background_rect.size)
pygame.display.set_caption("Game 1")
clock = pygame.time.Clock()
dirty_spot_resized = pygame.transform.scale(dirty_spot, (200, 200))
square_dirty_spot = dirty_spot_resized.convert()
rect_dirty_spot = square_dirty_spot.get_rect()
def dirtyspot1(imagex, imagey):
gameDisplay.blit(dirty_spot_resized, (imagex,imagey))
while running:
rects = []
if rects != []:
pygame.display.update(rects)
for event in pygame.event.get():
if event.type == pygame.quit:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
running = False
#if box3_image: #Replacing the Bool passing variable with a simple loop count to trigger the else condition
if count < 50:
print("Test 1")
dirtyspot1(0,0)
pygame.display.update()
else:
print("Test 2")
dirty_rect = background.subsurface(rect_dirty_spot)
gameDisplay.blit(dirty_rect, (0,0))
rects.append(pygame.Rect(0,0, 200, 200))
gameDisplay.fill(white)
clock.tick(30)
count += 1
pygame.quit()
quit()
box1_image & box1_image are bool variables to flag certain condition which is passed from another function.
But I have gotten the passing of said variables working by doing a simple test with print("Test 2"). However, when it tries to blit dirty_rect. Nothing changes on the pygame display.
Assets (if needed):
background.jpg
dirty.png
May I check what is missing to properly "remove/delete" the dirty_spot blit? Thank you in advance.
import pygame
pygame.init()
SCALE = 1
display_width = int(1200 * SCALE)
display_height = int(800 * SCALE)
x = (display_width * 0.45)
y = (display_height * 0.8)
transparent = (0, 0, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
green = (44, 215, 223)
red = (255, 67, 34)
blue = (77, 77, 77)
count = 0
running = True
box1_image = True
box3_image = True
background = pygame.image.load('background.jpg')
dirty_spot = pygame.image.load('dirty.png')
background_resized = pygame.transform.scale(background, (display_width, display_height))
background_rect = background_resized.get_rect()
gameDisplay = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption("Game 1")
clock = pygame.time.Clock()
dirty_spot_resized = pygame.transform.scale(dirty_spot, (200, 200))
square_dirty_spot = dirty_spot_resized.convert()
rect_dirty_spot = square_dirty_spot.get_rect()
show_dirt = False
def dirtyspot1(imagex, imagey):
gameDisplay.blit(dirty_spot_resized, (imagex,imagey))
while running:
rects = []
if rects != []:
pygame.display.update(rects)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
running = False
if event.key == pygame.K_d:
show_dirt = not show_dirt
if event.key == pygame.K_UP:
rect_dirty_spot.y -= 5
if event.key == pygame.K_DOWN:
rect_dirty_spot.y += 5
if event.key == pygame.K_RIGHT:
rect_dirty_spot.x += 5
if event.key == pygame.K_LEFT:
rect_dirty_spot.x -= 5
gameDisplay.blit(background_resized, (0,0))
if show_dirt:
gameDisplay.blit(dirty_spot_resized, rect_dirty_spot)
pygame.display.update()
clock.tick(5)
count += 1
pygame.quit()
quit()
like this? (I changed the FPS to 5 so it takes a while to change)
import pygame
pygame.init()
SCALE = 1
display_width = int(1200 * SCALE)
display_height = int(800 * SCALE)
x = (display_width * 0.45)
y = (display_height * 0.8)
transparent = (0, 0, 0, 0)
black = (0, 0, 0)
white = (255, 255, 255)
green = (44, 215, 223)
red = (255, 67, 34)
blue = (77, 77, 77)
count = 0
running = True
box1_image = True
box3_image = True
background = pygame.image.load('background.jpg')
dirty_spot = pygame.image.load('dirty.png')
background_resized = pygame.transform.scale(background, (display_width, display_height))
background_rect = background_resized.get_rect()
gameDisplay = pygame.display.set_mode(background_rect.size)
pygame.display.set_caption("Game 1")
clock = pygame.time.Clock()
dirty_spot_resized = pygame.transform.scale(dirty_spot, (200, 200))
square_dirty_spot = dirty_spot_resized.convert()
rect_dirty_spot = square_dirty_spot.get_rect()
def dirtyspot1(imagex, imagey):
gameDisplay.blit(dirty_spot_resized, (imagex,imagey))
while running:
rects = []
if rects != []:
pygame.display.update(rects)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
running = False
gameDisplay.fill(white)
#if box3_image: #Replacing the Bool passing variable with a simple loop count to trigger the else condition
if count < 50:
print("Test 1")
dirtyspot1(0,0)
else:
print("Test 2")
dirty_rect = background.subsurface(rect_dirty_spot)
gameDisplay.blit(dirty_rect, (0,0))
rects.append(pygame.Rect(0,0, 200, 200))
pygame.display.update()
clock.tick(5)
count += 1
pygame.quit()
quit()
I think you have misunderstood things. You can blit one image or surface on top of another, and you build things up like that, then blit them to the display and finally update the display.
You have this line:
background_resized = pygame.transform.scale(dirty_spot, (display_width, display_height))
which I assume should be background not dirty_spot.
I moved the call to display.update() out of the if loop, because you call display.update() last.
I am trying to make an Algorithm Visualizer with pygame and I started by implementing Linear Search. The problem I am facing is that, in the visualization I am changing colour of the rectangle but that animation is repeating itself as it is inside the while loop. Here is the code:
I want that the animation should stop so that the viewer can actually see what happened. Further I am planning to add more algorithms.
ARRAY = [2, 10, 5, 8, 7, 3, 43, 54, 23, 1]
def main():
global SCREEN, CLOCK
pygame.init()
SCREEN = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
CLOCK = pygame.time.Clock()
num_font = pygame.font.SysFont("roboto", NUM_FONT_SIZE)
x = 3
y = 10
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE:
pygame.quit()
showArray(x, y, num_font)
linearSearch(x, y)
pygame.display.update()
CLOCK.tick(60)
def linearSearch(x, y):
num = 23
box = pygame.Rect(x, y, BOX_SIZE+5, BOX_SIZE)
for i in ARRAY:
if i == num:
pygame.draw.rect(SCREEN, RED, box, 1)
pygame.draw.rect(SCREEN, GREEN, box, 1)
else:
box.x += BOX_SIZE + 5
CLOCK.tick_busy_loop(10)
pygame.draw.rect(SCREEN, RED, box, 1)
pygame.display.update()
def showArray(x, y, num_font):
box = pygame.Rect(x, y, BOX_SIZE+5, BOX_SIZE)
for i in ARRAY:
box.x += BOX_SIZE + 5
pygame.draw.rect(SCREEN, WHITE, box, 1)
nums = num_font.render(str(i), True, WHITE)
SCREEN.blit(nums, (box.x + 5, box.y + 5))
Here is the image of the output
You have an application loop, so use it. Change the function linearSearch. The list index has to be an argument to the function, but remove the for loop has to be removed form the function:
def linearSearch(x, y, list_i):
i = ARRAY[list_i]
num = 23
box = pygame.Rect(x + (BOX_SIZE+5)*(list_i+1), y, (BOX_SIZE+5), BOX_SIZE)
color = GREEN if i == num else RED
pygame.draw.rect(SCREEN, color, box, 1)
Iterate through the list in the main application loop:
def main():
# [...]
list_i = 0
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE:
pygame.quit()
showArray(x, y, num_font)
if list_i < len(ARRAY):
linearSearch(x, y, list_i)
list_i += 1
pygame.display.update()
CLOCK.tick(60)
I've got two lists with 3 rects in each. Can I assign to variables selected1 and selected2 3 rects from each list and move these two rows of rects seperately up and down while keeping the gaps between them? I am beginner and don't know if such constructed code can handle this task.
import pygame
# === CONSTANS ===
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
green = (0, 102, 0)
yellow = (255, 204, 0)
grid_color = (224, 224, 224)
width = 1200
height = 720
k = 10
screen = pygame.display.set_mode((width, height))
screen_rect = screen.get_rect()
# --- objects ---
G_x = 10 # stripe width
x = 2
stripes_x1 = []
stripes_x2 = []
G1_pos_x = 122
G2_pos_x = 367
G1_pos_y = 0
G2_pos_y = 0
G1_y = 60*x
G2_y = 75*x
G1_start = G1_pos_y + height - G1_y
G2_start = G2_pos_y + height - G2_y
a = 166
b = 222
for x in range(3):
gap = a*x
gap2 = b*x
stripes_x1.append(pygame.Rect(G1_pos_x, (G1_start - 6*k) - gap, G_x, G1_y))
stripes_x2.append(pygame.Rect(G2_pos_x, (G2_start - 6*k) - gap2, G_x, G2_y))
selected1 = None
selected2 = None
# --- mainloop ---
clock = pygame.time.Clock()
is_running = True
while is_running:
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for i, r in enumerate(stripes_x1):
if r.collidepoint(event.pos):
selected1 = i
selected_offset_y = r.y - event.pos[1]
if event.type == pygame.MOUSEMOTION:
if selected1 is not None: # selected can be `0` so `is not None` is required
stripes_x1[selected1].y = event.pos[1] + selected_offset_y
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
selected1 = None
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for j, r in enumerate(stripes_x2):
if r.collidepoint(event.pos):
selected2 = j
selected_offset_y = r.y - event.pos[1]
if event.type == pygame.MOUSEMOTION:
if selected2 is not None: # selected can be `0` so `is not None` is required
stripes_x2[selected2].y = event.pos[1] + selected_offset_y
if event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
selected2 = None
# --- objects events ---
'''
button.handle_event(event)
'''
# --- updates ---
# empty
# --- draws ---
screen.fill(white)
for i in range(width):
grid_x = k * i
grid_y = k * i
pygame.draw.line(screen, grid_color, (grid_x, 0), (grid_x, height), 1)
pygame.draw.line(screen, grid_color, (0, grid_y), (width, grid_y), 1)
pygame.draw.line(screen, black, (6 * k, height - 6 * k), (width - 6 * k, height - 6 * k), 3)
pygame.draw.line(screen, black, (6 * k, height - 6 * k), (6 * k, 0 * k), 3)
# draw rect
for r in stripes_x1:
pygame.draw.rect(screen, green, r)
for s in stripes_x2:
pygame.draw.rect(screen, green, s)
pygame.display.update()
clock.tick(60)
pygame.quit()
To move the rects simultaneously, you can put them in a list and, if one rect is selected, move them all with the help of the rel attribute of the MOUSEMOTION event (the relative position from the last mouse event). Here's a minimal example:
import sys
import pygame as pg
BLACK = pg.Color('black')
RECT_COLOR = pg.Color(78, 140, 200)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect_list = [pg.Rect(100, 100+y, 20, 80) for y in range(0, 241, 120)]
selected = False
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
for rect in rect_list:
if rect.collidepoint(event.pos):
selected = True
elif event.type == pg.MOUSEBUTTONUP:
selected = False
elif event.type == pg.MOUSEMOTION:
if selected:
for rect in rect_list:
rect.y += event.rel[1]
screen.fill(BLACK)
for rect in rect_list:
pg.draw.rect(screen, RECT_COLOR, rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()