Two Surfaces not bliting pygame - python

I'm trying to render some font onto my Pygame screen but it never shows up. I think I have everything set-up right and my programs not throwing any errors so I'm not sure what's wrong. This is the code I'm using to try and create the text:
pygame.init()
pygame.display.set_caption("MyGame")
font = SysFont("Times", 24) #Create a new font using times if it exists, else use system font.
white = (255, 255, 255)
while True: #Game loop
label = font.render("Score: " + str(score), 1, white)
self.surface.blit(label, (100, 100))
# Do other game things....
self.board.draw()
pygame.display.update()
self.clock.tick(60)
and in my init function:
def __init__(self):
self.surface = pygame.display.set_mode((400, 500)) #Set dimensions of game window. Creates a Surface
self.clock = pygame.time.Clock()
self.board = Board(self.surface) # Board is an object in my game
What am I doing wrong? I've looked all over the Pygame documentation and SO but I can't see anything wrong in my code. I've also tried setting the font explicitly with
font = pygame.font.Font("/System/Library/Fonts/Helvetica.dfont", 24)
but nothing seems to work.

As furas suggested, the problem was caused by me filling in the surface after drawing.

Related

Pygame draggable frame seems not to be working

I am working with Pygame currently, and I made a simple function to create window instances much like Windows 10 UI. the code I made doesn't give any errors or any unwanted outputs. It just seems not to be working properly, what I mean by "not working properly"; it just doesn't seem to be moving the frames that are meant to be dragged around by a master frame...
This is my code:
import pygame
from pyautogui import size
import datetime
pygame.init()
infoObject = pygame.display.Info()
surface = pygame.display.set_mode((900, 700))
run = True
clock = pygame.time.Clock()
def draw_text(text, font, text_col, x,y):
img = font.render(text, True, text_col)
rect = img.get_rect()
rect.center = (x,y)
surface.blit(img, rect)
return rect
class make_a_window():
def __init__(self,app,width=750,height=500):
self.app_name = str(app)
self.width = width
self.height = height
def run(self):
self.top_frame = pygame.draw.rect(surface, "#C0C0C0", pygame.Rect(0,0,int(self.width),40))#master frame
self.main_frame = pygame.draw.rect(surface, (255,255,255), pygame.Rect(0,40,int(self.width),int(self.height)))
self.red_frame_for_exit_btn_X = pygame.draw.rect(surface, (255,0,0), pygame.Rect(self.width-42,0,42,40))
self.exit_btn_X = draw_text("x", pygame.font.SysFont("calibri",25), "black", self.width-20, 15)
self.mouse_position = pygame.mouse.get_pos()
if pygame.mouse.get_pressed()[0] == 1:
if self.top_frame.collidepoint(self.mouse_position):
#moving the frames
self.top_frame.move(self.mouse_position[0],self.mouse_position[1])
self.main_frame.move(self.mouse_position[0]-40,self.mouse_position[1])
self.red_frame_for_exit_btn_X.move(self.mouse_position[0]-42,self.mouse_position[1])
self.exit_btn_X.move(self.mouse_position[0]-20,self.mouse_position[1])
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
run = False
app = make_a_window("hello")
app.run()
pygame.display.update()
clock.tick(60)
Sorry for my bad English. and thanks for the help, I really appreciate it 😃!
There is some logic error from line 32 to 41.
Firstly you should use the event queue by pygame.event.get() to track mouse activities(this is really important) and secondly why are you recording the mouse position before hand you are checking for its collision. Instead you should insert your
{self.mouse_position = pygame.mouse.get_pos()}
inside the collision checking if statement (rather that would not work smoothly until you use pygame.event.get())
One more thing that the function
pygame.Rect().move()
takes x and y offesets as its arguments not x and y coordinates.
So, mainly give focus on your event loop and the destination positions of your manual window. Maybe I would share the correct code later (don't wait for it.)
The method pygame.Rect.move doesn't move the rectangle itself, but it returns new rectangle that is moved. In compare, the method pygame.Rect.move_ip move the object in place.
However, these methods do not move anything that has been drawn on the screen. These methods simply move a rectangle representing an area of the screen. This rectangle can later be used to draw something on the screen at a new location.
Create the pygame.Rect objects in the class's constructor and use them to draw the objects. Use move_ip to move the rectangles:
class make_a_window():
def __init__(self,app,width=750,height=500):
self.app_name = str(app)
self.width = width
self.height = height
self.top_frame = pygame.Rect(0,0,int(self.width),40)
self.main_frame = pygame.Rect(0,40,int(self.width),int(self.height))
self.red_frame_for_exit_btn_X = pygame.Rect(self.width-42,0,42,40)
self.exit_btn_X = pygame.Rect(self.width-20, 15, 0, 0)
def run(self):
pygame.draw.rect(surface, "#C0C0C0", self.top_frame)
pygame.draw.rect(surface, (255,255,255), self.main_frame)
pygame.draw.rect(surface, (255,0,0), self.red_frame_for_exit_btn_X)
draw_text("x", pygame.font.SysFont("calibri",25), "black", self.exit_btn_X.topleft)
self.mouse_position = pygame.mouse.get_rel()
if pygame.mouse.get_pressed()[0] == 1:
if self.top_frame.collidepoint(self.mouse_position):
#moving the frames
move_rel = pygame.mouse.get_rel()
self.top_frame.move_ip(*move_rel)
self.main_frame.move_ip(*move_rel)
self.red_frame_for_exit_btn_X.move_ip(*move_rel)
self.exit_btn_X.move_ip(*move_rel)

Illegal instruction: 4 on MacOS High Sierra

I am trying to make a chat-looking window in pygame 3.6, I just updated my MacBook to version 10.13.6, before I did this it worked perfectly but after I get the message: Illegal instruction: 4.
Code
import pygame
from pygame.locals import *
import pygame.gfxdraw
pygame.init()
window_width=360
window_height=640
animation_increment=10
clock_tick_rate=20
size = (window_width, window_height)
screen = pygame.display.set_mode(size)
black = (0,0,0)
grey = (220,220,220)
shadow = (0, 255, 0, 100)
pygame.display.set_caption("BrAIn")
dead=False
clock = pygame.time.Clock()
background_image = pygame.image.load("background.png").convert()
micro = pygame.image.load("microphone.png")
PF = pygame.image.load("BrAIn.png")
while(dead==False):
for event in pygame.event.get():
if event.type == pygame.QUIT:
dead = True
font = pygame.font.Font("Impact copy.ttf", 52)
text = font.render('BrAIn', True, (0,0,0))
screen.blit(background_image, [0, 0])
pygame.gfxdraw.hline(screen, 0, 360, 40, shadow)
pygame.draw.line(screen, black, [0,62], [360,62], 2)
pygame.draw.line(screen, grey, [0,30], [360,30], 62)
pygame.draw.line(screen, grey, [0,620],[360,620],75)
pygame.draw.line(screen, black, [0,583], [360,583], 2)
screen.blit(micro, [152, 587])
screen.blit(PF, [-5, -7])
screen.blit(text, [125,0])
pygame.display.flip()
clock.tick(clock_tick_rate)
Python 3.6 (and 2.7) also crashes after running this.
Although "removing pygame.init()" isn't really much of an answer and I would like to know why it does this and how to permanently fix this, I have found a way to 'fix' this problem. I removed the pygame.init() command, which gave me the error: pygame.error: font not initialized. This is pretty obvious because then you haven't initialized the engine where the fonts are. There is another way without using pygame.init() without getting this error (as many of you are aware I think), this is by using pygame.font.init(). I tried replacing pygame.init() by pygame.font.init() and finally my program worked like it used to. I would still very much like to know why and how this error is made, how to permanently get rid of it and what difference there is between pygame.font.init() and pygame.init() but this is a temporary answer for me.

How to display text in pygame? [duplicate]

This question already has answers here:
pygame - How to display text with font & color?
(7 answers)
Closed 2 years ago.
I can't figure out to display text in pygame.
I know I can't use print like in regular Python IDLE but I don't know how.
import pygame, sys
from pygame.locals import *
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = ( 255, 0, 0)
pygame.init()
size = (700, 500)
screen = pygame.display.set_mode(size)
DISPLAYSURF = pygame.display.set_mode((400, 300))
pygame.display.set_caption('P.Earth')
while 1: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.display.update()
import time
direction = ''
print('Welcome to Earth')
pygame.draw.rect(screen, RED, [55,500,10,5], 0)
time.sleep(1)
This is only the beginning part of the whole program.
If there is a format that will allow me to show the text I type in the pygame window that'd be great. So instead of using print I would use something else. But I don't know what that something else is.
When I run my program in pygame it doesn't show anything.
I want the program to run in the pygame window instead of it just running in idle.
You can create a surface with text on it. For this take a look at this short example:
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)
This creates a new object on which you can call the render method.
text_surface = my_font.render('Some Text', False, (0, 0, 0))
This creates a new surface with text already drawn onto it.
At the end you can just blit the text surface onto your main screen.
screen.blit(text_surface, (0,0))
Bear in mind, that every time the text changes, you have to recreate the surface again, to see the new text.
There's also the pygame.freetype module which is more modern, works with more fonts and offers additional functionality.
Create a font object with pygame.freetype.SysFont() or pygame.freetype.Font if the font is inside of your game directory.
You can render the text either with the render method similarly to the old pygame.font.Font.render or directly onto the target surface with render_to.
import pygame
import pygame.freetype # Import the freetype module.
pygame.init()
screen = pygame.display.set_mode((800, 600))
GAME_FONT = pygame.freetype.Font("your_font.ttf", 24)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((255,255,255))
# You can use `render` and then blit the text surface ...
text_surface, rect = GAME_FONT.render("Hello World!", (0, 0, 0))
screen.blit(text_surface, (40, 250))
# or just `render_to` the target surface.
GAME_FONT.render_to(screen, (40, 350), "Hello World!", (0, 0, 0))
pygame.display.flip()
pygame.quit()
When displaying I sometimes make a new file called Funk. This will have the font, size etc. This is the code for the class:
import pygame
def text_to_screen(screen, text, x, y, size = 50,
color = (200, 000, 000), font_type = 'data/fonts/orecrusherexpand.ttf'):
try:
text = str(text)
font = pygame.font.Font(font_type, size)
text = font.render(text, True, color)
screen.blit(text, (x, y))
except Exception, e:
print 'Font Error, saw it coming'
raise e
Then when that has been imported when I want to display text taht updates E.G score I do:
Funk.text_to_screen(screen, 'Text {0}'.format(score), xpos, ypos)
If it is just normal text that isn't being updated:
Funk.text_to_screen(screen, 'Text', xpos, ypos)
You may notice {0} on the first example. That is because when .format(whatever) is used that is what will be updated. If you have something like Score then target score you'd do {0} for score then {1} for target score then .format(score, targetscore)
This is slighly more OS independent way:
# do this init somewhere
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
font = pygame.font.Font(pygame.font.get_default_font(), 36)
# now print the text
text_surface = font.render('Hello world', antialias=True, color=(0, 0, 0))
screen.blit(text_surface, dest=(0,0))

How to add text into a pygame rectangle

I have come as far as drawing a rectangle in pygame however I need to be able to get text like "Hello" into that rectangle. How can I do this? (If you can explain it as well that would be much appreciated. Thank-you)
Here is my code:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
class Pane(object):
def __init__(self):
pygame.init()
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
#This is where I want to get the text from
if __name__ == '__main__':
Pan3 = Pane()
Pan3.addRect()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
Thank you for your time.
You first have to create a Font (or SysFont) object. Calling the render method on this object will return a Surface with the given text, which you can blit on the screen or any other Surface.
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
class Pane(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Hello!', True, (255,0,0)), (200, 100))
pygame.display.update()
if __name__ == '__main__':
Pan3 = Pane()
Pan3.addRect()
Pan3.addText()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
Note that your code seems a little bit strange, since usually you do all the drawing in the main loop, not beforehand. Also, when you make heavy use of text in your program, consider caching the result of Font.render, since it is a very slow operation.
Hi!
To be honestly there is pretty good ways to write text in any place of current rect.
And now i'll show how to do it pretty easy.
First of all we need to create object of rect instance:
rect_obj = pygame.draw.rect(
screen,
color,
<your cords and margin goes here>
)
Now rect_obj is object of pygame.rect instance. So, we are free to manipulate with this methods. But, beforehand lets create our rendered text object like this:
text_surface_object = pygame.font.SysFont(<your font here>, <font size here>).render(
<text>, True, <color>
)
Afterall we are free to manipulate with all methods, as i mensioned before:
text_rect = text_surface_object.get_rect(center=rect_obj.center)
What is this code about?
We've just got center cords of out current rect, so easy!
Now, you need to blit ur screen like this:
self.game_screen.blit(text_surface_object, text_rect)
Happy coding! :)

Update display all at one time PyGame

Using PyGame, I get flickering things. Boxes, circles, text, it all flickers. I can reduce this by increasing the wait between my loop, but I though maybe I could eliminate it by drawing everything to screen at once, instead of doing everything individually. Here's a simple example of what happens to me:
import pygame, time
pygame.init()
screen = pygame.display.set_mode((400, 300))
loop = "yes"
while loop=="yes":
screen.fill((0, 0, 0), (0, 0, 400, 300))
font = pygame.font.SysFont("calibri",40)
text = font.render("TextA", True,(255,255,255))
screen.blit(text,(0,0))
pygame.display.update()
font = pygame.font.SysFont("calibri",20)
text = font.render("Begin", True,(255,255,255))
screen.blit(text,(50,50))
pygame.display.update()
time.sleep(0.1)
The "Begin" button flickers for me. It could just be my slower computer, but is there a way to reduce or eliminate the flickers? In more complex things I'm working on, it gets really bad. Thanks!
I think part of the problem is you're calling 'pygame.display.update()' more then once. Try calling it only once during the mainloop.
Some other optimizations:
You could take the font creation code out of the main loop to speed things up
Do loop = True rather then loop = "yes"
To have a more consistent fps, you could use Pygame's clock class
So...
import pygame
pygame.init()
screen = pygame.display.set_mode((400, 300))
loop = True
# No need to re-make these again each loop.
font1 = pygame.font.SysFont("calibri",40)
font2 = pygame.font.SysFont("calibri",20)
fps = 30
clock = pygame.time.Clock()
while loop:
screen.fill((0, 0, 0), (0, 0, 400, 300))
text = font1.render("TextA", True,(255,255,255))
screen.blit(text,(0,0))
text = font2.render("Begin", True,(255,255,255))
screen.blit(text,(50,50))
pygame.display.update() # Call this only once per loop
clock.tick(fps) # forces the program to run at 30 fps.
You're updating your screen 2 times in a loop, one for drawing first text(TextA) and one for second text(Begin).
After your first update, only first text appears, so you can't see begin text between first update and second update. This causes flickering.
Update your screen after drawing everything. In your case, remove first pygame.display.update().
You're redrawing the content of your entire screen every 0.1 seconds. It's much more common and faster to keep track of the changes you actual make and only update the rects that actually contain changed content. So draw everything outside of your loop and have your events modify the screen and keep track of the rectangles that actually are changed.
So something like this:
import pygame, time
pygame.init()
screen = pygame.display.set_mode((400, 300))
screen.fill((0, 0, 0), (0, 0, 400, 300))
font = pygame.font.SysFont("calibri",40)
text = font.render("TextA", True,(255,255,255))
screen.blit(text,(0,0))
font = pygame.font.SysFont("calibri",20)
text = font.render("Begin", True,(255,255,255))
screen.blit(text,(50,50))
loop = "yes"
counter = 0
dirty_rects = []
while loop=="yes":
pygame.display.update()
time.sleep(0.1)
# Handle events, checks for changes, etc. Call appropriate functions like:
counter += 1
if counter == 50:
font = pygame.font.SysFont("calibri",20)
text = font.render("We hit 50!", True,(255,255,255))
screen.blit(text,(50,100))
dirty_rects.append(Rect((50,100),text.get_size()))
Pygame has a Buffer system to avoid flickering, so you should draw them as you are doing, but update only once at the end:
...
while loop=="yes":
screen.fill((0, 0, 0), (0, 0, 400, 300))
font = pygame.font.SysFont("calibri",40)
text = font.render("TextA", True,(255,255,255))
screen.blit(text,(0,0))
font = pygame.font.SysFont("calibri",20)
text = font.render("Begin", True,(255,255,255))
screen.blit(text,(50,50))
pygame.display.update() # only one update
time.sleep(0.1)
And Pygame has a Clock Class that is better than time.sleep(0.1) if you wan't to keep a framerate.

Categories