How to move the location of a grid in pygame - python

import pygame
pygame.init()
width = 800
height = 600
running = True
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Dijkstra's Path-Finding Algorithm Solver")
icon = pygame.image.load('icon.jpg')
pygame.display.set_icon(icon)
def title():
button_font = pygame.font.Font('TrajanPro-Regular.otf', 40)
rect_display = button_font.render('Dijkstra Path-Finding Algorithm', True, (255, 255, 255))
# display global total deaths
screen.blit(rect_display, (12, 10))
def title_underline():
# create the button
rect = pygame.Rect(0, 60, 800, 3)
rect_display = pygame.draw.rect(screen, [255, 255, 255], rect)
button_font = pygame.font.Font('TrajanPro-Regular.otf', 100)
rect_display = button_font.render('', True, (255, 255, 255))
# display global total deaths
screen.blit(rect_display, (270, 198))
def grid():
blockSize = 20 #Set the size of the grid block
for x in range(width):
for y in range(height):
rect = pygame.Rect(x*blockSize, y*blockSize, blockSize, blockSize)
pygame.draw.rect(screen, (200,200,200), rect, 1)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((0, 0, 0))
title()
title_underline()
grid()
pygame.display.update()
I have created a title for my project and I created a grid for which I want to run my application, but the grid is being made in every single x, y location on my screen. But I want the grid to only be made under the title and not over it.

Define the top left coordinates of the grid (grid_x, grid_y) and add the coordinates when constructing the rectangle of a cell. For instance:
def grid():
grid_x = 12
grid_y = 30
blockSize = 20 #Set the size of the grid block
for x in range(width):
for y in range(height):
rect = pygame.Rect(
grid_x + x*blockSize, grid_y + y*blockSize,
blockSize, blockSize)
pygame.draw.rect(screen, (200,200,200), rect, 1)

Related

How to subtract geometry in pygame?

I am trying to make a logic in which i can subtract the geometrical shapes. Lets say i have to subtract a circle from a rectangle.
The idea is to draw each point of the rectangle as a single individual point using win.set_at(). And then when we need to subtract the circle from the rectangle we an simply calculate that the point on which we are drawing and completing our square lies or not in the circle. If it lies then don't set pixels else draw the pixel. This is my code:
import pygame
WIDTH, HEIGHT = 700, 500
win = pygame.display.set_mode((WIDTH, HEIGHT))
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
def drawer(window, x, y, radius, s_l, s_w, s_x, s_y):
for i in range(0, HEIGHT):
for j in range(0, WIDTH):
distance = (x - j)**2 + (y - i)**2
if not distance <= radius**2 and i >= s_y and j >= s_x and i <= s_w + s_x and j <= s_l + s_y:
window.set_at((j, i), BLACK)
c_x, c_y = 130, 150
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
win.fill(WHITE)
drawer(win, c_x, c_y, 30, 100, 100, 100, 100)
pygame.display.flip()
pygame.quit()
But is it is quite slow. Can you suggest a better way (more optimized algorithm) of doing it.
For a good performance I suggest to use pygame.mask. Draw the shapes on pygame.Surface objects and create masks from the surfaces:
mask1 = pygame.mask.from_surface(shape1)
mask2 = pygame.mask.from_surface(shape2)
Invert the mask of the second shape and create the overlapping mask. Finally, create a new _Surface: from the overlapping mask:
mask2.invert()
subtract_maks = mask1.overlap_mask(mask2, (0, 0))
subtract_shape = subtract_maks.to_surface(setcolor = "red", unsetcolor=(0, 0, 0, 0))
Minimal example
import pygame
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
shape1 = pygame.Surface((200, 200), pygame.SRCALPHA)
pygame.draw.circle(shape1, "white", (100, 100), 100)
shape2 = pygame.Surface((200, 200), pygame.SRCALPHA)
pygame.draw.rect(shape2, "white", (25, 50, 150, 100))
mask1 = pygame.mask.from_surface(shape1)
mask2 = pygame.mask.from_surface(shape2)
mask2.invert()
subtract_maks = mask1.overlap_mask(mask2, (0, 0))
subtract_shape = subtract_maks.to_surface(setcolor = "red", unsetcolor=(0, 0, 0, 0))
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *background.get_size(), (128, 128, 128), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
[pygame.draw.rect(background, color, rect) for rect, color in tiles]
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))
window.blit(background, (0, 0))
window.blit(subtract_shape, (50, 50))
pygame.display.flip()
pygame.quit()
exit()

drawing objects on pygame

I am restarting some code for a covid simulation as I cant use the collide function in my current one. I have been able to draw the basic background, and draw one cell. However, when i try create the cell in a different place on my screen it does not appear for some reason.
My code is as seen below:
import random
import pygame
# import numpy
import time
pygame.init()
GREEN1 = (0, 255, 0) # Healthy cells
RED = (255, 0, 0) # Infected cells
GREEN2 = (0, 100, 0) # Healthy cells not susecptible
BLACK = (0, 0, 0) # Dead cells
WHITE = (255, 255, 255)
Bgcolor = (225, 198, 153)
ScreenSize = (800, 800)
Screen = pygame.display.set_mode(ScreenSize)
pygame.display.set_caption("Covid-19 Simualtion")
clock = pygame.time.Clock()
speed = [0.5, -0.5]
class Cells(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
super().__init__()
self.color = color
self.x_cord = random.randint(0, 400)
self.y_cord = random.randint(50, 700)
self.radius = 5
self.speed = speed
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
pygame.draw.circle(self.image, self.color, [30, 70], self.radius, width = 0)
self.rect = self.image.get_rect()
self.radius = 5
#x_number = random.randint(0, 1)
#self.xSpeed = speed[x_number]
#y_number = random.randint(0, 1)
#self.ySpeed = speed[y_number]
allCellsList = pygame.sprite.Group()
Cell1 = Cells(GREEN1, 5, 50, 50)
allCellsList.add(Cell1)
End = False
while not End:
for event in pygame.event.get():
if event.type == pygame.QUIT:
End = True
Screen.fill(Bgcolor)
pygame.draw.rect(Screen, BLACK, (0, 50, 400, 700), 3)
allCellsList.update()
allCellsList.draw(Screen)
pygame.display.flip()
clock.tick(60)
Thanks for any help in advance
The main problem is that your cell has size (50,50) and you try to draw on position (20,70) so it draws outside rectangle (50, 50) and you can't see it. You have to draw inside rectangle (50, 50) - for example in center (25,25). And later you should use self.rect to move it on screen.
Second problem is that you keep position in self.x_coord, self.x_coord but you should use self.rect.x self.rect.y because Sprite use self.image and self.rect to draw it on screen.
And it show third problem - in Cell you need method update which will change values in self.rect to move object.
Minimal working example which move 5 cells in random directions.
I organize code in different way and try to use PEP 8 - Style Guide for Python Code
import random
import pygame
# --- constants --- (UPPER_CASE_NAMES)
GREEN1 = (0, 255, 0) # Healthy cells
RED = (255, 0, 0) # Infected cells
GREEN2 = (0, 100, 0) # Healthy cells not susecptible
BLACK = (0, 0, 0) # Dead cells
WHITE = (255, 255, 255)
BACKGROUND_COLOR = (225, 198, 153)
SCREEN_SIZE = (800, 800)
# --- classes --- (CamelCaseNames)
# class keeep only one cell so it should has name `Cell` instead of `Cells`
class Cell(pygame.sprite.Sprite):
def __init__(self, color, speed, width, height):
super().__init__()
self.color = color
self.speed = speed
self.image = pygame.Surface([width, height])
self.image.fill(WHITE)
self.image.set_colorkey(WHITE)
self.radius = width//2 # 25
center = [width//2, height//2]
pygame.draw.circle(self.image, self.color, center, self.radius, width=0)
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, 400)
self.rect.y = random.randint(50, 700)
def update(self):
self.rect.x += random.randint(-10, 10)
self.rect.y += random.randint(-10, 10)
# --- functions --- (lower_case_names)
# empty
# --- main --- (lower_case_names)
pygame.init()
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Covid-19 Simualtion")
speed = [0.5, -0.5]
# - objects -
all_cells = pygame.sprite.Group() # PEP8: lower_case_name
for _ in range(5):
cell = Cell(GREEN1, 5, 50, 50) # PEP8: lower_case_name
all_cells.add(cell)
# - loop -
clock = pygame.time.Clock()
end = False
while not end:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
end = True
# - upadates (without draws) -
all_cells.update()
# - draws (without updates) -
screen.fill(BACKGROUND_COLOR)
pygame.draw.rect(screen, BLACK, (0, 50, 400, 700), 3)
all_cells.draw(screen)
pygame.display.flip()
clock.tick(30) # to use less CPU
# - end
pygame.quit() # some system may need it to close window

Python: How to make drawn elements snap to grid in pygame

I am experimenting with a Pathfinding project and got stuck while creating a working GUI. I'm using pygame and already created a grid and a feature, which draws cubes when you press (or keep pressing) the mouse-button. However, these cubes just go wherever you click, and do not snap to the grid. I thought about using modulo somehow but I cannot seem to get it to work. Please find the code attached below. The Cube class is what I use for the squares drawn on the screen. Moreover, the drawgrid() function is how I set up my grid. I'd love some help on this, as I've been stuck on this roadblock for three days now.
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 20, 20)
def draw(self):
click = pygame.mouse.get_pressed()
if click[0]: # evaluate left button
pygame.draw.rect(screen, (255, 255, 255), self.square)
Other drawgrid() function:
def drawgrid(w, rows, surface):
sizebtwn = w // rows # Distance between Lines
x = 0
y = 0
for i in range(rows):
x = x + sizebtwn
y = y + sizebtwn
pygame.draw.line(surface, (255, 255, 255), (x, 0), (x, w))
pygame.draw.line(surface, (255, 255, 255), (0, y), (w, y))
You have to align the position to the grids size. Use the floor division operator (//) to divide the coordinates by the size of a cell and compute the integral index in the grid:
x, y = pygame.mouse.get_pos()
ix = x // sizebtwn
iy = y // sizebtwn
Multiply the result by the size of a cell to compute the coordinate:
self.cx, self.cy = ix * sizebtwn, iy * sizebtwn
Minimal example:
import pygame
pygame.init()
screen = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
def drawgrid(w, rows, surface):
sizebtwn = w // rows
for i in range(0, w, sizebtwn):
x, y = i, i
pygame.draw.line(surface, (255, 255, 255), (x, 0), (x, w))
pygame.draw.line(surface, (255, 255, 255), (0, y), (w, y))
class Cube:
def update(self, sizebtwn):
x, y = pygame.mouse.get_pos()
ix = x // sizebtwn
iy = y // sizebtwn
self.cx, self.cy = ix * sizebtwn, iy * sizebtwn
self.square = pygame.Rect(self.cx, self.cy, sizebtwn, sizebtwn)
def draw(self, surface):
click = pygame.mouse.get_pressed()
if click[0]:
pygame.draw.rect(surface, (255, 255, 255), self.square)
cube = Cube()
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
cube.update(screen.get_width() // 10)
screen.fill(0)
drawgrid(screen.get_width(), 10, screen)
cube.draw(screen)
pygame.display.flip()

Need help creating buttons in pygame

I have been assigned a homework problem in pygame to make two rectangles, one red , one green and when clicked, text appears which gives the name of the colour of the button, I have created the shapes successfully, however I don't know how to make the text appear when the button is clicked. Any help is appreciated
I have successfully drawn two rectangles using the pygame.draw.rect() function and I have called pos = pygame.mouse.get_pos() in order to get an x and y value for the user's mouse.
pos = pygame.mouse.get_pos()
x = pos[0]
y = pos[1]
screen.fill(WHITE)
pygame.draw.rect(screen, GREEN, [100, 300, 200, 200])
pygame.draw.rect(screen, RED, [400, 300, 200, 200])
pygame.display.flip()
clock.tick(60)
The result is two rectangles, one green, one red in the centre of the screen.
To verify if amouse button is pressed oyu can use pygame.mouse.get_pressed():
leftClicked = pygame.mouse.get_pressed()[0]
For text rendering you can use pygame.font or pygame.pygame.freetype. e. g:
import pygame.freetype
font = pygame.freetype.SysFont('Times New Roman', 30)
Define a pygame.Rect for each button:
rect_green = pygame.Rect(100, 300, 200, 200)
rect_red = pygame.Rect(400, 300, 200, 200)
Verify if the mouse button is pressed an the mouse coursor is on the button by .collidepoint()). e.g.:
pygame.draw.rect(screen, GREEN, rectGreen)
if leftClicked and rectGreen.collidepoint(pos):
text_surf, text_rect = font.render("GREEN", WHITE, size=30)
text_rect.center = rectGreen.center
screen.blit(text_surf, text_rect)
See the short example:
import pygame
import pygame.freetype
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
pygame.init()
size = (800,600)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
font = pygame.freetype.SysFont('Times New Roman', 30)
rect_green = pygame.Rect(100, 300, 200, 200)
rect_red = pygame.Rect(400, 300, 200, 200)
def DrawButton(surf, cursor_pos, pressed, rect, color, text_color, text):
pygame.draw.rect(surf, color, rect)
if pressed and rect.collidepoint(cursor_pos):
text_surf, text_rect = font.render(text, text_color, size=30)
text_rect.center = rect.center
screen.blit(text_surf, text_rect)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pos = pygame.mouse.get_pos()
x = pos[0]
y = pos[1]
leftClicked = pygame.mouse.get_pressed()[0]
screen.fill(WHITE)
DrawButton(screen, pos, leftClicked, rect_green, GREEN, BLACK, "GREEN")
DrawButton(screen, pos, leftClicked, rect_red, RED, BLACK, "RED")
pygame.display.flip()
clock.tick(60)
pygame.quit()

How to make a grid in pygame

I am trying to create a basic snake game with Python and I am not familiar with Pygame. I have created a window and I am trying to split that window up into a grid based on the size of the window and a set square size.
def get_initial_snake( snake_length, width, height, block_size ):
window = pygame.display.set_mode((width,height))
background_colour = (0,0,0)
window.fill(background_colour)
return snake_list
What should I add inside window.fill function to create a grid based on width, height, and block_size? Any info would be helpful.
Using the for loop as a reference from the answer: https://stackoverflow.com/a/33963521/9715289
This is what I did when I was trying to make a snake game.
BLACK = (0, 0, 0)
WHITE = (200, 200, 200)
WINDOW_HEIGHT = 400
WINDOW_WIDTH = 400
def main():
global SCREEN, CLOCK
pygame.init()
SCREEN = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
CLOCK = pygame.time.Clock()
SCREEN.fill(BLACK)
while True:
drawGrid()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
def drawGrid():
blockSize = 20 #Set the size of the grid block
for x in range(0, WINDOW_WIDTH, blockSize):
for y in range(0, WINDOW_HEIGHT, blockSize):
rect = pygame.Rect(x, y, blockSize, blockSize)
pygame.draw.rect(SCREEN, WHITE, rect, 1)
How the result looks like:
You can draw rectangles
for y in range(height):
for x in range(width):
rect = pygame.Rect(x*block_size, y*block_size, block_size, block_size)
pygame.draw.rect(window, color, rect)
I assumed that the height and width is the number of blocks.
if you need one pixel gap between rectangles then use
rect = pygame.Rect(x*(block_size+1), y*(block_size+1), block_size, block_size)
To draw snake you can use list and head_color, tail_color
snake = [(0,0), (0,1), (1,1), (1,2), (1,3)]
# head
x, y = snake[0]
rect = pygame.Rect(x*block_size, y*block_size, block_size, block_size)
pygame.draw.rect(window, head_color, rect)
# tail
for x, y in snake[1:]:
rect = pygame.Rect(x*block_size, y*block_size, block_size, block_size)
pygame.draw.rect(window, tail_color, rect)

Categories