Blinking endscreen - pygame - python

So Im making a game and at the end of 60 seconds I want to make the screen change colors and display some end text.
I set up the timer like this:
time = 60
TICKTOCK = 0
pygame.time.set_timer (TICKTOCK+1, 1000)
and that's being displayed onscreen just fine, but when the end screen appear it flashes between the original white screen and the end screen. For some reason, it doesn't flash if I'm waving my mouse around the screen.
if time <= 0:
playground.fill(black)
playground.blit(end, (0, 100))
"end" is my game over text variable
pygame.display.flip()
playground.fill(white)
clock.tick (fps)
pygame.quit()
This is what I have at the end too if that helps
Is there a way I can make it appear steadily without having to change my timer?

You show not enough code so I can only suggest to do something like this
if not gameover:
playground.fill(...)
# draw normal game
else:
playground.fill(...)
# draw gameover text
playground.flip()

Related

Is there a more accurate clock for pygame for a rhythm game I'm making

I'm trying to get a series of lines to fall through the screen at exact tempo, for example, you input say 120 BPM and the result is the road lines hitting the bottom of the screen at 120 BPM.
I have tried using both pygame.clock.tick() and pygame.time.delay() (which I heard is more accurate), however when I use these as a clock to blit both the background and the road lines, against a metronome the clock seems very inconsistent.
For making an exact rhythm game which must stay in time for the entire song, is there another way to do this?
#GAMELOOP
while playing==True:
win.blit(bg,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
playing = False
#win.fill(WHITE)
y1=y1+gameSpeed
y2=y2+gameSpeed
y3=y3+gameSpeed
win.blit(track1,(x,y1))
win.blit(track2,(x,y2))
win.blit(track3,(x,y3))
if y1>=1000:
y1=-2000
if y2>=1000:
y2=-2000
if y3>=1000:
y3=-2000
fpsClock.tick(30)
pygame.display.update()
pygame.quit()
120 BPM (which I assume is "Beats Per Minute"), is only a per half-second timing, that's reasonably slow in computer terms. Most applications repaint the screen at 3600 frame-updates per minute (60Hz).
You can use the pygame.time object to return the number of milliseconds since the program started. This is really useful for timing things in the game:
clock = pygame.time.get_ticks() # time now
So immediately on start-up, this time is "0 milliseconds", and grows from there, forever more.
This value can then be used in relative time comparisons. When you make the track1 fall, it's possible to update the y-position based on the clock. One way to do this is to calculate the future millisecond-time at which the track1 should next move:
clock = pygame.time.get_ticks()
track1_move_next_time = clock + 500 # 500 milliseconds = 120 BPM
The repeatedly check that time until it's in the past. Then move the track1:
# In the Main Loop:
clock = pygame.time.get_ticks()
# ...
if ( clock > track1_move_next_time ): # is it time to move?
y1 += pixels_per_tick # move it
track1_move_next_time = clock + 500 # set next move time

How do I move my Rect that has text across the screen?

I'm working on a project where I want to move this text box that I made from the left to the right. I have multiple of these text boxes, and I wanted to do that right after one another.
text1_rect = text1.get_rect(center = (window_width/2, window_height*.25)) : This is the current location of the text, but I was looking at the rect.move method to do this.
window.blit(text1, text1_rect) : This is how I blit the text onto the screen when the program first starts up.
I don't require a direct answer, but maybe just some tips or a nudge in the right direction on how to add a little movement to my text box.
Create text1_rect before the application loop and change the position of the rectangle in the application loop
If you want to move the text form from the left to the center of the window, you need to set the start position outside the window and move the text until it is in the center.
Use pygame.time.Clock to control the frames per second and thus the game speed.
The method tick() of a pygame.time.Clock object, delays the game in that way, that every iteration of the loop consumes the same period of time. See pygame.time.Clock.tick():
This method should be called once per frame.
That means that the loop:
clock = pygame.time.Clock()
run = True
while run:
clock.tick(60)
runs 60 times per second.
clock = pygame.time.Clock()
# initial position is outside the window
text1_rect = text1.get_rect(midright = (0, window_height*.25))
# [...]
while run:
clock.tick(60)
# [...]
window.blit(text1, text1_rect)
# move the text to the center
if text1_rect.centerx < window_width // 2:
text1_rect.x += 1
# [...]

Pygame - can I make music have an introduction and then a loop point?

I'm currently working on a game in Pygame, and I've been trying to think of a way to have a music track that loops at a point that isn't the beginning of the track. So essentially, it plays an introduction, then moves onto another section that repeats without revisiting that introduction.
I've thought of a couple of ways that almost worked, but they have problems.
The first was to have two separate audio files for the introduction and the looping section, then to use pygame.music.set_endevent(), and just load the second audio file once the first is finished. This left quite an obvious gap and click though.
The second was to also use two audio files but to queue in the second as the first is loaded. The problem with this is that it seems like you can't change the play mode from 0 (play once) to -1 (looping) for the new queued track...
I feel like there has to be a way of doing this, I'd really appreciate any help.
In the example below, PyGame's sound channels are used for multiple tracks. Here an event is created, such that after 1500 milliseconds, a second sound in played (at the same time as the looping track).
For your suggested use-case, the code could play the intro-music at start, but also set an event-timer for /intro-length/ milliseconds in the future. When that timer-event is received, the looping-part of your music could play continuously, as the intro should have just stopped. Using multiple channels, it should not matter if the two sounds overlap by a few milliseconds (of silence/fadeout), as long as the user does not perceive it of course! Maybe it will be tricky to get the timing 100% correct on vastly different systems, but it should get you close.
Note that in the example, the sounds are already initialised into PyGame Sound objects, I expect this would cut-down on startup latency.
import pygame
# Window size
WINDOW_WIDTH = 400
WINDOW_HEIGHT = 400
DARK_BLUE = ( 3, 5, 54)
### initialisation
pygame.init()
pygame.mixer.init()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
pygame.display.set_caption("Multi Sound with Timer")
### sound
# create separate Channel objects for simultaneous playback
channel1 = pygame.mixer.Channel(0) # argument must be int
channel2 = pygame.mixer.Channel(1)
# Rain sound from: https://www.freesoundslibrary.com/sound-of-rain-falling-mp3/ (CC BY 4.0)
rain_sound = pygame.mixer.Sound( 'rain-falling.ogg' )
channel1.play( rain_sound, -1 ) # loop the rain sound forever
# Car Horn sound from: https://www.freesoundslibrary.com/car-horn-sound-effect/ (CC BY 4.0)
horn_sound = pygame.mixer.Sound( 'car-horn.ogg' )
# Create a timer, which will (after the delay-time) post an event to the main loop
pygame.time.set_timer( pygame.USEREVENT, 1500 ) # play the horn in 1500 milliseconds
### Main Loop
clock = pygame.time.Clock()
done = False
while not done:
# Handle user-input
for event in pygame.event.get():
if ( event.type == pygame.QUIT ):
done = True
elif ( event.type == pygame.USEREVENT ):
# Timer expired, play the sound
channel2.play( horn_sound )
# Movement keys
#keys = pygame.key.get_pressed()
#if ( keys[pygame.K_UP] ):
# print("up")
# Update the window, but not more than 60fps
window.fill( DARK_BLUE )
pygame.display.flip()
# Clamp FPS
clock.tick_busy_loop(60)
pygame.quit()

Pygame Font text not displaying correct number

So, for the game I am working on I have found an error which I haven't been able to find an answer anywhere.
Here is a snippet of my code from my UI
if not self.game.rot_lim == 0:
pg.draw.rect(self.ui, (255,255,255), (730,16,32,32))
rotators = str(self.game.rot_rem)
self.draw_text("Prisms Remaining: " + rotators, 770)
rot_lim is an Integer which stores the value of how many total rotators the user can place for that level. Similarly, rot_rem is the amount remaining that can be placed.
My draw text function goes as follows:
def draw_text(self, text, x, y = 20):
# Renders text
draw = self.game.text.render(text, False, (0,0,0), (170, 170, 170))
# Draws on UI
self.ui.blit(draw, (x,y))
Now my issue comes with displaying this with 10 or more in total. When I go below 10, it displays with an extra 0 at the end (e.g. If I place 1 it goes to 90). For every one I place after it ignores the last 0, and it does not exist within the code (tested with print statements) so it only exists in the rendering side of it.
Thanks a lot!
Alright, I managed to recreate the issue and it has to do with re-drawing the screen (not with the code you posted). Since we can only see a portion of your code, I can't be exactly sure if my recreation matches your issue.
Make sure you are doing one of two things:
1) clearing the who screen by refilling the background color screen.fill((255, 255, 200))
2) clearing the portion where the text is by refilling it (maybe it is within a rectangle that needs to be redrawn)
This should happen in each pass of the game while loop. Basically, make sure you are refreshing the screen each time, because currently it is just drawing over

Stop time without freezing the program

In my pong game, whenever someone scores (the ball goes out to the left or to the right) the ball position is reset to the middle of screen and it waits one second before moving. In that one second I have a little animation going on.
My problem is this: if I pause the game in the middle of the animation, even though none of the objects are updated and only the pause text is drawn, time keeps rolling in. And if I wait time enough, the animation just stops right after I unpause the game. Here's what I mean. This is the ball update:
def update(self, dt):
now = pygame.time.get_ticks() / 1000
# if time elapsed since the ball got out >= BALL_WAIT_TIME
if now - self._spawn_time >= BALL_WAIT_TIME:
self.rect = self.calcnewpos(dt)
self.handle_collision()
# spawn animation
else:
step = 255 / (FPS * BALL_WAIT_TIME)
value = int(self._frame * step)
rgb = (value, value, value)
self._draw_ball(rgb)
self._frame += 1
From http://pygame.org/docs/ref/time.html#pygame.time.get_ticks:
pygame.time.get_ticks()
Return the number of millisconds since pygame.init() was called. Before pygame is initialized this will always be 0.
So even though nothing is drawn or updated while the game is paused, pygame.time.get_ticks() will still return the time elapsed since pygame.init. How can I solve this? Sorry if that is a little hard to understand, I'll post the rest of the code if needed.
Well it looks as though you're just subtracting the time that some event occurred from the current time. If that's your method for checking how much time has elapsed since the event, then it's not going to matter if the game has been paused. If the event happens and you then pause the game for 10 minutes, it's always going to have been 10 minutes since the event happened.
So with that in mind, you need some way to only count time when the game is active. Perhaps the ball could have an attribute that says how long since the ball got out, and you only increase it if the game isn't paused.
Edit: something like:
class Ball:
def spawn(self):
self.sinceSpawn = 0
def update(self, dt):
if not gamePaused:
self.sinceSpawn += dt
if self.sinceSpawn >= BALL_WAIT_TIME:
pass #Do something here

Categories