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")
Related
I learned how to print image in pygame, but I don't know how to make a dynamic position(It can change the image position by itself). What did I miss? Here's my attempt.
import pygame
screen_size = [360,600]
screen = pygame.display.set_mode(screen_size)
background = pygame.image.load("rocketship.png")
keep_alive = True
while keep_alive:
planet_x = 140
o = planet_x
move_direction = 'right'
if move_direction == 'right':
while planet_x == 140 and planet_x < 300:
planet_x = planet_x + 5
if planet_x == 300:
planet_x = planet_x - 5
while planet_x == 0:
if planet_x == 0:
planet_x+=5
screen.blit(background, [planet_x, 950])
pygame.display.update()
You don't need nested loops to animate objects. You have one loop, the application loop. Use it! You need to redraw the entire scene in each frame. Change the position of the object slightly in each frame. Since the object is drawn at a different position in each frame, the object appears to move smoothly.
Define the path the object should move along by a list of points and move the object from one point to another.
Minimal example
import pygame
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
corner_points = [(100, 100), (300, 300), (300, 100), (100, 300)]
pos = corner_points[0]
speed = 2
def move(pos, speed, points):
direction = pygame.math.Vector2(points[0]) - pos
if direction.length() <= speed:
pos = points[0]
points.append(points[0])
points.pop(0)
else:
direction.scale_to_length(speed)
new_pos = pygame.math.Vector2(pos) + direction
pos = (new_pos.x, new_pos.y)
return pos
image = pygame.image.load('bird.png').convert_alpha()
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pos = move(pos, speed, corner_points)
image_rect = image.get_rect(center = pos)
window.fill(0)
pygame.draw.lines(window, "gray", True, corner_points)
window.blit(image, image_rect)
pygame.display.update()
pygame.quit()
exit()
This question already has an answer here:
How can I move the ball instead of leaving a trail all over the screen in pygame?
(1 answer)
Closed 1 year ago.
I am trying to make blocks fall to fall to the ground, but sadly the old sprites won't disappear. I have tried to move sprites with .move_ip, but then I get an error message, saying that my rect doesn't have attribute 'move_ip'. Also a little bit non-related, but how do I make the blocks stack on top of eachother? I suppose it's something to do with worldy?
import pygame
import random
pygame.init()
WHITE = (255, 255, 255)
worldx = 590
worldy = 770
screen = pygame.display.set_mode([worldx, worldy])
screen.fill([0,0,0])
gravity = 1
class Block1(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.image = pygame.image.load("img_12.png")
self.rect = self.image.get_rect(topleft = (x,y))
self.x = x
self.y = y
self.speed_y = 0
def update(self):
self.speed_y += gravity
self.y += self.speed_y
self.rect.y = self.y
if self.rect.y >= worldy:
self.speed_y = 0
x = 0
y = 1
dt = 0
timer = 1
all_sprites_list = pygame.sprite.Group()
stopped_blocks = pygame.sprite.Group()
clock = pygame.time.Clock()
score = 0
block = Block1
mäng_töötab = True
while mäng_töötab:
for event in pygame.event.get():
if event.type == pygame.QUIT:
mäng_töötab = False
timer -= dt
if timer <= 0:
x = random.randrange(0, 18) * 32
all_sprites_list.add(block(x,y))
timer = 1
all_sprites_list.draw(screen)
all_sprites_list.update()
pygame.display.flip()
dt = clock.tick(60) / 1000
pygame.quit()
You have to clear the display in every frame:
while mäng_töötab:
for event in pygame.event.get():
if event.type == pygame.QUIT:
mäng_töötab = False
timer -= dt
if timer <= 0:
x = random.randrange(0, 18) * 32
all_sprites_list.add(block(x,y))
timer = 1
screen.fill(0) # <---
all_sprites_list.draw(screen)
all_sprites_list.update()
pygame.display.flip()
dt = clock.tick(60) / 1000
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
I am trying to make a simple moving game with Pygame since I am currently learning it. Whenever i try to run the code I keep on getting a problem saying: "pygame.error: display Surface quit"
I've tried adding "break" at the end but the window closes immediately! I've tried searching for the solution but I can't find one that helps my code.
import pygame
import random
pygame.init()
# Window setup
size = [400, 400]
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
# player position
x = size[0] // 2
y = size[1] // 2
# ball position
ballX = random.randrange(0, size[0])
ballY = random.randrange(0, size[1])
# colours
red = pygame.color.Color('#FF8080')
blue = pygame.color.Color('#8080FF')
white = pygame.color.Color('#FFFFFF')
black = pygame.color.Color('#000000')
def CheckOffScreenX(x):
if x > size[0]:
x = 0
elif x < 0:
x = size[0]
return x
def CheckOffScreenY(y):
if y > size[1]:
y = 0
elif y < 0:
y = size[1]
return y
# Game loop
done = False
while not done:
screen.fill(black)
keys = pygame.key.get_pressed()
#player movement
if keys[pygame.K_w]:
y -=1
if keys[pygame.K_s]:
y +=1
if keys[pygame.K_a]:
x -=1
if keys[pygame.K_d]:
x +=1
# Check offscreen
x = CheckOffScreenX(x)
y = CheckOffScreenY(y)
# draw player
pygame.draw.circle(screen, red, [x, y], 6)
pygame.display.flip()
# draw ball
pygame.draw.circle(screen, blue, [ballX, ballY], 6)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
clock.tick(32)
pygame.quit()
Any help would be appreciated!
The issue is the pygame.quit() insider the main loop. pygame.quit() uninitialize all pygame modules. After the modules are uninitialized all further calls to pygyme instructions (in the next frame) will cause a crash.
Do pygame.quit() after the main loop, when the application has end.
done = False
while not done:
screen.fill(black)
# [...]
# pygame.quit() <----- delete
pygame.quit() # <---- add
Note, probably you've added an Indentation when you copied the code.
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()
A section of jetfighterx leaves the screen when the mouse hovers over the edge of the window, this causes tarantula to explode from time to time as soon as it respawns to the top of the window, how can I stop this from happening (without the use of classes)?
Code:
import pygame, sys, pygame.mixer
from pygame.locals import *
import random
pygame.init()
bif = "space.jpg"
jf = "spacefightersprite.png"
enemy = "TarantulaSpaceFighter.png"
laser = pygame.mixer.Sound("LaserBlast.wav")
explosionsound = pygame.mixer.Sound("Explosion.wav")
screen = pygame.display.set_mode((1000,900),0,32)
caption = pygame.display.set_caption("Jet Fighter X")
background = pygame.image.load(bif).convert()
jetfighterx = pygame.image.load(jf)
jetfighterx = pygame.transform.scale(jetfighterx, (400,400))
tarantula = pygame.image.load(enemy)
tarantula = pygame.transform.scale(tarantula, (100,100))
laserblast = pygame.image.load("C:\Python27\laser.png")
explosion=pygame.image.load("C:\Python27\explosion.png")
explosion=pygame.transform.scale(explosion, (150,150))
ex,ey = 450,0
movex,movey = 0,0
clock = pygame.time.Clock()
speed = 300
shoot_y = 0
laser_fired = False
collision = False
alive = True
explo_timer = 25
while True:
pygame.mouse.set_visible(False)
mx,my = pygame.mouse.get_pos()
jetfighterx_rect = jetfighterx.get_rect(center=(mx, my))
jetfighterx_rect = jetfighterx_rect.inflate(-200,-200)
tarantula_rect = tarantula.get_rect(center=(ex, ey))
tarantula_rect = tarantula_rect.inflate(-180,-200)
# Check for player inputs
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE or event.key == K_q:
sys.exit()
if event.type == MOUSEBUTTONDOWN:
laser_fired = True
laser.play()
shoot_y = my-200
shoot_x = mx-16
# Update Game
milli = clock.tick()
seconds = milli/1000.
dmy = seconds * speed
ey += dmy
if ey > 900:
explo_timer = 25
collision = False
alive = True
ey = 0
ex = random.randint(50,900)
if laser_fired:
shoot_y -= 10
if shoot_y < 0:
laser_fired = False
else:
laserblast_rect = laserblast.get_rect(center=(shoot_x, shoot_y))
if laserblast_rect.colliderect(tarantula_rect):
explosionsound.play()
collision = True
alive = False
if jetfighterx_rect.colliderect(tarantula_rect) and alive:
explosionsound.play()
collision = True
alive = False
# Draw on screen
screen.blit(background, (0,0))
screen.blit(jetfighterx,(mx-200,my-200))
if not collision:
screen.blit(tarantula, (ex, ey))
elif collision:
explo_timer-=2
if explo_timer > 0 and alive == False:
screen.blit(explosion, (ex, ey-50))
if laser_fired:
screen.blit(laserblast, (shoot_x, shoot_y))
pygame.display.update()
Just add a limit that does not allow the fighter to move within x pixels of the border.
Assuming that the x,y coordinates of the centre of your fighter are jetfighter_x, jetfighter_y (You will need to change the variable names to whatever your code has) then write something like this:
LBuffer = 16
RBuffer = 1000 - 16
TBuffer = 900 - 16
BBuffer = 16
if jetfighter_x > RBuffer:
jetfighter_x = RBuffer
if jetfighter_x < LBuffer:
jetfighter_x = LBuffer
if jetfighter_y > TBuffer:
jetfighter_y = TBuffer
if jetfighter_y < BBuffer:
jetfighter_y = BBuffer
This should prevent the center of the ship from getting closer than 16 pixels from the edge. Obviously you will need to tweak this to accommodate the size of your ship. (The buffer for the sides would be the width of the image/2 .Respectively the buffer for the top and bottom would be the height of the image/2).