Pygame: How to correctly use get_rect() - python

I'm trying to understand how get_rect() works. In this simple example, I have two images and want to obtain the location of the second and move the first image to the second image.
I have looked at a variety of examples online and cannot get this to work. What am I doing wrong?
import pygame, sys
from pygame.locals import *
import time
pygame.init()
FPS = 10 # frames per second setting
fpsClock = pygame.time.Clock()
# Set up the window
DISPLAYSURF = pygame.display.set_mode((600, 400), 0, 32)
pygame.display.set_caption('Test program for get_rect()')
WHITE = (255, 255, 255)
# Load two images
baseImg = pygame.image.load('image1.jpg')
spaceshipImg = pygame.image.load('image2.jpg')
DISPLAYSURF.fill(WHITE)
# Place one image at the bottom of the screen
DISPLAYSURF.blit(baseImg, (300, 300))
pygame.display.update()
# Place the second image at the top of the screen
DISPLAYSURF.blit(spaceshipImg, (300, 0))
pygame.display.update()
# Wait for one second
time.sleep(1)
# Obtain the rectangle for each image
baseRect = baseImg.get_rect()
spaceshipRect = spaceshipImg.get_rect()
# This is where I believe I'm going wrong
# I understand this to obtain the x,y of the spaceship image
# Set the xy coordinates for the top image to the xy of the bottom image
spaceshipRect.x = baseRect.x
spaceshipRect.y = baseRect.y
# Move the top image to new xy position
# However this doesn't work
DISPLAYSURF.blit(spaceshipImg, (spaceshipRect.x, spaceshipRect.y))
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()

First, images/pygame.Surfaces don't have a position, so you have to store the blit position in the rect. When you call the get_rect method of a pygame.Surface, Pygame creates a new rect with the size of the image and the x, y coordinates (0, 0). To give the rect other coords during the instantiation you can pass an argument to get_rect, mostly center or topleft is used. To move the rect later, you can change any of these attributes of the rect:
x,y
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery
size, width, height
w,h
Here's an example (press a or d to change the position of the rect and thereby the blit pos of the image):
import sys
import pygame as pg
BG_COLOR = pg.Color(80, 60, 70)
PLAYER_COLOR = pg.Color(90, 140, 190)
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
player_img = pg.Surface((40, 60))
player_img.fill(PLAYER_COLOR)
# Create a rect with the size of the image/pygame.Surface
# and immediately set it's topleft coords to (100, 300).
player_rect = player_img.get_rect(topleft=(100, 300))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_d:
# Set the center to these new coords.
player_rect.center = (400, 200)
if event.key == pg.K_a:
# Set the x coord to 300.
player_rect.x = 300
screen.fill(BG_COLOR)
screen.blit(player_img, player_rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()

Related

center images and add padding according to screen resolution

I'm using pygame to show two images: I've maneged to resize the images according to the screen size of my user. But I'd like to standardized also the x and the y coordination position of my images. The images should always be in the middle according to the y axis and have the a little bit of pad to stay close to the border of the monitor like this no matter what resolution my user
has:
This are the values that I'd like to standardized
WIN.blit(FIRST_IMG, (100, 280))
WIN.blit(SECOND_IMAGE, (1350, 280))
This is my code right now:
import pygame
import os
WIN = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
WHITE = (255, 255, 255)
FPS = 60
SCREEN_INFO = pygame.display.Info()
IMAGE_WIDTH, IMG_HEIGHT = SCREEN_INFO.current_w // 5, SCREEN_INFO.current_h // 3
FIRST_IMG = pygame.image.load(os.path.join("Assets", "7.png"))
FIRST_IMG = pygame.transform.scale(FIRST_IMG, (IMAGE_WIDTH, IMG_HEIGHT))
SECOND_IMAGE = pygame.image.load(os.path.join("Assets", "8.png"))
SECOND_IMAGE = pygame.transform.scale(SECOND_IMAGE, (IMAGE_WIDTH, IMG_HEIGHT))
def draw_window():
WIN.fill(WHITE)
WIN.blit(FIRST_IMG, (100, 280))
WIN.blit(SECOND_IMAGE, (1350, 280))
pygame.display.update()
def main():
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
draw_window()
pygame.quit()
if __name__ == "__main__":
main()
Get the bounding rectangle of the image and set the centery and left or right of the rectangle depending on the size of WIN. Use the rectangles to blit the images:
def draw_window():
width, height = WIN.get_size()
WIN.fill(WHITE)
first_rect = FIRST_IMG.get_rect(midleft = (100, height // 2))
WIN.blit(FIRST_IMG, first_rect)
second_rect = FIRST_IMG.get_rect(midright = (width - 100, height // 2))
WIN.blit(SECOND_IMAGE, second_rect)
pygame.display.update()

How can i give my image an initial position before it starts moving with the mouse?

I'm working on this pygame game and i'm just getting started but got a bit confused because i want the image to move in the x-axis along with the mouse but when i run the program i want the image to show up at the center or the 'floor' but appears at the left side instead. This is my code and a screenshot of what's happening.
import pygame
import sys
pygame.init()
pygame.mixer.init()
WIDTH, HEIGHT = 400, 500
FPS = 60
TITLE = 'FOOD DROP'
SIZE = 190
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE_SKY = (152, 166, 255)
# Display
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
# Surfaces
floor_surface = pygame.Surface((WIDTH, 100))
floor_surface.fill(BLUE_SKY)
floor_rect = floor_surface.get_rect(midbottom=(200, 500))
# Images
LOAD_DITTO = pygame.image.load('Graphics/ditto.png')
DITTO = pygame.transform.scale(LOAD_DITTO, (SIZE, SIZE))
# Time
CLOCK = pygame.time.Clock()
class Figure:
def draw_figure(self, mouse_x):
SCREEN.blit(DITTO, (mouse_x - 90, 330))
# Game loop
SCREEN_UPDATE = pygame.USEREVENT
# main_game = Main()
figure = Figure()
running = True
while running:
CLOCK.tick(FPS)
mx, my = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
SCREEN.fill(WHITE)
SCREEN.blit(floor_surface, floor_rect)
figure.draw_figure(mx)
pygame.display.update()
When i run the program, this happens:
And i want the image to appear right at the center or the x-axis, not the border, i don't know why is this happening. Just to state, that screenshot was taken when the mouse hadn't been placed over the display.
If the mouse pointer is not in the window (out of focus), the initial position of the mouse pointer is (0, 0). Therefore pygame.mouse.get_pos returns (0, 0). It is also not possible to set the mouse position with pygame.mouse.set_pos if it is not in the window.
Initialize the variables mx and mx with the center of the window. Change the mouse position only when the mouse pointer is in the window (in focus). pygame.mouse.get_focused can be used to test whether the mouse is in the window.
mx, my = SCREEN.get_rect().center
running = True
while running:
CLOCK.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if pygame.mouse.get_focused():
mx, my = pygame.mouse.get_pos()
SCREEN.fill(WHITE)
SCREEN.blit(floor_surface, floor_rect)
figure.draw_figure(mx)
pygame.display.update()
pygame.quit()
sys.exit()

Image in pygame gets pixelated after scaling it several times [duplicate]

There is the image I'm importing :
look_1 = pygame.image.load('data\\png\\look1.png').convert_alpha()
And what I tried to get its size reduce was this :
pygame.transform.scale()
But this seems not to be the right way to do it.
You can either use pygame.transform.scale or smoothscale and pass the new width and height of the surface or pygame.transform.rotozoom and pass a float that will be multiplied by the current resolution.
import sys
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
IMAGE = pg.Surface((100, 60))
IMAGE.fill(pg.Color('sienna2'))
pg.draw.circle(IMAGE, pg.Color('royalblue2'), (50, 30), 20)
# New width and height will be (50, 30).
IMAGE_SMALL = pg.transform.scale(IMAGE, (50, 30))
# Rotate by 0 degrees, multiply size by 2.
IMAGE_BIG = pg.transform.rotozoom(IMAGE, 0, 2)
def main():
clock = pg.time.Clock()
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
screen.fill(pg.Color('gray15'))
screen.blit(IMAGE, (50, 50))
screen.blit(IMAGE_SMALL, (50, 155))
screen.blit(IMAGE_BIG, (50, 230))
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
main()
pg.quit()
sys.exit()
You have to decide if you want to use Use pygame.transform.smoothscale or pygame.transform.scale. While pygame.transform.scale performs a fast scaling with the nearest pixel, pygame.transform.smoothscale scales a surface smoothly to any size with interpolation of the pixels.
Scaling up a Surface with pygame.transform.scale() will result in a jagged result. When downscaling you lose information (pixels). In comparison, pygame.transform.smoothscale blurs the Surface.
pygame.transform.scale() and pygame.transform.smoothscale are used in the same way. They do not scale the input Surface itself. It creates a new surface and does a scaled "blit" to the new surface. The new surface is returned by the return value. They:
Creates a new surface (newSurface) with size (width, height).
Scale and copy Surface to newSurface.
Return newSurface.
look_1 = pygame.image.load('data\\png\\look1.png').convert_alpha()
look_1 = pygame.transform.scale(look_1, (new_width, new_height))
or
look_1 = pygame.image.load('data\\png\\look1.png').convert_alpha()
look_1 = pygame.transform.smoothscale(look_1, (new_width, new_height))
See also Transform scale and zoom surface
Minimal example: replit.com/#Rabbid76/PyGame-ScaleCenter
import pygame
class ScaleSprite(pygame.sprite.Sprite):
def __init__(self, center, image):
super().__init__()
self.original_image = image
self.image = image
self.rect = self.image.get_rect(center = center)
self.mode = 1
self.grow = 0
def update(self):
if self.grow > 100:
self.mode = -1
if self.grow < 1:
self.mode = 1
self.grow += 1 * self.mode
orig_x, orig_y = self.original_image.get_size()
size_x = orig_x + round(self.grow)
size_y = orig_y + round(self.grow)
self.image = pygame.transform.scale(self.original_image, (size_x, size_y))
self.rect = self.image.get_rect(center = self.rect.center)
pygame.init()
window = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
sprite = ScaleSprite(window.get_rect().center, pygame.image.load("Banana64.png"))
group = pygame.sprite.Group(sprite)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
group.update()
window.fill(0)
group.draw(window)
pygame.display.flip()
pygame.quit()
exit()
Import the Image first.
Then we can use pygame.transform.scale.
This is a fast-scale operation.
self.image = pygame.image.load('ship.bmp')
self.image = pygame.transform.scale(self.image,(35,35))
You can do:
import pygame,sys
from pygame.locals import *
size = int(input("What is the size?"))
look_1 = pygame.image.load('data\\png\\look1.png')
win = pygame.display.set_mode((500,500),0,32)
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
win.blit(pygame.transform.scale(look_1, (size, size)), (x, y))
win.update()
I hope it helps!

Is there a way to make a circle with my own picture with pygame?

Hello i want to make a picture of type pygame.circle(something like get_rect() but circle). That's for an Billiard game and to be able to move them properly i think they would be circles. Here's the code:
import pygame
import pyautogui
width, height = pyautogui.size()
pygame.init()
screen = pygame.display.set_mode(pyautogui.size())
pygame.display.set_caption('Billiard')
background_image = pygame.image.load("Table.png")
background_image = pygame.transform.scale(background_image, pyautogui.size())
ball_1 = pygame.image.load("Ball_1.png")
ball_1 = pygame.transform.scale(ball_1, (65, 65))
screen.blit(ball_1, [400, 400])
clock = pygame.time.Clock()
screen.blit(background_image, [0,0])
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
clock.tick(30)
I want to make the balls as circles
Thanks in advance
Create a transparent pygame.Surface object and use pygame.draw.circle to draw a circle on it:
radius = 20 # just for example
color = "red"
circle_surf = pygame.Surface((radius * 2, radius * 2), pygame.SRCALPHA)
pygame.draw.circle(circle_surf, color, (radius, radius), radius)

Clicking on image will not work

I am using pygame to create a fully customizable enigma machine in python. One thing I decided to implement early is a help function. When I was testing this, nothing would show up on the console. Here is the code for the image clicking (not all of the code)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
pygame.display.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
if img.get_rect().collidepoint(x, y):
print('test')
How do I make this work? All help would be useful.
When you call img.get_rect() you create a pygame.Rect with the size of the image/surface and the default topleft coordinates (0, 0), i.e. your rect is positioned at the top left corner of your screen. I suggest creating a rect instance for the img at the beginning of the program and use it as the blit position and for the collision detection. You can pass the topleft, center, x, y, etc., coordinates directly as an argument to get_rect: rect = img.get_rect(topleft=(200, 300)).
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
img = pg.Surface((100, 50))
img.fill((0, 100, 200))
# Create a pygame.Rect with the size of the surface and
# the `topleft` coordinates (200, 300).
rect = img.get_rect(topleft=(200, 300))
# You could also set the coords afterwards.
# rect.topleft = (200, 300)
# rect.center = (250, 325)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.MOUSEBUTTONDOWN:
if rect.collidepoint(event.pos):
print('test')
screen.fill(BG_COLOR)
# Blit the image/surface at the rect.topleft coords.
screen.blit(img, rect)
pg.display.flip()
clock.tick(60)
pg.quit()

Categories

Resources