Collide Images in Pygame - python

im trying to check if two images collide but im just getting back an error saying
"'pygame.Surface' object has no attribute 'colliderect'". The images are battery and playerPic and i did a define to see if they collide. It should return a black screen if they collide.
Note: i removed the drawScene from my code on here
#initialize pygame
from pygame import *
import os
import random
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0, 0)
init()
#set screen size
size = width, height = 800, 600
screen = display.set_mode(size)
#set fonts
fontGame=font.SysFont("Times New Roman", 30)
fontBack=font.SysFont("Ariel", 30)
fontTitle=font.SysFont("Ariel", 100)
fontResearch=font.SysFont ("Times New Roman", 18)
#set button and page to 0
button = 0
page=0
#setting colours
BLACK = (0, 0, 0)
RED = (255,0,0)
GREEN = (0, 255, 0)
BLUE = (106,186,232)
#loading image
backgroundPic=image.load("Background.jpg")
backgroundGame=image.load("gameBackground.jpg")
backgroundGame=transform.scale(backgroundGame,(800,600))
battery=image.load("Battery.png")
battery=transform.scale(battery,(100,100))
backgroundx=0
playerPic=image.load("player.png")
playerPic=transform.scale(playerPic,(70,70))
batteryx=[]
#defining what is going to be shown on the screen
def drawScene(screen, button,page,locationx,locationy):
global batteryx
mx, my = mouse.get_pos() #will get where the mouse is
#if the user does nothing
if page==0:
draw.rect(screen, BLACK, (0,0, width, height))
screen.fill(BLACK)
rel_backgroundx= backgroundx % backgroundGame.get_rect().width
screen.blit(backgroundGame, (rel_backgroundx - backgroundGame.get_rect().width,0))
if rel_backgroundx < width:
screen.blit (backgroundGame, (rel_backgroundx,0))
screen.blit(playerPic,(locationx,locationy))
screen.blit(battery,(batteryx,420))
batteryx-=1
display.flip()
return page
def collision (battery, playerPic):
if battery.colliderect(playerPic):
return True
return False
running = True
myClock = time.Clock()
KEY_LEFT= False
KEY_RIGHT= False
KEY_UP= False
KEY_DOWN= False
locationx=0
jumping=False
accel=20
onGround= height-150
locationy=onGround
batteryx=random.randrange(50,width,10)
# Game Loop
while running:
button=0
print (KEY_LEFT, KEY_RIGHT)
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running=False
if evnt.type == MOUSEBUTTONDOWN:
mx,my=evnt.pos
button = evnt.button
if evnt.type== KEYDOWN:
if evnt.key==K_LEFT:
KEY_LEFT= True
KEY_RIGHT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= True
KEY_LEFT= False
if evnt.key==K_UP and jumping==False:
jumping=True
accel=20
if evnt.key== K_DOWN:
KEY_DOWN= True
KEY_UP= False
if evnt.type==KEYUP:
if evnt.key==K_LEFT:
KEY_LEFT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= False
if evnt.key==K_DOWN:
KEY_DOWN=False
if KEY_LEFT== True:
locationx-=10
backgroundx+=10
if KEY_RIGHT== True:
locationx+=10
backgroundx-=10
if jumping==True:
locationy-=accel
accel-=1
if locationy>=onGround:
jumping=False
locationy=onGround
#player cannot move off screen
if locationx<0:
locationx=0
if locationx>400:
locationx=400
if collision(battery, playerPic)==True:
screen.fill(BLACK)
page=drawScene(screen,button,page,locationx,locationy)
myClock.tick(60) # waits long enough to have 60 fps
if page==6: #if last button is clicked program closes
running=False
quit()

Images/pygame.Surfaces can't be used for collision detection. You have to create pygame.Rect objects for the battery and the player and then use their colliderect method. You can use the get_rect method of the surfaces to get rects with their size and then update the positions of the rects every time you move the player or the battery.
# Create a rect with the size of the playerPic with
# the topleft coordinates (0, 0).
player_rect = playerPic.get_rect()
In the while loop:
# Adjust the position of the rect.
player_rect.x = locationx
player_rect.y = locationy
# You can also assign the location variables to the topleft attribute.
player_rect.topleft = (locationx, locationy)
# Then pass the battery_rect and player_rect to the collision function.
if collision(battery_rect, player_rect):
You can also shorten the collision function:
def collision(battery_rect, player_rect):
return battery_rect.colliderect(player_rect)
Or just call battery_rect.colliderect(player_rect) in the while loop.
Here's a minimal, complete example:
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
player_image = pg.Surface((30, 50))
player_image.fill(pg.Color('dodgerblue1'))
battery_image = pg.Surface((30, 50))
battery_image.fill(pg.Color('sienna1'))
speed_x = 0
location_x = 100
# Define the rects.
# You can pass the topleft position to `get_rect` as well.
player_rect = player_image.get_rect(topleft=(location_x, 100))
battery_rect = battery_image.get_rect(topleft=(200, 100))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_a:
speed_x = -4
elif event.key == pg.K_d:
speed_x = 4
# Update the location and the player_rect.
location_x += speed_x
player_rect.x = location_x
if player_rect.colliderect(battery_rect):
print('collision')
# Blit everything.
screen.fill(BG_COLOR)
screen.blit(player_image, player_rect)
screen.blit(battery_image, battery_rect)
pg.display.flip()
clock.tick(30)
pg.quit()

Related

Mouse not interacting with object correctly using collidepoint function

So I used the collidepoint function to test out whether or not my mouse is interacting or can interact with the images on the surface Surface but the variable mouse_pos does give out a position yet the mouse cannot ever collide with the object (see A is always false rather than true when the mouse hit the object). How do I solve this
Code:
import pygame
from sys import exit
pygame.init()
widthscreen = 1440 #middle 720
heightscreen = 790 #middle 395
w_surface = 800
h_surface = 500
midalignX_lg = (widthscreen-w_surface)/2
midalignY_lg = (heightscreen-h_surface)/2
#blue = player
#yellow = barrier
screen = pygame.display.set_mode((widthscreen,heightscreen))
pygame.display.set_caption("Collision Game")
clock = pygame.time.Clock()
test_font = pygame.font.Font('font/Pixeltype.ttf', 45)
surface = pygame.Surface((w_surface,h_surface))
surface.fill('Light Yellow')
blue_b = pygame.image.load('images/blue.png').convert_alpha()
blue_b = pygame.transform.scale(blue_b,(35,35))
yellow_b = pygame.image.load('images/yellow.png').convert_alpha()
yellow_b = pygame.transform.scale(yellow_b,(35,35))
text_surface = test_font.render('Ball Option:', True, 'White')
barrier_1_x = 0
barrier_1_surf = pygame.image.load('images/yellow.png').convert_alpha()
barrier_1_surf = pygame.transform.scale(barrier_1_surf,(35,35))
barrier_1_rect = barrier_1_surf.get_rect(center = (100, 350))
player_surf = pygame.image.load('images/blue.png').convert_alpha()
player_surf = pygame.transform.scale(player_surf,(35,35))
player_rect = player_surf.get_rect(center = (0,350))
while True:
#elements & update
#event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
screen.blit(surface, (midalignX_lg,midalignY_lg))
screen.blit(blue_b,(150,250))
screen.blit(yellow_b, (150,300))
screen.blit(text_surface,(150, 200))
#barrier_1_x += 3
#if barrier_1_x > 800: barrier_1_x = 0
#barrier_1_rect.x += 3
#if barrier_1_rect.x > 800: barrier_1_rect.x = 0
barrier_1_rect.x += 2
if barrier_1_rect.right >= 820: barrier_1_rect.left = -10
player_rect.x += 3
if player_rect.right >= 820: player_rect.left = -10
surface = pygame.Surface((w_surface,h_surface))
surface.fill('Light Yellow')
surface.blit(barrier_1_surf, barrier_1_rect)
surface.blit(player_surf, player_rect)
'''if player_rect.colliderect(barrier_1_rect):
print('collision')'''
A = False;
mouse_pos = pygame.mouse.get_pos()
if player_rect.collidepoint(mouse_pos):
A = True
print(A)
pygame.display.update()
clock.tick(60)
I am not sure what else to do. i think it may be something wrong with the layering of the surface?
You are not drawing the objects on the screen, but on the surface. Therefore the coordinates of player_rect are relative to the surface and you also have to calculate the mouse position relative to the surface. The top left coordinate of the surface is (midalignX_lg, midalignY_lg):
while True:
# [...]
mouse_pos = pygame.mouse.get_pos()
rel_x = mouse_pos[0] - midalignX_lg
rel_y = mouse_pos[1] - midalignY_lg
if player_rect.collidepoint(rel_x, rel_y):
print("hit")

How would I create side scrolling text in PyGame?

I am currently working on a weather application using the PyGame framework and it needs to have side scrolling text at the bottom, but I wouldn't know how to do it. I have looked for tutorials online and I have found things similar but not quite what I would like.
This is my code around the end, where all of the text is initalized.
desc_text = desc.render(description, True, (255, 255, 255))
desc_rect = desc_text.get_rect()
desc_rect.center = (238, 740)
screen = pygame.display.set_mode((960, 720), pygame.FULLSCREEN, vsync=1)
while running:
try:
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == QUIT:
running = False
screen.fill((0, 0, 125))
screen.blit(header_text, header_rect)
screen.blit(temperature_text, temperature_rect)
screen.blit(wind_text, wind_rect)
screen.blit(desc_text, desc_rect)
pygame.display.update()
except KeyboardInterrupt:
print("Quitting...")
running = False
This is the text.
I want it to be like a marquee, scrolling left to right endlessly.
I don't understand what is the problem.
The simplest version which moves to left and when all text leave screen on left side then it shows it again on right need
put on right side rect.x = screen_rect.right
in every loop move rect.x -= 1
in every loop check if it all text leave screen rect.right <= 0 and move to right side rect.x = screen_rect.right
and you should start with this - and later try to create more complex version which repeat text at once after when there is space text.
import pygame
# --- constants --- # PEP8: `UPPER_CASE_NAMES`; directly after import
FPS = 30
# --- main ---
pygame.init()
screen = pygame.display.set_mode((960, 720))#, pygame.FULLSCREEN, vsync=1)
screen_rect = screen.get_rect()
font = pygame.font.SysFont(None, 50)
description = " How would I create side scrolling text in PyGame? "
desc_text = font.render(description, True, (255, 255, 255))
desc_rect = desc_text.get_rect(left=screen_rect.right)
clock = pygame.time.Clock()
running = True
while running:
try:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.QUIT:
running = False
# --- updates (without draws) ---
desc_rect.x -= 5
if desc_rect.right <= 0: # if leave on left side
desc_rect.x = screen_rect.right # then move to right side
# --- draws (without updates) ---
screen.fill((0, 0, 125))
screen.blit(desc_text, desc_rect)
pygame.display.update()
clock.tick(FPS) # slowdown to 30 FPS
except KeyboardInterrupt:
print("Quitting...")
running = False
pygame.quit()
To make more complex version you have to repeate the same text 2 or 3 times - so it needs to create 2 or 3 rect with offsets. First starts at rect.x second starts at rect.x + rect.width and third starts at rect.x + rect.width + rect.width. And for all of then you have to repeat (almost) the same code as in previous version. If you put all rect on list then it can be simpler.
Difference is: when it leave on left side then move to right by rect.width * 3
import pygame
# --- constants --- # PEP8: `UPPER_CASE_NAMES`; directly after import
FPS = 30
# --- main ---
pygame.init()
screen = pygame.display.set_mode((960, 720))#, pygame.FULLSCREEN, vsync=1)
screen_rect = screen.get_rect()
font = pygame.font.SysFont(None, 50)
description = " How would I create side scrolling text in PyGame? "
desc_text = font.render(description, True, (255, 255, 255))
# because text is short so I need 3 copies (with different offsets)
desc_rects = []
for i in range(3):
rect = desc_text.get_rect(left=screen_rect.right)
rect.x += rect.width * i # add offset
desc_rects.append(rect)
clock = pygame.time.Clock()
running = True
while running:
try:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.type == pygame.QUIT:
running = False
# --- updates (without draws) ---
for rect in desc_rects:
rect.x -= 5
if rect.right <= 0:
rect.x += rect.width * 3
# --- draws (without updates) ---
screen.fill((0, 0, 125))
for rect in desc_rects:
screen.blit(desc_text, rect)
pygame.display.update()
clock.tick(FPS) # slowdown to 30 FPS
except KeyboardInterrupt:
print("Quitting...")
running = False
pygame.quit()

Why does my sprite reset to the top left of the screen when I try to rotate it with pygame.transform.rotate? [duplicate]

This question already has answers here:
How do I rotate an image around its center using Pygame?
(6 answers)
Closed 1 year ago.
I'm trying to rotate a sprite 90 degrees whenever the player presses the A and D keys, and I've got that working, but the sprite is always sent to the top left corner of the screen whenever this happens. Can someone shed some light on this? As well as that, I've tried to get a shooting system working with shooting asteroids, by creating an asteroid and appending it to a list, but it seems to become a tuple instead of a pygame rectangle when I try to change the y of it, can someone help with that as well?
import pygame, sys, random
from pygame.locals import *
#Imports pygame, system and random as modules to use later in the code.
#Also imports extra stuff from pygame that contains useful variables.
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
#Initialises pygame, sets up the clock to stop the program running too fast
#And also makes the font (must happen after pygame initialises)
WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite
def terminate():
pygame.quit()
sys.exit()
def pendingKey():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
return
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOUR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
#Defining functions, to quit pygame and the system.
#And to wait for the escape key to be pressed to start the terminate function.
#And to wait for the quit event (such as at the end of the game).
#And a function to create text on the screen, such as for the title.
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
#Creates the games window, sets the name of the window, and makes the mouse invisible
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
pendingKey()
#Sets the colour of the background and draws the title and some basic instructions
#And updates the display and activates the terminate function
while True:
LEFT = RIGHT = UP = DOWN = SHOOT = LEFTROTATE = RIGHTROTATE = False
#Sets the players start position to half through the screen, and 50 pixels down
#And sets the movement variables to false
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
#Checks for events, first event being the game quitting
if event.type == KEYDOWN:
if event.key == K_LEFT:
RIGHT = False
LEFT = True
if event.key == K_RIGHT:
LEFT = False
RIGHT = True
if event.key == K_UP:
DOWN = False
UP = True
if event.key == K_DOWN:
UP = False
DOWN = True
if event.key == K_SPACE:
SHOOT = True
if event.key == K_a:
RIGHTROTATE = False
LEFTROTATE = True
if event.key == K_d:
LEFTROTATE = False
RIGHTROTATE = True
#Checks for keys being pressed, corresponding to movement.
if event.key == K_ESCAPE:
terminate()
#Checks for escape being pressed, which quits the game.
if event.type == KEYUP:
if event.key == K_ESCAPE:
terminate()
if event.key == K_LEFT:
LEFT = False
if event.key == K_RIGHT:
RIGHT = False
if event.key == K_UP:
UP = False
if event.key == K_DOWN:
DOWN = False
if event.key == K_SPACE:
SHOOT = False
if event.key == K_a:
RIGHTROTATE = False
LEFTROTATE = False
if event.key == K_d:
LEFTROTATE = False
RIGHTROTATE = False
#Checks whether keys have been let go of.
if LEFT and PLAYERRECT.left > 0:
PLAYERRECT.move_ip(-1 * PLAYERSPEED, 0)
if RIGHT and PLAYERRECT.right < WINDOWWIDTH:
PLAYERRECT.move_ip(PLAYERSPEED, 0)
if UP and PLAYERRECT.top > 0:
PLAYERRECT.move_ip(0, -1 * PLAYERSPEED)
if DOWN and PLAYERRECT.bottom < WINDOWHEIGHT:
PLAYERRECT.move_ip(0, PLAYERSPEED)
if SHOOT:
ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
if LEFTROTATE:
PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, 90)
PLAYERRECT = PLAYERIMAGE.get_rect()
if RIGHTROTATE:
PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, -90)
PLAYERRECT = PLAYERIMAGE.get_rect()
for asteroid in ASTEROIDS:
asteroid.y -= 4
for asteroid in ASTEROIDS:
WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
#Moves the player a certain number of pixels in a direction and shoots asteroids
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
WINDOWSURFACE.blit(PLAYERIMAGE, PLAYERRECT)
pygame.display.update()
mainClock.tick(FPS)
#Fills the background, draws the players image on the rectangle
#And updates the screen and selects how many frames per second the game should tick by
Thanks in advance
Note that you should only call pygame.event.get() once in your application.
When you rotate, you set your player rect as such:
PLAYERRECT = PLAYERIMAGE.get_rect()
You have never specified the value of PLAYERIMAGE.get_rect() and it is (0, 0) by default, so if the player is transported to the top left of the screen. To fix that, simply remove it, it serves no purpose.
Also, your movement code can be simplified.
keys = pygame.key.get_pressed()
PLAYERRECT.move_ip
(
(keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED,
(keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED
)
Thats it.
Code to handle rotation can be simplified as well. Make a function that gets the players rotation angle:
def getPlayerRotation(keys):
if keys[K_a]: return 90
elif keys[K_d]: return -90
return 0
Then use that to rotate your image and draw it.
#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
WINDOWSURFACE.blit(rotated_image, new_rect)
Your asteroid isn't drawing because you are trying to draw it before you clear the screen, which draws over the asteroids.
Also you cannot do
ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
because there is only one asteroid.rect object, so what you are appending is a reference to the same object over and over. You need to create a new rect if your want to use a rect, but I got around the problem by using a list.
ASTEROIDS.append(list(PLAYERRECT.center))
and then later:
for asteroid in ASTEROIDS:
asteroid[1] -= 4
Lastly I changed pending key function:
def pendingKey(events):
for event in events:
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
It takes events as argument to avoid calling pygame.event.get() in the function. I also removed the return statement at the end of it since it was causing the function to exit before it got to to through all the events.
Here is the new code:
import pygame, sys, random
from pygame.locals import *
WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite
def terminate():
pygame.quit()
sys.exit()
def pendingKey(events):
for event in events:
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOUR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
def getPlayerRotation(keys):
if keys[K_a]: return 90
elif keys[K_d]: return -90
return 0
while True:
events = pygame.event.get()
pendingKey(events)
keys = pygame.key.get_pressed()
PLAYERRECT.move_ip((keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED, (keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED)
#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
for event in events:
if event.type == KEYDOWN and event.key == K_SPACE:
ASTEROIDS.append(list(PLAYERRECT.center))
for asteroid in ASTEROIDS:
asteroid[1] -= 4
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
WINDOWSURFACE.blit(rotated_image, new_rect)
for asteroid in ASTEROIDS:
WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
pygame.display.update()
mainClock.tick(FPS)

Pygame: Click event is affecting every sprite to the left of them

I have an array with all the sprites inside of them, and in the loop, if the sprite is clicked then the sprite is killed.
If I click the sprites from left to right, everything is fine. They are cleared one by one independent of each other. But, if I click the sprite most right of the screen, it kills everything to the left of it.
Full code because I've no idea where the important region might be.
import pygame
from pygame.locals import *
import random
pygame.init()
level = 1
cooldown = 1000
class test(pygame.sprite.Sprite):
def __init__(self, w):
super().__init__()
self.image = pygame.Surface([600,600])
self.rect = self.image.get_rect()
self.image = pygame.image.load("index.png")
self.image = pygame.transform.scale(self.image, (w,w))
self.last = pygame.time.get_ticks()
screen = pygame.display.set_mode([600,600])
clock = pygame.time.Clock()
background = pygame.Surface(screen.get_size())
background.fill([0,0,0])
rX = random.randint(0, 500)
rX2 = random.randint(0, 500)
screen.blit(background, (0,0))
sp = []
all_sprites_list = pygame.sprite.Group()
a_1 = test(random.randint(40,60))
a_1.rect.x = rX
a_1.rect.y = -400
sp.append(a_1)
all_sprites_list.add(a_1)
#The steps for a_1 is repeated to make variables a_2, a_3, a_4...
Running = True
while Running:
now = pygame.time.get_ticks()
for x in sp:
x.rect.y+=level
m_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == QUIT:
Running = False
if event.type == MOUSEBUTTONDOWN:
for s in sp:
if s.rect.collidepoint(m_pos):
s.kill()
pygame.display.flip()
all_sprites_list.clear(screen, background)
all_sprites_list.draw(screen)
all_sprites_list.update()
clock.tick(60)
Problem is because in class you create Surface with size (600, 600) and you assign this size to self.rect. After that you load image but you forgot to assign its size to self.rect so program always check mouse click with size (600, 600) and when you click most right item then all rect (600, 600) are in area of click.
But you don't have to create Surface if you load image.
My version with many changes.
I removed list sp because I can use all_sprites_list
When it sends MOUSEBUTTONDOWN event then mouse position is in event.pos so I don't need pygame.mouse.get_pos()
import pygame
import random
# --- classes --- (UpperCaseNames)
class Test(pygame.sprite.Sprite):
def __init__(self, w):
super().__init__()
self.image = pygame.image.load("index.png")
self.image = pygame.transform.scale(self.image, (w, w))
self.rect = self.image.get_rect()
self.last = pygame.time.get_ticks()
# --- main ----
level = 1
cooldown = 1000
# - init -
pygame.init()
screen = pygame.display.set_mode((600, 600))
# - items -
background = pygame.Surface(screen.get_size())
background.fill((0, 0, 0))
screen.blit(background, (0,0))
all_sprites_list = pygame.sprite.Group()
for x in range(10):
item = Test(random.randint(40, 60))
item.rect.x = 40 * random.randint(0, 10)
item.rect.y = 0
all_sprites_list.add(item)
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
now = pygame.time.get_ticks()
for item in all_sprites_list:
item.rect.y += level
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
for item in all_sprites_list:
if item.rect.collidepoint(event.pos):
item.kill()
pygame.display.flip()
all_sprites_list.clear(screen, background)
all_sprites_list.draw(screen)
all_sprites_list.update()
clock.tick(30)
pygame.quit()

What is the simplest way to rotate a pygame sprite on holding a button?

I currently have a racecar game in development, using Pygame. I understand that in order to get the sprite to move the way a real car does, trigonometry is required. However, for now, I am simply trying to get the racecar image to rotate as the user holds a button. What is the simplest way to do so?
import pygame
pygame.init()
#DEFING COLOURS
BLACK = ( 0, 0, 0)
WHITE = ( 255, 255, 255)
BLUE = (0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
size = (800,600)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("My First Game")
class Car(pygame.sprite.Sprite):
#BASE CAR CLASS
def __init__(self, filename):
#INITIALISE OBJECT PROPERTIES
super().__init__()
#LOAD IMAGE
self.image = pygame.image.load(filename).convert_alpha()
#SET BACKGROUND COLOUR
#self.image.set_colorkey(WHITE)
#SET RECTANGLE COLLISION BOX
self.rect = self.image.get_rect()
self.angle = 0
self.angle_change = 0
#Create sprites list
all_sprites_list = pygame.sprite.Group()
#Create F1car object
F1car = Car("car.png")
car_rotation = 0.0
surface = pygame.Surface((15, 15))
#Add F1car to sprites list
all_sprites_list.add(F1car)
#LOOP UNTIL USER EXITS THE GAME
carryOn = True
#CLOCK TO CONTROL FRAME RATE
clock = pygame.time.Clock()
##MAIN LOOP##
while carryOn:
#MAIN EVENT LOOP
for event in pygame.event.get(): #USER DID SOMETHING
if event.type == pygame.QUIT: #IF USER CLICKED CLOSE
carryOn = False #END THE LOOP
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
car_rotation += 0.1
pygame.transform.rotate(surface, car_rotation)
#GAME LOGIC
#DRAWING CODE
#CLEARING SCREEN
screen.fill(WHITE)
#DRAWING SHAPES
pygame.draw.rect(screen, RED, [55, 200, 100, 70], 0)
pygame.draw.rect(screen, BLUE, [78, 300, 60, 70], 0)
#LIST OF SPRITES TO COLLIDE WITH EACHOTHER
#blocks_hit_list = pygame.sprite.spritecollide(F1car, )
#DRAW SPRITES FROM all_sprites_list LIST
all_sprites_list.draw(screen)
#UPDATE THE SCREEN
pygame.display.flip()
#SET UPDATE RATE
clock.tick(60)
pygame.quit()
I'd give the Car class an update method and in this method rotate the car if self.angle_change is not 0. That allows you to call all_sprites.update() to call the update methods of all contained sprites.
Set the angle_change in the event loop to start the rotation. In the update method, increase the self.angle by the self.angle_change, then use pygame.transform.rotate or .rotozoom and pass the self.angle. Afterwards you need to get a new rect and pass the center of the old rect as the center argument.
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
WHITE = (255, 255, 255)
CAR_IMAGE = pygame.Surface((45, 90), pygame.SRCALPHA)
CAR_IMAGE.fill((150, 20, 0))
class Car(pygame.sprite.Sprite):
def __init__(self, pos, image):
super().__init__()
self.image = image
# Store a reference to the original to preserve the image quality.
self.orig_image = self.image
self.rect = self.image.get_rect(center=pos)
self.angle = 0
self.angle_change = 0
def update(self):
if self.angle_change != 0:
self.angle += self.angle_change
# I prefer rotozoom because it looks smoother.
self.image = pygame.transform.rotozoom(self.orig_image, self.angle, 1)
self.rect = self.image.get_rect(center=self.rect.center)
all_sprites = pygame.sprite.Group()
f1_car = Car((300, 300), CAR_IMAGE)
all_sprites.add(f1_car)
carryOn = True
while carryOn:
for event in pygame.event.get():
if event.type == pygame.QUIT:
carryOn = False
elif event.type == pygame.KEYDOWN:
# Set the rotation speed of the car sprite.
if event.key == pygame.K_RIGHT:
f1_car.angle_change = -3
elif event.key == pygame.K_LEFT:
f1_car.angle_change = 3
elif event.type == pygame.KEYUP:
# Stop rotating if the player releases the keys.
if event.key == pygame.K_RIGHT and f1_car.angle_change < 0:
f1_car.angle_change = 0
elif event.key == pygame.K_LEFT and f1_car.angle_change > 0:
f1_car.angle_change = 0
all_sprites.update()
screen.fill(WHITE)
all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
This can be done rather simply. You need a game loop that checks for inputs. Then you must check that the desired input is present, and increase the rotation of your car each time the input is present.
import pygame
run = True
car_rotation = 0.0
surface = pygame.Surface((100, 60)) # 100 horizontal length. 60 is the vertical length.
while run:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
car_rotation += 0.1
surface = pygame.transform.rotate(surface, car_rotation)
For the case of your code
You have done some wrong checks in the loop. Change your code from pygame.K_RIGHT to pygame.K_r, to use your R key to rotate your sprite. In order to use the mouse, change the pygame.event.type to .MOUSEBUTTONDOWN or .MOUSEBUTTONUP, and keep pygame.K_RIGHT.
Change the if statement, if event.key == pygame.K_r, to
if event.key == pygame.K_r
car_rotation += 1.0
for car in all_sprites_list:
car.image = pygame.transform.rotate(car.image, car_rotation)
and then remove surface = pygame.Surface((15, 15)).

Categories