This question already has answers here:
Pygame mouse clicking detection
(4 answers)
How do I add a border to a sprite when the mouse hovers over it, and delete it after the mouse stops?
(1 answer)
Closed 5 months ago.
So im trying to remake a simple card game in pygame. Im trying to make it where whenever you hover over a card it will turn slightly transparent by changing the alpha of the card.
However I can't seem to get this to work and im genuinely confucious as to why my code doesnt work.
while running:
mX, mY = pygame.mouse.get_pos()
if 50 + 60 > mX > 50 and 500 + 84 > mY > 500:
hand[0].set_alpha(100)
else:
hand[0].set_alpha(255)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#Hover()
if printHand:
#print(hand)
#print(cardSize)
#print(hand[0].get_width())
#print(hand[0].get_height())
#print(hand[0].get_rect(center=(80, 542)))
printHand = False
if displayHand:
DisplayHand(hand)
DisplayBoard(pile1)
DisplayBoard(pile2)
displayHand = False
print(50 + 60 > mX > 50 and 500 + 84 > mY > 500)
pygame.display.update()
Where hand is an array of surfaces from image.load
As of right now this code doesnt do anything but the print statement at the end returns true
Here is a minimal example that creates a Card sprite with two images, swapping the image if the mouse is over the card.
import pygame
WIDTH = 640
HEIGHT = 480
FPS = 30
class Card(pygame.sprite.Sprite):
"""A playing card like sprite"""
def __init__(self, color="white", pos=(0, 0)):
pygame.sprite.Sprite.__init__(self)
self.color = pygame.Color(color)
# if you're loading an image, make sure to use .convert()
self.orig_image = pygame.Surface((50, 100), pygame.SRCALPHA)
self.orig_image.fill(self.color)
# create a copy of the image
self.alt_image = self.orig_image.copy()
self.alt_image.set_alpha(127) # make the copy transparent
self.image = self.orig_image
self.rect = self.image.get_rect(center=pos)
def update(self):
if self.rect.collidepoint(pygame.mouse.get_pos()):
self.image = self.alt_image
else:
self.image = self.orig_image
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
cards = pygame.sprite.Group()
# create five cards distributed across the bottom of the screen
for x in range(5):
card = Card(pos=((x + 1) * (WIDTH // 6), HEIGHT - 90))
cards.add(card)
pygame.display.set_caption("♠♣♥♦ Cards")
paused = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYUP:
pass
# update game elements
cards.update()
# draw surface - fill background
window.fill("black")
## draw sprites
cards.draw(window)
# show surface
pygame.display.update()
# limit frames
clock.tick(FPS)
pygame.quit()
This will look like this, although the screenshot doesn't include the mouse cursor:
Related
This question already has answers here:
Spawning multiple instances of the same object concurrently in python
(1 answer)
How to wait some time in pygame?
(3 answers)
Is there a way to have different tick rates for differents parts of my code in pygame?
(1 answer)
How to run multiple while loops at a time in Pygame
(1 answer)
Closed 6 months ago.
I have a list of images that I want pygame to draw in two rows, one by one, with a one second delay between them. The code I wrote is this:
import pygame
def main():
FPS = 60
clock = pygame.time.Clock()
clock.tick(FPS)
delay = 50
WIN = pygame.display.set_mode((500, 500))
WIN.fill((0,0,0))
pygame.display.update()
pygame.time.delay(delay)
run = True
while run:
# positions of the first two images to be drawn
x1, y1 = 20, 20
x2, y2 = 20, 300
i = 0
for _ in range(len(IMAGES)):
if i >= len(IMAGES):
break
image = IMAGES[i]
WIN.blit(image, (x1, y1))
pygame.display.update()
pygame.time.delay(delay)
i += 1
if i >= len(IMAGES):
break
image = IMAGES[i]
WIN.blit(image, (x2, y2))
pygame.display.update()
pygame.time.delay(delay)
i += 1
x1 += 10
x2 += 10
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
main()
The program crashes if I set the delay higher than 50 milliseconds. After some research here on StackOverflow, I found out that pygame.time.delay and pygame.time.wait can't be used in my case. However, the numerous workarounds suggested here are too complicated for me, as I'm only a beginner.
Is there a simple, straightforward way to make my program to work properly?
Thanks!
The best way to do this is through custom events, you add another image every time you receive an event. That way the rest of the event handling can take place and the operating system won't think your application is no longer responding.
Here's a minimal example, it doesn't limit the number of squares, although your can either skip the image creation in the event handler, or call set_timer(…) with a loops keyword argument to specify the number or events to be generated.
import pygame
import itertools
CUSTOM_TIMER_EVENT = pygame.USEREVENT + 1
my_colors = ["red", "orange", "yellow", "green", "blue", "purple"]
# create an iterator that will repeat these colours forever
color_cycler = itertools.cycle([pygame.color.Color(c) for c in my_colors])
pygame.init()
pygame.font.init()
clock = pygame.time.Clock()
width, height = 320, 240
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Timer Rows")
squares = []
done = False
x, y = 20, 20 # initial position
pygame.time.set_timer(CUSTOM_TIMER_EVENT, 100) # tenth of a second
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == CUSTOM_TIMER_EVENT:
image = pygame.Surface((8, 8))
image.fill(next(color_cycler))
squares.append((image, (x, y)))
x += 10
if x > (width - 20): # next row
x = 20
y += 20
# Graphics
screen.fill(pygame.Color("black"))
# Draw squares
for image, pos in squares:
screen.blit(image, pos)
# Update Screen
pygame.display.update()
clock.tick(30)
pygame.quit()
The timer is set to 100 ms instead of a second due to my own impatience.
But suppose you want to do something with your newly created squares. Instead of creating everything from scratch because it seems easier than reading documentation, I would encourage you to use sprites.
Defining our Sprite:
class Square(pygame.sprite.Sprite):
def __init__(self, size, pos, color):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface([size[0], size[1]])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = pos[0] # sprite tracks its position
self.rect.y = pos[1]
Instead of a list, squares is a sprite group:
squares = pygame.sprite.Group()
The event handler changes to create a sprite and add it to the group instead of creating an image and adding it the list:
elif event.type == CUSTOM_TIMER_EVENT:
square = Square((8,8), (x,y), next(color_cycler))
squares.add(square)
But we want to do things with the sprite, so we can use its update function to check if the mouse is over it, and if so, destroy the sprite:
def update(self):
if self.rect.collidepoint(pygame.mouse.get_pos()):
self.kill()
This will look something like:
Here's the full code listing:
import pygame
import itertools
class Square(pygame.sprite.Sprite):
def __init__(self, size, pos, color):
pygame.sprite.Sprite.__init__(self)
self.size = size
self.image = pygame.Surface([size[0], size[1]])
self.image.fill(color)
self.rect = self.image.get_rect()
self.rect.x = pos[0]
self.rect.y = pos[1]
def update(self):
if self.rect.collidepoint(pygame.mouse.get_pos()):
self.kill()
CUSTOM_TIMER_EVENT = pygame.USEREVENT + 1
my_colors = ["red", "orange", "yellow", "green", "blue", "purple"]
# create an iterator that will repeat these colours forever
color_cycler = itertools.cycle([pygame.color.Color(c) for c in my_colors])
pygame.init()
pygame.font.init()
clock = pygame.time.Clock()
width, height = 320, 240
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption("Timer Sprite Rows")
squares = pygame.sprite.Group()
done = False
x, y = 20, 20 # initial position
pygame.time.set_timer(CUSTOM_TIMER_EVENT, 100) # tenth of a second
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == CUSTOM_TIMER_EVENT:
square = Square((8,8), (x,y), next(color_cycler))
squares.add(square)
x += 10
if x > (width - 20): # next row
x = 20
y += 20
# Graphics
screen.fill(pygame.Color("black"))
# Update Sprites
squares.update()
# Draw Sprites
squares.draw(screen)
# Update Screen
pygame.display.update()
clock.tick(30)
pygame.quit()
This question already has answers here:
Setting up an invisible boundary for my sprite
(1 answer)
Use vector2 in pygame. Collide with the window frame and restrict the ball to the rectangular area
(1 answer)
How to make ball bounce off wall with PyGame?
(1 answer)
Not letting the character move out of the window
(2 answers)
Closed 10 months ago.
I just started trying out pygame, so I watched a tutorial. When the guy showed, how to create edges left and right from the screen, it just didn't work when I did it, even though I've written it 100% equal as the tutorial guy. The tutorial is already two years old, so maybe pygame just has changed. Can somebody help me?
That's my code:
import pygame
import sys
pygame.init()
background = pygame.image.load("C:\Programmieren\Python\Grafiken\pygame test1 - background.png")
screen = pygame.display.set_mode([1200,595])
clock = pygame.time.Clock()
pygame.display.set_caption("pygame test1")
def draw():
screen.blit(background, (0, 0))
pygame.draw.rect(screen, (0, 0, 255), (x, y, width, height))
pygame.display.update()
x = 300
y = 300
speed = 3
width = 40
height = 80
left_wall = pygame.draw.rect(screen, (0,0,0), (-2,0,2,600), 0)
right_wall = pygame.draw.rect(screen, (0,0,0), (1201,0,2,600), 0)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
character = pygame.Rect(x,y,width, height)
pressed = pygame.key.get_pressed()
if presses[pygame.K_UP] or pressed[pygame.K_w] or pressed[pygame.K_SPACE]:
y -= speed
if pressed[pygame.K_RIGHT] or pressed[pygame.K_d] and not character.colliderect(right_wall):
x += speed
if pressed[pygame.K_DOWN] or pressed[pygame.K_s]:
y += speed
if pressed[pygame.K_LEFT] or pressed[pygame.K_a] and not character.colliderect(left_wall):
x -= speed
draw()
clock.tick(60)
The following code works for me after replacing the background.png path with a picture that exists on my computer. I changed left_wall and right_wall to call pygame.Rect instead of pygame.draw.rect and copied the draw.rect calls that were previously assigned to left_wall and right_wall to draw() function, and added some needed parentheses in two of the if statements. Also fixed a typo where pressed was spelled presses.
Without the parentheses, the character would always move right when right key is pressed even past the right edge of the window. When "d" is pressed, it would check against colliderect. Same for left arrow and "a" keys. or short-circuits, so if K_RIGHT or K_LEFT is pressed, it doesn't check the right hand side of the or in the if statements. With the parentheses added, the "move right" if statement always checks colliderect when K_RIGHT or K_d is pressed, instead of only when K_d is pressed.
import pygame
import sys
pygame.init()
background = pygame.image.load("C:\Programmieren\Python\Grafiken\pygame test1 - background.png")
screen = pygame.display.set_mode([1200,595])
clock = pygame.time.Clock()
pygame.display.set_caption("pygame test1")
def draw():
screen.blit(background, (0, 0))
pygame.draw.rect(screen, (0, 0, 255), (x, y, width, height))
pygame.draw.rect(screen, (0,0,0), left_wall, 0)
pygame.draw.rect(screen, (0,0,0), right_wall, 0)
pygame.display.update()
x = 300
y = 300
speed = 3
width = 40
height = 80
left_wall = pygame.Rect(-2,0,2,600)
right_wall = pygame.Rect(1201,0,2,600)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
character = pygame.Rect(x,y,width, height)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP] or pressed[pygame.K_w] or pressed[pygame.K_SPACE]:
y -= speed
if (pressed[pygame.K_RIGHT] or pressed[pygame.K_d]) and not character.colliderect(right_wall):
x += speed
if pressed[pygame.K_DOWN] or pressed[pygame.K_s]:
y += speed
if (pressed[pygame.K_LEFT] or pressed[pygame.K_a]) and not character.colliderect(left_wall):
x -= speed
draw()
clock.tick(60)
This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 1 year ago.
import pygame
import os
pygame.font.init()
pygame.mixer.init()
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("HELP ME")
WHITE = (255, 255, 255)
black = (0, 0, 0)
MENU_bg = pygame.transform.scale(pygame.image.load(os.path.join("menu.png")), (WIDTH, HEIGHT))
quiting = 0
def main_menu():
running = True
quiting = 0
clock = pygame.time.Clock()
FPS = 60
WIN.blit(MENU_bg, (0, 0))
while running:
clock.tick(FPS)
if quiting == 1:
exit()
WIN.blit(MENU_bg, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
quiting = 1
if event.type == pygame.MOUSEBUTTONUP:
mouse_pos = pygame.mouse.get_pos()
print(mouse_pos)
if mouse_pos[0] >= 0 and mouse_pos[0] <= 450 and mouse_pos[1] >= 200 and mouse_pos[1] <= 500:
running = False
# Here I will link to another function
I get no error messages when running the code, but the images don´t show up. The image files are available and their right names have been used. I have read several tutorials and don´t see what I´ve done wrong.
You need to update the display.
You are actually drawing on a Surface object. If you draw on the Surface associated to the PyGame display, this is not immediately visible in the display. The changes become visibel, when the display is updated with either pygame.display.update() or pygame.display.flip():
def main_menu():
# [...]
while running:
clock.tick(FPS)
if quiting == 1:
exit()
WIN.blit(MENU_bg, (0, 0))
# [...]
pygame.display.flip()
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.
So my ball animation for my multiplayer pong game is broken. Instead of moving and bouncing normally, the ball draws it self again after moving.
How do i fix the ball to not like clone itself after it moves 5 pixels? This is the animation code:
enter code here
import pygame
pygame.init()
#Creating the window
screen_width, screen_height = 1000, 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Pong")
#FPS
FPS = 60
clock = pygame.time.Clock()
#Game Variables
light_grey = (170,170,170)
#Paddles
paddle_1 = pygame.Rect(screen_width - 30, screen_height/2 - 70, 20,100)
paddle_2 = pygame.Rect(10, screen_height/2 - 70, 20, 100)
#Ball
ball = pygame.Rect(screen_width/2, screen_height/2, 30, 30)
ball_xVel = 5
ball_yVel = 5
def ball_animation():
global ball_xVel, ball_yVel
ball.x += ball_xVel
ball.y += ball_yVel
if ball.x > screen_width or ball.x < 0:
ball_xVel *= -1
if ball.y > screen_height or ball.y < 0:
ball_yVel *= -1
def draw():
pygame.draw.ellipse(screen, light_grey, ball)
pygame.draw.rect(screen, light_grey, paddle_1)
pygame.draw.rect(screen, light_grey, paddle_2)
def main():
#main game loop
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
draw()
ball_animation()
pygame.display.update()
clock.tick(FPS)
pygame.quit()
if __name__ == "__main__":
main()
You have to clear the display in every frame with pygame.Surface.fill:
screen.fill(0)
The typical PyGame application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()
limit frames per second to limit CPU usage with pygame.time.Clock.tick
def main():
# main application loop
run = True
while run:
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# update and move objects
ball_animation()
# clear the display
screen.fill(0)
# draw the scene
draw()
# update the display
pygame.display.update()
# limit frames per second
clock.tick(FPS)
pygame.quit()
exit()
This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
I have this code:
plaxer = 20
player = 300
vel = 5
res = (720,720)
thistle = (216,191,216)
plum = (221,160,221)
screen = pygame.display.set_mode(res)
color = (255,255,255)
color_light = (255,0,0)
color_dark = (200,0,0)
red = (128, 0, 128)
reder = (31,0,31)
width = screen.get_width()
height = screen.get_height()
smallfont = pygame.font.SysFont('Corbel',35)
text = smallfont.render('Exit ' , True , color)
small = pygame.font.SysFont('Corbel',22)
texta = small.render('Customise Avatar ' , True , color)
screen.fill((0,0,255))
img1 = pygame.image.load("C:\\Users\\Path\\To\\Brown.png")
screen.blit(img1,(plaxer, player))
runs = True
while runs:
mouse = pygame.mouse.get_pos()
for ev in pygame.event.get():
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
plaxer =+ 0
screen.fill((0,0,255))
screen.blit(img1, (plaxer, player))
The problem is that the sprite doesn't move properly - it moves too robotically. How do I fix this?
You have to draw the player and update the display in the application loop:
while runs:
mouse = pygame.mouse.get_pos()
for ev in pygame.event.get():
if ev.type == pygame.QUIT:
runs = False
keys = pygame.key.get_pressed()
if keys[pygame.K_a]:
plaxer += 1
screen.fill((0,0,255))
screen.blit(img1, (plaxer, player))
pygame.display.update()
The typical PyGame application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()