How to display an FPS counter in pygame? - python

I have recently started learning pygame, and I'd like to have an FPS counter displayed in the top left of the screen. I have that already done but when I start my game the FPS counter displays this, which is not what I'd like. I'd like the counter to display just two numbers, which would be 60 in that picture. This is my code so far:
class FPSCounter:
def __init__(self, surface, font, clock, color, pos):
self.surface = surface
self.font = font
self.clock = clock
self.pos = pos
self.color = color
self.fps_text = self.font.render(str(int(self.clock.get_fps())) + "FPS", False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
def render(self):
self.surface.blit(self.fps_text, self.fps_text_rect)
def update(self):
self.fps_text = self.font.render(str(self.clock.get_fps()) + "FPS", False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
And this is how I'd display it in my game:
import pygame, sys
from fps_counter import FPSCounter
pygame.init()
clock = pygame.time.Clock()
black = (0, 0, 0)
green = (0, 0, 255)
width = 640
height = 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("FPS Test")
font = pygame.font.Font(None, 36)
fps_counter = FPSCounter(screen, font, clock, green, (150, 10))
while True:
screen.fill(black)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
fps_counter.render()
fps_counter.update()
pygame.display.update()
clock.tick(60)
Thank you in advance. :)

All you need to do is to format the text. See Format String Syntax:
class FPSCounter:
# [...]
def update(self):
text = f"{self.clock.get_fps():2.0f} FPS"
self.fps_text = self.font.render(text, False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))

Related

How do I make this pymunk code work? It shows a black screen

I am new to stackoverflow.
My code has a problem which the screen turns completely black.
The error.
I need the answer quickly so any help will be good.
Heres the code:
import pygame, sys
import pymunk
import pymunk.pygame_util
from pymunk.vec2d import Vec2d
size = (800, 800)
FPS = 120
space = pymunk.Space()
space.gravity = (0,250)
pygame.init()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ball:
global space
def __init__(self, pos):
self.body = pymunk.Body(1,1, body_type = pymunk.Body.DYNAMIC)
self.body.position = pos
self.radius = 60
self.shape = pymunk.Circle(self.body, self.radius)
space.add(self.body, self.shape)
def draw(self):
x = int(self.body.position.x)
y = int(self.body.position.y)
pygame.draw.circle(screen, (255,0,0), (x,y), self.radius)
balls = []
balls.append(Ball((400,0)))
balls.append(Ball((100,0)))
balls.append(Ball((600,100)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screeen.fill(217,217,217)
for ball in balls:
ball.draw()
space.step(1/50)
pygame.display.update()
clock.tick(FPS)
Any help on what to do???
Thanks.
screeen.fill(217,217,217) should be screen.fill((217,217,217))
The Indentation is not correct. In particular, the scene must be pulled in the application loop and not in the bleed loop:
import pygame, sys
import pymunk
import pymunk.pygame_util
from pymunk.vec2d import Vec2d
size = (800, 800)
FPS = 120
space = pymunk.Space()
space.gravity = (0,250)
pygame.init()
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
class Ball:
global space
def __init__(self, pos):
self.body = pymunk.Body(1,1, body_type = pymunk.Body.DYNAMIC)
self.body.position = pos
self.radius = 60
self.shape = pymunk.Circle(self.body, self.radius)
space.add(self.body, self.shape)
# INDENTATION
#<--|
def draw(self):
x = int(self.body.position.x)
y = int(self.body.position.y)
pygame.draw.circle(screen, (255,0,0), (x,y), self.radius)
balls = []
balls.append(Ball((400,0)))
balls.append(Ball((100,0)))
balls.append(Ball((600,100)))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# INDENTATION
#<------|
screen.fill((217,217,217))
for ball in balls:
ball.draw()
space.step(1/50)
pygame.display.update()
clock.tick(FPS)

I'n creating my first game in pygame and i need help on showing up a screen when i press any key [duplicate]

This question already has answers here:
Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?
(1 answer)
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
As i mention, i'm super new in pygame and need help with this. I'm just testing the pygame commands, and want to show up a white screen with a message whenever i initialize the game and press any key, but apparently, it's not working. Here's my code:
# pygame template
import pygame
# import random
WIDTH = 400
HEIGHT = 500
FPS = 60
TITLE = 'My Game'
FONT_NAME = 'SNAKE/DinoTopia.ttf'
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
CLOCK = pygame.time.Clock()
# classes
class Main:
def __init__(self):
self.running = False
self.game_font = pygame.font.match_font(FONT_NAME)
def show_screen(self):
if self.running is True:
SCREEN.fill(WHITE)
self.draw_text('HELLO', 50, WIDTH/2, HEIGHT/2, BLUE)
pygame.display.flip()
self.wait_for_key()
def wait_for_key(self):
for key in pygame.event.get():
if key.type == pygame.KEYUP:
self.running = True
self.show_screen()
def draw_text(self, text, size, x, y, color):
font = pygame.font.Font(self.game_font, size)
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
text_rect.center = (x, y)
SCREEN.blit(text_surface, text_rect)
g = Main()
# game loop
running = True
while running:
# keep loop running at the right speed
CLOCK.tick(FPS)
# process input
for event in pygame.event.get():
# check for closing window
if event.type == pygame.QUIT:
running = False
# update
# draw/ render
SCREEN.fill(BLACK)
g.wait_for_key()
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()
i know something may be wrong with the wait_for_key function but i can't see what it is, so a little help would be nice! thanks in advance!
show screen function is only called when a key is up. A single frame. You have to call it every frame. Also don't call pygame.event.get and pygame.display.flip more than once.
# pygame template
import pygame
# import random
WIDTH = 400
HEIGHT = 500
FPS = 60
TITLE = 'My Game'
FONT_NAME = 'SNAKE/DinoTopia.ttf'
# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# initialize pygame and create window
pygame.init()
pygame.mixer.init()
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
CLOCK = pygame.time.Clock()
# classes
class Main:
def __init__(self):
self.running = False
self.game_font = pygame.font.match_font(FONT_NAME)
def show_screen(self):
if self.running:
SCREEN.fill(WHITE)
self.draw_text('HELLO', 50, WIDTH/2, HEIGHT/2, BLUE)
def wait_for_key(self, events):
for event in events:
if event.type == pygame.KEYUP:
self.running = True
def draw_text(self, text, size, x, y, color):
font = pygame.font.Font(self.game_font, size)
text_surface = font.render(text, True, color)
text_rect = text_surface.get_rect()
text_rect.center = (x, y)
SCREEN.blit(text_surface, text_rect)
g = Main()
# game loop
running = True
while running:
# keep loop running at the right speed
CLOCK.tick(FPS)
# process input
events = pygame.event.get()
for event in events:
# check for closing window
if event.type == pygame.QUIT:
running = False
# update
# draw/ render
SCREEN.fill(BLACK)
g.wait_for_key(events)
g.show_screen()
# *after* drawing everything, flip the display
pygame.display.flip()
pygame.quit()

Detect when my mouse is on 2 rect and choose the action

I don't know how to detect when my mouse is on 2 rect and choose (if two rect has an action) the action. For example, in Windows, when two windows are one over the other, it's the first window that will be selected. I want to do exactly the same thing.
import pygame
class Rectangle(pygame.sprite.Sprite):
def __init__(self, screen, rect, x, y, color, name):
super().__init__()
self.screen = screen
self.name = name
self.screen_str = str(screen)
self.rect = rect
self.color = color
self.x, self.y = x, y
self.r = pygame.Surface((self.rect[2], self.rect[3]), pygame.SRCALPHA)
self.rect = self.r.get_rect()
self.rect.x, self.rect.y = x, y
self.r.fill(self.color)
pygame.init()
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("PyStoneTest")
width, height = screen.get_size()
background_default = "image\Settings\Wallpaper\default_1.jpg"
D = {}
D["Rect2"] = Rectangle(screen, (0, 200, width, 70), 0,
50, (255, 255, 0), "Rect2")
D["Rect1"] = Rectangle(screen, (0, 100, width-200, 200), 0,
100, (255, 0, 255), "Rect1")
Programme = ["Rect1", "Rect2"]
while True:
background = pygame.image.load(background_default).convert()
background = pygame.transform.scale(background, (width, height))
for event in pygame.event.get():
x,y = pygame.mouse.get_pos()
if event.type == pygame.QUIT:
pygame.quit()
for element in Programme:
if D[element].rect.collidepoint(x,y) and event.type == pygame.MOUSEBUTTONDOWN:
del Programme[Programme.index(D[element].name)]
Programme.append(D[element].name)
print(Programme)
screen.blit(background, (0, 0))
for element in Programme:
screen.blit(D[element].r, D[element].rect)
pygame.display.update()
You should first run for-loop to check all windows and use last one which collides with mouse.
elif event.type == pygame.MOUSEBUTTONDOWN:
last = None
for element in Programme:
if D[element].rect.collidepoint(event.pos):
last = element
if last:
Programme.remove(last)
Programme.append(last)
print(Programme)
Or you would have to check in reverse order - from last to first - and break loop on first matching rectangle.
elif event.type == pygame.MOUSEBUTTONDOWN:
last = None
for element in reversed(Programme):
if D[element].rect.collidepoint(event.pos):
last = element
break
if last:
Programme.remove(last)
Programme.append(last)
print(Programme)
Minimal working code with other changes
import pygame
# --- classes ---
class Rectangle(pygame.sprite.Sprite):
# I skip `x,y` because I have it in `rect`
def __init__(self, screen, rect, color, name):
super().__init__()
self.screen = screen
self.color = color
self.name = name
self.rect = pygame.Rect(rect)
self.image = pygame.Surface(self.rect.size, pygame.SRCALPHA)
self.image.fill(self.color)
def draw(self):
self.screen.blit(self.image, self.rect)
# --- functions ---
# empty
# --- main ---
pygame.init()
screen = pygame.display.set_mode((1280, 720))
screen_rect = screen.get_rect() # it can be useful to center elements on screen - `d[name].rect.center = screen_rect.center`
pygame.display.set_caption("PyStoneTest")
# raw string
background_default = r"image\Settings\Wallpaper\default_1.jpg"
# load and rescale before `while`-loop
background = pygame.image.load(background_default).convert()
background = pygame.transform.scale(background, screen_rect.size)
d = {} # PEP8: `lower_case_names` for variable
d["Rect2"] = Rectangle(screen, (0, 0, screen_rect.width-100, 70), (255, 255, 0), "Rect2")
d["Rect2"].rect.center = screen_rect.center
d["Rect1"] = Rectangle(screen, (0, 0, 70, screen_rect.height-100), (255, 0, 255), "Rect1")
d["Rect1"].rect.center = screen_rect.center
programme = ["Rect1", "Rect2"] # PEP8: `lower_case_names` for variable
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit() # to skip rest of while-loop
elif event.type == pygame.MOUSEBUTTONDOWN:
selected = None
for name in programme:
if d[name].rect.collidepoint(event.pos):
selected = name
if selected and selected != programme[-1]:
programme.remove(selected)
programme.append(selected)
print('after replace:', programme)
screen.blit(background, (0, 0))
for name in programme:
d[name].draw()
pygame.display.update()
I cannot help with your code since I cannot understand what you are doing but I can offer my own solution. Since pygame renders thigs that are drawn later on the top, you can change the rendering order of your rectangles by checking which rectangle is being clicked and swapping it with the last rectangle in your list.
Here is an example. The colors in my example change weirdly but that's because I am generating them on the fly just to be able to tell the different between the different rects. You shouldn't have this problem.
import pygame
pygame.init()
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("PyStoneTest")
rects = []
for i in range(10):
rects.append(pygame.Rect(i * 25, 100, 30, 30))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
screen.fill((0, 0, 0))
c = 1
for rect in rects:
pygame.draw.rect(screen, (c, 100, 100), rect)
c += 20
clicked = pygame.mouse.get_pressed()
x,y = pygame.mouse.get_pos()
for rect in rects:
if (rect.collidepoint(x, y) and clicked[0]):
#swap it
rects[-1][:], rect[:] = rect[:], rects[-1][:]
pygame.display.update()

Hide part after 5 seconds after mousedown action

I'm new to python. I programmed with vb2010, but it's time to try something new. I want to hide a action after 5 seconds after mouse down event(like in start()).
import pygame
import sys
from pygame.locals import *
from time import gmtime, strftime
import threading
import time
white = (255,255,255)
black = (0,0,0)
blue = (0,0,255)
width = 600
height = 400
channel = '0001'
name = 'Channel 3'
class screen(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('PyTV')
self.screen = pygame.display.set_mode((width,height), 0, 32)
self.screen.fill((black))
pygame.display.update()
def printData(self):
self.rect = pygame.draw.rect(self.screen, (blue), (0, 0, width, height - 350), 0)
self.screen.blit(self.font.render(channel, True, white), (width - 590, 0))
self.screen.blit(self.font.render(name, True, white), (height - 335, 0))
self.screen.blit(self.font.render(strftime("%H:%M %d/%m/%Y", gmtime()), True, white), (width - 590, height - 377))
pygame.display.update()
def clean(self):
self.screen.fill((black))
pygame.display.update()
if __name__ == '__main__':
def start():
Pan3.printData()
time.sleep(5)
Pan3.clean()
Pan3 = screen()
threading.Thread(target=start).start()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
if event.type == pygame.MOUSEBUTTONDOWN:
print 'Event! Mouse Down! Code here....'
A timer may suit your needs, given that you also use threading.
EDIT: Addressing your needs for a more detailed explanation as to how to get it to work, here's some pseudo-code.
if event.type == pygame.MOUSEBUTTONDOWN:
if active_timer:
timer.cancel()
timer = Timer(5.0, show_info_things)
timer.start()
I hope this gets you going well enough.
When you click left mouse first time then it shows date, when you click second time then it hides date. If you don't click second time then it hides automatically after 5 seconds.
The same with key SPACE - first press shows, second hides. If you don't press second time then it hides automatically after 5 seconds.
Key ESC and right click hides too.
import pygame
import sys
import time
# --- constants --- (UPPER_CASE names)
WHITE = (255,255,255)
BLACK = ( 0, 0, 0)
BLUE = ( 0, 0,255)
WIDTH = 600
HEIGHT = 400
# --- classes --- (CamelCase names)
class Screen(object):
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
pygame.display.set_caption('PyTV')
self.font = pygame.font.SysFont('Arial', 25)
self.channel = '0001'
self.name = 'Channel 3'
self.show_data = None
self.current_time = pygame.time.get_ticks()
def draw_data(self):
self.rect = pygame.draw.rect(self.screen, BLUE, (0, 0, WIDTH, HEIGHT-350), 0)
self.screen.blit(self.font.render(self.channel, True, WHITE), (WIDTH-590, 0))
self.screen.blit(self.font.render(self.name, True, WHITE), (HEIGHT-335, 0))
self.screen.blit(self.font.render(time.strftime("%H:%M:%S %d/%m/%Y", time.gmtime()), True, WHITE), (WIDTH-590, HEIGHT-377))
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.show_data = None
elif event.key == pygame.K_SPACE:
if self.show_data:
self.show_data = None
else:
self.show_data = self.current_time + 5000
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if self.show_data:
self.show_data = None
else:
self.show_data = self.current_time + 5000
elif event.button == 3:
# hide on right click
self.show_data = None
def update(self):
# if displayed
if self.show_data:
# check time
if self.current_time >= self.show_data:
# hide after time
self.show_data = None
def draw(self):
self.screen.fill(BLACK)
if self.show_data:
self.draw_data()
pygame.display.update()
def run(self): # mainloop
while True:
self.current_time = pygame.time.get_ticks()
if self.events() is False:
break
self.update()
self.draw()
#sys.exit()
# --- fucntions --- (lower_case names)
# empty
# --- main ---
if __name__ == '__main__':
Screen().run()

PyGame: text not appearing

i was following a tutorial and i'm trying to get my text to appear in the screen, here is my code but the text won't appear:
from __future__ import division
import math
import sys
import pygame
class MyGame(object):
def __init__(self):
pygame.mixer.init()
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init()
self.width = 800
self.height = 600
self.screen = pygame.display.set_mode((self.width, self.height))
self.bg_color = 0, 0, 0
font = pygame.font.Font(None, 100)
text = font.render("text that should appear", True, 238, 58, 140)
self.FPS = 30
self.REFRESH = pygame.USEREVENT+1
pygame.time.set_timer(self.REFRESH, 1000//self.FPS)
def run(self):
running = True
while running:
event = pygame.event.wait()
if event.type == pygame.QUIT:
running = False
elif event.type == self.REFRESH:
self.draw()
else:
pass
def draw(self):
self.screen.fill(self.bg_color)
screen.blit(text, [400,300])
pygame.display.flip()
MyGame().run()
pygame.quit()
sys.exit()
any idea why is this happening? am i forgetting to import a library or is there something off with my draw method?
It looks like you're passing the three RGB values of color in as three separate values to render. They should be passed in as a single tuple.
You're also missing some selfs. screen.blit(text, [400,300]) should be self.screen.blit(text, [400,300]), and you need to make all instances of text into self.text if you want it to be accessible in both __init__ and draw.
from __future__ import division
import math
import sys
import pygame
class MyGame(object):
def __init__(self):
pygame.mixer.init()
pygame.mixer.pre_init(44100, -16, 2, 2048)
pygame.init()
self.width = 800
self.height = 600
self.screen = pygame.display.set_mode((self.width, self.height))
self.bg_color = 0, 0, 0
font = pygame.font.Font(None, 100)
self.text = font.render("text that should appear", True, (238, 58, 140))
self.FPS = 30
self.REFRESH = pygame.USEREVENT+1
pygame.time.set_timer(self.REFRESH, 1000//self.FPS)
def run(self):
running = True
while running:
event = pygame.event.wait()
if event.type == pygame.QUIT:
running = False
elif event.type == self.REFRESH:
self.draw()
else:
pass
def draw(self):
self.screen.fill(self.bg_color)
self.screen.blit(self.text, [400,300])
pygame.display.flip()
MyGame().run()
pygame.quit()
sys.exit()
Result:

Categories