i have a code that pops up a speechbubble when the player hits a rectangle. But now its just spamming the speech bubble. Thats not good because i have random texts that appears so it's just going through it very fast
this is the code for the speech bubble
def draw_speech_bubble(screen, text, text_color, bg_color, pos, size):
font = pygame.font.SysFont(None, size)
text_surface = font.render(text, True, text_color)
text_rect = text_surface.get_rect(midbottom=pos)
#Background Object
bg_rect = text_rect.copy()
bg_rect.inflate_ip(10,10)
#Border
border_rect = bg_rect.copy()
border_rect.inflate_ip(4,4)
pygame.draw.rect(screen, text_color, border_rect)
pygame.draw.rect(screen, bg_color, bg_rect)
screen.blit(text_surface, text_rect)
This is my code for the collision
if(player.player_rect.colliderect(BarCounter)):
draw_speech_bubble(screen, str(RandomText()), (255, 255, 255), (0, 0,0),SpeechBubbleAnchor.midtop,25)
I want some sort of cooldown so it doesn't spam the speechbubbles. I tried making a calculation with ticks but i wasn't able to do that
Add a variable that stores the text (current_bubble_text) and change the text when the player hits the rectangle. Use pygame.time.get_ticks() to get the number of milliseconds since pygame.init() was called. Calculate the point in time at which the text has to disappear again. When the time comes, reset the variable:
current_bubble_text = None
bubble_text_end_time = 0
#application loop
while True:
current_time = pygame.time.get_ticks()
# [...]
if current_bubble_text == None and player.player_rect.colliderect(BarCounter):
current_bubble_text = RandomText()
bubble_text_end_time = current_time + 5000 # 1 second time interval
if current_bubble_text:
draw_speech_bubble(screen, current_bubble_text,
(255, 255, 255), (0, 0, 0), SpeechBubbleAnchor.midtop, 25)
if current_time > bubble_text_end_time:
current_bubble_text = None
# [...]
See also Adding a particle effect to my clicker game.
Related
I'm following the programarcadegames website to try and move an object along with mouse movement. When I run the program, the coordinates of the moving mouse print out as it goes which is good, but the issue is that the item itself is constantly stuck in its starting position. I've tried making changes and running them to see what went wrong but the same thing keeps happening. Here is my code so far:
import pygame
import random
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GRAY = (128, 128, 128)
pygame.init()
star_list = []
for i in range(50):
x = random.randrange(0, 700)
y = random.randrange(0, 700)
star_list.append([x, y])
# Set the width and height of the screen [width, height]
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Space Game")
# Loop until the user clicks the close button.
done = False
# Draw spaceship
def draw_spaceship(screen, x ,y):
#body
pygame.draw.rect(screen, GRAY, [350,375,20,40], 0)
#wing1 pygame.draw.polygon(screen, BLUE, [[350,375], [330,375], [350,400]], 0)
pygame.draw.polygon(screen, GRAY, [[390,375], [365,375], [365,400]], 0)
#wing2
pygame.draw.polygon(screen, GRAY, [[350,375], [330,375], [350,400]], 0)
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
# --- Main event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
# Game logic
# Mouse movement
pos = pygame.mouse.get_pos()
print (pos)
x=pos[0]
y=pos[1]
# Background
screen.fill(BLACK)
# Process each star in the list
for i in range(len(star_list)):
pygame.draw.circle(screen, WHITE, star_list[i], 2)
star_list[i][1] += 1
if star_list[i][1] > 700:
y = random.randrange(-50, -10)
star_list[i][1] = y
x = random.randrange(0, 700)
star_list[i][0] = x
#call draw_spaceship
draw_spaceship(screen, 0, 0)
# --- Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# --- Limit to 60 frames per second
clock.tick(60)
# Close the window and quit.
pygame.quit()
Your draw_spaceship function draws the ship at a constant position. Draw the ship relative to the x and y coordiante:
def draw_spaceship(screen, x, y):
#body
pygame.draw.rect(screen, GRAY, [x-10, y-20, 20, 40], 0)
#wing1
pygame.draw.polygon(screen, GRAY, [[x+30,y-20], [x+10,y-20], [x+10,y+5]], 0)
#wing2
pygame.draw.polygon(screen, GRAY, [[x-10,y-20], [x-30,y-20], [x-10,y+5]], 0)
Call draw_spaceship with the current mouse position, instead of (0, 0):
while not done:
# [...]
#draw_spaceship(screen, 0, 0)
draw_spaceship(screen, pos[0], pos[1])
draw_spaceship is drawing your ship at a constant position, (0,0). You should change the call for that to something more like
draw_spaceship(screen, pos[0], pos[1])
Edit: It looks like your draw_spaceship() function has hardcoded values for where to draw the spaceship, without even using the x and y arguments given.
So I'm currently making a clicker game, and I already have some pretty good looking stuff. But since I want to polish the game, I would like to add a spinning coin animation to the coin that's in the center of the screen.
I have a coin.py file and this is how it looks like:
import pygame
class Coin():
def __init__(self, screen):
self.screen = screen
self.image = pygame.image.load('pyfiles/images/click_button.png')
self.image_x = 230
self.image_y = 130
self.scale_change_x = 10
self.scale_change_y = 10
def blitme(self):
self.screen.blit(self.image, (self.image_x, self.image_y))
And the current gameplay looks like:
As you can see, when my cursor goes on the coin image, it turns yellow. But now, I want it to not only turn yellow but to spin like this image ( that I found on google ):
What code should I add to my coin.py file to make it do this when my cursor goes on ( collides with ) the coin?
If you have an animated GIF, see Animated sprite from few images.
If you don't have an animated GIF or sprite sheet of a coin, you can achieve a similar effect by squeezing and flipping the coin along the y-axis.
Use pygame.transform.scale() to scale an image and pygame.transform.flip() to flip it. The following code snippet creates a spin effect of a coin Surface that depends on a specific angel:
new_width = round(math.sin(math.radians(angle)) * coin_rect.width)
rot_coin = coin if new_width >= 0 else pygame.transform.flip(coin, True, False)
rot_coin = pygame.transform.scale(rot_coin, (abs(new_width), coin_rect.height))
window.blit(rot_coin, rot_coin.get_rect(center = coin_rect.center))
Minimal example:
import pygame
import math
pygame.init()
window = pygame.display.set_mode((400, 400))
font = pygame.font.SysFont(None, 40)
clock = pygame.time.Clock()
coin = pygame.Surface((160, 160), pygame.SRCALPHA)
pygame.draw.circle(coin, (255, 255, 0), (80, 80), 80, 10)
pygame.draw.circle(coin, (128, 128, 0), (80, 80), 75)
cointext = pygame.font.SysFont(None, 80).render("10", True, (255, 255, 0))
coin.blit(cointext, cointext.get_rect(center = coin.get_rect().center))
coin_rect = coin.get_rect(center = window.get_rect().center)
angle = 0
run = True
while run:
clock.tick(60)
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill(0)
new_width = round(math.sin(math.radians(angle)) * coin_rect.width)
angle += 2
rot_coin = coin if new_width >= 0 else pygame.transform.flip(coin, True, False)
rot_coin = pygame.transform.scale(rot_coin, (abs(new_width), coin_rect.height))
window.blit(rot_coin, rot_coin.get_rect(center = coin_rect.center))
pygame.display.flip()
pygame.quit()
exit()
This question already has an answer here:
Why is my pygame application loop not working properly?
(1 answer)
Closed 2 years ago.
I've been working on a Snake game in python 3.8 with PyGame as a side project. I've got all of the basics down, the only thing I am having trouble with is adding a score tracker.
def main():
global width, rows, s, snack
title()
width = 500
rows = 20
win = pygame.display.set_mode((width, width)) # Creates the screen, sets resolution
s = snake((0,255,0), (10,10)) # Sets snake colour to green and starting position
snack = cube(randomSnack(rows, s), colour=(255,0,0))
score = 0
flag = True
white = (255, 255, 255)
message = score
font = pygame.font.Font('Fonts/PressStart2P-vaV7.ttf', 30)
text = font.render(str(message), True, (255, 255, 255))
win.blit(text, (120,30))
pygame.display.flip()
clock = pygame.time.Clock() # Creates clock object that can change refresh rate
while flag:
pygame.time.delay(50) # Delays by 50 ms, makes it so snake cannot move 10 blocks a second
clock.tick(10) # Sets max refresh rate
s.move()
if s.body[0].position == snack.position:
s.addCube()
score += 1
print(score)
snack = cube(randomSnack(rows, s), colour=(255,0,0)) # Randomizes snack position and sets colour as red
for x in range(len(s.body)):
if s.body[x].position in list(map(lambda z:z.position,s.body[x+1:])): # This checks if you die
print('Score: ', len(s.body))
s.reset((10,10))
break
The score is in the while flag part, It pops up for a brief moment at the start then disappears. Spacing is a bit messed up on the question but the actual code works fine. The score just flashes and goes away
You have to do the drawing in the main application loop. The main application loop continuously redraws the entire scene. The main application loop has to do the following:
handle the events and change game sates dependent on the events and time
clear the display
draw the scene
update the display
Create the initial score Surface before the main application loop. Create a new score Surface when the score has changed. Draw the sore in the main application loop:
def main():
global width, rows, s, snack
title()
width = 500
rows = 20
win = pygame.display.set_mode((width, width)) # Creates the screen, sets resolution
s = snake((0,255,0), (10,10)) # Sets snake colour to green and starting position
snack = cube(randomSnack(rows, s), colour=(255,0,0))
score = 0
flag = True
white = (255, 255, 255)
# create score surface
message = score
font = pygame.font.Font('Fonts/PressStart2P-vaV7.ttf', 30)
text = font.render(str(message), True, (255, 255, 255))
clock = pygame.time.Clock() # Creates clock object that can change refresh rate
while flag:
pygame.time.delay(50) # Delays by 50 ms, makes it so snake cannot move 10 blocks a second
clock.tick(10) # Sets max refresh rate
# handle the events
for event in pygame.event.get():
if event.type == pygame.QUIT:
flag = False
s.move()
if s.body[0].position == snack.position:
s.addCube()
score += 1
# update score surface
message = score
text = font.render(str(message), True, (255, 255, 255))
print(score)
snack = cube(randomSnack(rows, s), colour=(255,0,0)) # Randomizes snack position and sets colour as red
for x in range(len(s.body)):
if s.body[x].position in list(map(lambda z:z.position,s.body[x+1:])): # This checks if you die
print('Score: ', len(s.body))
s.reset((10,10))
break
# clear the display
# [...]
# draw the score
win.blit(text, (120,30))
# draw the snake etc.
# [...]
pygame.display.flip()
Something that looks like this but I want the image and text editable.
Instead of having something like:
title = menuFont.render("COMPUTER INFORMATION!", 1, BLACK)
screen.blit(title, Rect(50, 100, 400, 400))
Is it possible for the colour in the text to be an image instead, or an animation?
EDIT:
For those curious... when I imported the imaged, I had to change the end of the code a bit
screen.blit(texture, (50, 50))
screen.fill(BG_COLOR)
screen.blit(text_surface, (50, 170))
pg.display.update()
clock.tick(30)
The screen.fill comes after the texture... just a heads up :)
To texture your text, you can first render the text in white, then blit the texture onto it and pass pygame.BLEND_RGB_MULT as the special_flags argument to use the multiply blend mode. The texture will appear only on the opaque parts of the text surface.
Also, make sure that your texture is bigger than the text surface, otherwise some parts of the text will remain unaffected.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray32')
FONT = pg.font.Font(None, 50)
# I create a grid texture for demonstration purposes here.
# Just load your image with pygame.image.load instead.
texture = pg.Surface((200, 100))
texture.fill((200, 100, 0))
for x in range(0, 201, 5):
pg.draw.line(texture, (0, 0, 0), (x, 0), (x, 200))
for y in range(0, 101, 5):
pg.draw.line(texture, (0, 0, 0), (0, y), (200, y))
# Render the text and use pure white as the color.
text_surface = FONT.render('Hello world!', True, (255, 255, 255))
# Now blit the texture onto the text surface and pass BLEND_RGB_MULT as
# the special_flags argument, so that only the opaque parts are affected.
text_surface.blit(texture, (0, 0), special_flags=pg.BLEND_RGB_MULT)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
screen.fill(BG_COLOR)
screen.blit(texture, (50, 50))
screen.blit(text_surface, (50, 170))
pg.display.flip()
clock.tick(30)
pg.quit()
Here's the animated version. You have to load the separate frames of the animation and do the same as above for each frame. Put the resulting surfaces into a list and then play them back in the main loop.
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray32')
FONT = pg.font.Font(None, 50)
# I create a grid texture for demonstration purposes here.
# Just load your image with pygame.image.load instead.
texture = pg.Surface((200, 100))
texture.fill((200, 100, 0))
for x in range(0, 201, 5):
pg.draw.line(texture, (0, 0, 0), (x, 0), (x, 200))
for y in range(0, 101, 5):
pg.draw.line(texture, (0, 0, 0), (0, y), (200, y))
# Render the text and use pure white as the color.
text_surface = FONT.render('Hello world!', True, (255, 255, 255))
frames = []
for i in range(5):
surf = text_surface.copy() # We need a fresh copy of the text.
# Now blit the texture onto the text surface and pass BLEND_RGB_MULT as
# the special_flags argument, so that only the opaque parts are affected.
# The y-position is shifted by -1 each iteration.
surf.blit(texture, (0, -1*i), special_flags=pg.BLEND_RGB_MULT)
frames.append(surf)
frame_counter = 0
frame_timer = 0
dt = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
frame_timer += dt # Add the passed time.
if frame_timer >= 150: # If 150 milliseconds have passed...
frame_timer = 0 # Reset the timer.
frame_counter += 1 # Increment the counter.
frame_counter %= len(frames) # Keep it in the correct range.
screen.fill(BG_COLOR)
# Now use `frame_counter` as the list index and blit the surface.
screen.blit(frames[frame_counter], (50, 170))
pg.display.flip()
dt = clock.tick(60) # `dt` is the passed time in milliseconds.
pg.quit()
I'm having trouble with the framerate in my game. I've set it to 60 but it only goes to ~25fps. This was not an issue before displaying the background (was fine with only win.fill(WHITE)). Here is enough of the code to reproduce:
import os, pygame
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (50, 50)
pygame.init()
bg = pygame.image.load('images/bg.jpg')
FPS = pygame.time.Clock()
fps = 60
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
winW = 1227
winH = 700
win = pygame.display.set_mode((winW, winH))
win.fill(WHITE)
pygame.display.set_icon(win)
def redraw_window():
#win.fill(WHITE)
win.blit(bg, (0, 0))
win.blit(text_to_screen('FPS: {}'.format(FPS.get_fps()), BLUE), (25, 50))
pygame.display.update()
def text_to_screen(txt, col):
font = pygame.font.SysFont('Comic Sans MS', 25, True)
text = font.render(str(txt), True, col)
return text
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
redraw_window()
FPS.tick(fps)
pygame.quit()
Ensure that the background Surface has the same format as the display Surface. Use convert() to create a Surface that has the same pixel format. That should improve the performance, when the background is blit to the display, because the formats are compatible and blit do not have to do an implicit transformation.
bg = pygame.image.load('images/bg.jpg').convert()
Furthermore, it is sufficient to create the font once, rather than every time when a text is drawn. Move font = pygame.font.SysFont('Comic Sans MS', 25, True) to the begin of the application (somewhere after pygame.init() and before the main application loop)
Instead use screen.blit(pygame.image.load(picture.png))
Just image = pygame.image.load(picture.png) then screen.blit(image)
( if you keep loading your pictures continuously it will get lag )