Given the following code (from this answer: How to display text in pygame?):
pygame.font.init() # you have to call this at the start,
# if you want to use this module.
my_font = pygame.font.SysFont('Comic Sans MS', 30)
text_surface = my_font.render('Some Text', False, (0, 0, 0))
Is it possible to make the word 'Text' bold while keeping the word 'Some ' regular?
(without rendering multiple times)
No it is not possible. You must use the "bold" version of the font. "bold" isn't a flag or attribute, it's just a different font. So you need to render the word "Text" with one font and the word "Some" with another font.
You can use pygame.font.match_font() to find the path to a specific font file.
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
courer_regular = pygame.font.match_font("Courier", bold = False)
courer_bold = pygame.font.match_font("Courier", bold = True)
font = pygame.font.Font(courer_regular, 50)
font_b = pygame.font.Font(courer_bold, 50)
text1 = font.render("Some ", True, (255, 255, 255))
text2 = font_b.render("Text", True, (255, 255, 255))
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill(0)
window.blit(text1, (50, 75))
window.blit(text2, (50 + text1.get_width(), 75))
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
With the pygame.freetype modle the text can be rendered with different styles like STYLE_DEFAULT and STYLE_STRONG. However, the text can only be rendered with one style at a time. So you still have to render each word separately:
import pygame
import pygame.freetype
pygame.init()
window = pygame.display.set_mode((400, 200))
clock = pygame.time.Clock()
ft_font = pygame.freetype.SysFont('Courier', 50)
text1, rect1 = ft_font.render("Some ",
fgcolor = (255, 255, 255), style = pygame.freetype.STYLE_DEFAULT)
text2, rect2 = ft_font.render("Text",
fgcolor = (255, 255, 255), style = pygame.freetype.STYLE_STRONG)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill(0)
window.blit(text1, (50, 75))
window.blit(text2, (50 + rect1.width, 75))
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
See also Text and font
Related
I'm trying to implement some text into my game. I've followed a tutorial that has led me to this
pygame.font.init()
gamefont = pygame.font.SysFont('Bahnschrift', 16)
text = gamefont.render("Round: ", 1, (0,0,0))
win.blit(text, (390, 10))
However, when I run my code, it says that the name 'win' is not defined. I was wondering if anyone knew how to fix this?
win is the pygame.Surface object which is associated to the window.
Somewhere you have t o initialize pygame (pygame.init()) and to create the window Surface (pygame.display.set_mode):
Minimal applicaiton:
import pygame
# initializations
pygame.init()
win = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
# create font ad render text
pygame.font.init()
gamefont = pygame.font.SysFont('Bahnschrift', 16)
text = gamefont.render("Round: ", 1, (0,0,0))
# main application loop
run = True
while run:
clock.tick(60)
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# clear the display
win.fill((255, 255, 255))
# draw the text
win.blit(text, (390, 10))
# update the display
pygame.display.flip()
I made this program:
import pygame
pygame.init()
WIDTH = 600
HEIGHT = 700
RED = (255, 0, 0)
BLACK = (0, 0, 0)
GREY = (211, 211, 211)
GREEN = (0, 255, 0)
win = pygame.display.set_mode((WIDTH, HEIGHT))
win.fill(GREY)
def buttons(buttonx, buttony, buttonw, buttonh, color, msg, size): # left, top, width, height, color, message, font size
pos = pygame.mouse.get_pos()
fontb = pygame.font.SysFont("arial", size)
text = fontb.render(msg, True, BLACK)
outline = pygame.Rect(buttonx - 2, buttony - 2, buttonw + 4, buttonh + 4)
win.fill(BLACK, outline)
button = pygame.Rect(buttonx, buttony, buttonw, buttonh)
win.fill(color, button)
textplace = text.get_rect(center=(buttonx + buttonw/2, buttony + buttonh/2))
win.blit(text, textplace)
if button.collidepoint(pos):
win.fill(GREEN, button)
win.blit(text, textplace)
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
pass
# this block of code should make window grey
def main_menu():
font1 = pygame.font.SysFont("arial", 45)
welcoming = font1.render("Welcome!", True, BLACK, GREY)
wRect = welcoming.get_rect(center=(WIDTH / 2, 75))
win.blit(welcoming, wRect)
buttons(100, 150, 400, 100, RED, "Play", 60)
buttons(100, 300, 175, 100, RED, "Options", 40)
buttons(325, 300, 175, 100, RED, "Instructions", 30)
buttons(100, 450, 175, 100, RED, "Leaderboard", 30)# left, top, width, height, color, message
buttons(325, 450, 175, 100, RED, "Quit", 60)
main = True
while main:
main_menu()
for event in pygame.event.get():
if event.type == pygame.QUIT:
main = False
pygame.display.update()
If any of the buttons is pressed, the window should turn completely grey (all buttons and texts should disappear). I have tried to put
win.fill(GREY)
pygame.display.update()
in place of
pass
# this block of code should make window grey
in lines 34 and 35, but it does not work. I have also tried to make some kind of functions that return grey window which is same size as the original window and then blit it on the main menu, but it doesn't work either. Can anyone help?
The code you are trying succeeds in filling the window with grey. However, the blank grey screen then has the menu drawn on top of it immediately by your main loop.
Using an additional global variable, current_screen, it is possible to prevent this from happening. The main loop now checks current_screen to see which screen it should draw before doing so, ensuring that the menu will not be drawn when it is not supposed to be shown.
This following code worked for me, but let me know if you have any problems with it.
import pygame
pygame.init()
# declare final variables
WIDTH = 600
HEIGHT = 700
RED = (255, 0, 0)
BLACK = (0, 0, 0)
GREY = (211, 211, 211)
GREEN = (0, 255, 0)
# create window
win = pygame.display.set_mode((WIDTH, HEIGHT))
win.fill(GREY)
# left, top, width, height, color, message, font size
def buttons(buttonx, buttony, buttonw, buttonh, color, msg, size):
global win, current_screen
pos = pygame.mouse.get_pos()
fontb = pygame.font.SysFont("arial", size)
text = fontb.render(msg, True, BLACK)
# draw button outline and fill
outline = pygame.Rect(buttonx - 2, buttony - 2, buttonw + 4, buttonh + 4)
win.fill(BLACK, outline)
button = pygame.Rect(buttonx, buttony, buttonw, buttonh)
win.fill(color, button)
# draw button text
textplace = text.get_rect(
center=(buttonx + buttonw/2, buttony + buttonh/2))
win.blit(text, textplace)
if button.collidepoint(pos): # button mouse-hover
win.fill(GREEN, button)
win.blit(text, textplace)
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN: # button pressed
current_screen = "blank"
def main_menu():
# draw welcome message
font1 = pygame.font.SysFont("arial", 45)
welcoming = font1.render("Welcome!", True, BLACK, GREY)
wRect = welcoming.get_rect(center=(WIDTH / 2, 75))
win.blit(welcoming, wRect)
# draw buttons
buttons(100, 150, 400, 100, RED, "Play", 60)
buttons(100, 300, 175, 100, RED, "Options", 40)
buttons(325, 300, 175, 100, RED, "Instructions", 30)
# left, top, width, height, color, message
buttons(100, 450, 175, 100, RED, "Leaderboard", 30)
buttons(325, 450, 175, 100, RED, "Quit", 60)
main = True
current_screen = "main menu"
while main:
# draw the current screen
if current_screen == "main menu":
main_menu()
elif current_screen == "blank":
win.fill(GREY)
else:
raise NotImplementedError("There is no behavior defined for the current screen, "+current_screen+", in the main loop!")
# end main loop on window close
for event in pygame.event.get():
if event.type == pygame.QUIT:
main = False
pygame.display.update()
I'm fairly new to python and pygame. I'm trying to make a simple game as a practice. My problem is how do I have a loop (or many loops) inside the main game loop so that the graphic also updates inside sub loops? For example I have a button and a rectangle, if I press on the button I want the rectangle to move across the screen. Things I've tried:
Another while loop, it works but the rectangle won't "move" and just appears wherever the loop is finished
Custom event, however it either works once per frame or continuously in case of set_timer() function
Here's my code:
import pygame as pg
pg.init()
clock = pg.time.Clock()
running = True
window = pg.display.set_mode((640, 480))
window.fill((255, 255, 255))
btn = pg.Rect(0, 0, 100, 30)
rect1 = pg.Rect(0, 30, 100, 100)
while running:
clock.tick(60)
window.fill((255, 255, 255))
for e in pg.event.get():
if e.type == pg.MOUSEBUTTONDOWN:
(mouseX, mouseY) = pg.mouse.get_pos()
if(btn.collidepoint((mouseX, mouseY))):
rect1.x = rect1.x + 1
if e.type == pg.QUIT:
running = False
#end event handling
pg.draw.rect(window, (255, 0, 255), rect1, 1)
pg.draw.rect(window, (0, 255, 255), btn)
pg.display.flip()
#end main loop
pg.quit()
Any help is much appreciated
You have to implement some kind of state. Usually, you would use the Sprite class, but in your case, a simple variable would do.
Take a look at this example:
import pygame as pg
pg.init()
clock = pg.time.Clock()
running = True
window = pg.display.set_mode((640, 480))
window.fill((255, 255, 255))
btn = pg.Rect(0, 0, 100, 30)
rect1 = pg.Rect(0, 30, 100, 100)
move_it = False
move_direction = 1
while running:
clock.tick(60)
window.fill((255, 255, 255))
for e in pg.event.get():
if e.type == pg.MOUSEBUTTONDOWN:
(mouseX, mouseY) = pg.mouse.get_pos()
if(btn.collidepoint((mouseX, mouseY))):
move_it = not move_it
if e.type == pg.QUIT:
running = False
#end event handling
if move_it:
rect1.move_ip(move_direction * 5, 0)
if not window.get_rect().contains(rect1):
move_direction = move_direction * -1
rect1.move_ip(move_direction * 5, 0)
pg.draw.rect(window, (255, 0, 255), rect1, 1)
pg.draw.rect(window, (255, 0, 0) if move_it else (0, 255, 255), btn)
pg.display.flip()
#end main loop
pg.quit()
When the button is pressed, we just set the move_it flag.
Then, in the main loop, we check if this flag is set, and then move the Rect.
You should avoid creating multiple logic loops (sorry, I don't have a better word) in your game; see the problems you mentioned. Aim for one single main loop that does three things: input handling, game logic, and drawing.
import pygame
import random
WIDTH = 360
HEIGHT = 480
FPS = 30
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode([WIDTH, HEIGHT])
pygame.display.set_caption("My Game")
clock = pygame.time.Clock()
class Player(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((10, 10))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.centerx = WIDTH / 2
self.rect = HEIGHT - 10
all_sprites = pygame.sprite.Group()
Player = Player()
all_sprites.add(Player)
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
all_sprites.update()
screen.fill(BLACK)
all_sprites.draw(screen)
pygame.display.flip()
pygame.quit()
Hello I am getting this error when i am trying to run this program File , line 54, in
all_sprites.draw(screen)
line 475, in draw
self.spritedict[spr] = surface_blit(spr.image, spr.rect)
TypeError: invalid destination position for blit. Plz help me.
Your rect attribute must be an Rect object but you're overriding it with an integer in the line self.rect = HEIGHT - 10. Since a single integer isn't a valid location to blit a sprite on you get "invalid destination position for blit".
So i'm making a space game where you have a open world to explore (A black Screen)
and i wanna create planets(Blit images to screen) around the universe(from a list).
This is my code currently
star = pygame.image.load("star.png")
planets = random.randrange(100,500) #<------#####NOT IMPORTANT#######
positions = [(300,50),(400,27),(900,55)] #<------
position = ()
positions has coorinates where images should be blitted
but when i blit them
for position in positions:
ikkuna.blit(star, position)
it blits the first one or nothing and does not crash
why?
################################################-
Here is the full code if it helps (there is bits of the finish language in there hope it does not bother)
"ikkuna = screen (leveys,korkeus) = (width,hight) toiminnassa = in action"
import pygame
import random
import time
import sys
import math
pygame.init()
White = (255,255,255)
red = (255,0,0)
kello = pygame.time.Clock()
star = pygame.image.load("star.png")
planets = random.randrange(100,500)
positions = [(300,50)]
position = ()
tausta_vari = (255,255,255)
(leveys, korkeus) = (1000, 1000)
ikkuna = pygame.display.set_mode((leveys, korkeus))
pygame.display.set_caption("SpaceGenerationTest")
######################################################################
toiminnassa = True
while toiminnassa:
for event in pygame.event.get():
if event.type == pygame.QUIT:
toiminnassa = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
print("Generating World....")
print(planets)
for position in positions:
ikkuna.blit(star, position)
print("hello")
There's some problems with your code:
Your not updating the display, which means that all your changes won't be visible. Use pygame.display.update() or pygame.display.flip() at the end of the game loop to update the screen.
When you're mixing English and Finnish it becomes very inconsistent and hard to follow, especially for people who don't speak Finnish. Try to use English, even when you're just practicing.
Your full example only contain one position in the list, thus it's only creating one star at one position.
Pressing the 'g'-key won't generate any planets. You might want to introduce a boolean variable like in the example below.
I changed your code to english and made some adjustment so it's more consistent.
import pygame
import random
pygame.init()
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# I changed the background color to black, because I understood it as that is what you want.
BACKGROUND_COLOR = (0, 0, 0) # tausta_vari
clock = pygame.time.Clock() # kello
star = pygame.Surface((32, 32))
star.fill((255, 255, 255))
planets = random.randrange(100, 500)
positions = [(300, 50), (400, 27), (900, 55)]
WIDTH, HEIGHT = (1000, 1000) # (leveys, korkeus)
screen = pygame.display.set_mode((WIDTH, HEIGHT)) # ikkuna
pygame.display.set_caption("SpaceGenerationTest")
display_stars = False
running = True # toiminnassa
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
print("Generating World....")
print(planets)
display_stars = True
screen.fill(BACKGROUND_COLOR)
if display_stars:
for position in positions:
# This will create 3 stars because there're 3 elements in the list positions.
# To create more stars you'll need to add more in the list positions.
screen.blit(star, position)
pygame.display.update()
Your blitting all your images to the exact same position: positions = [(300, 50)], so the last image covers all the other images up. Also, you may not know this, but to display anything in pygame you have to either call pygame.display.flip() or pygame.display.update() after you finish drawing. I made a few revisions to your code, so the stars should show-up:
import pygame
import random
import time
import sys
import math
def main():
pygame.init()
White = (255,255,255)
red = (255,0,0)
kello = pygame.time.Clock()
star = pygame.image.load("star.png")
planets = random.randrange(100,500)
positions = [(300,50), (310, 60), (320, 80), (607, 451), (345, 231)]
tausta_vari = (255,255,255)
(leveys, korkeus) = (1000, 1000)
ikkuna = pygame.display.set_mode((leveys, korkeus))
pygame.display.set_caption("SpaceGenerationTest")
######################################################################
toiminnassa = True
while toiminnassa:
for event in pygame.event.get():
if event.type == pygame.QUIT:
toiminnassa = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_g:
print("Generating World....")
print(planets)
ikkuna.fill((0, 0, 0)) # fill the screen with black
for position in positions:
ikkuna.blit(star, position)
print("Hello")
pygame.display.flip() # updating the screen
if __name__ == '__main__': # are we running this .py file as the main program?
try:
main()
finally:
pg.quit()
quit()
~Mr.Python