I am trying two draw two surfaces, one on top of the other, each with a border around it. Both the top surface (topSurf) and the bottom surface (botSurf) appear on the screen.
When I attempt to draw a border around each surface with the pygame.draw.rect command, the rect on the top surface appears, but the rect on the bottom surface does not.
Why does this happen?
Here is the code:
import sys
import pygame
from pygame.locals import *
pygame.init()
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
WHITE = (255,255,255)
screen = pygame.display.set_mode((600,600))
#top surface
topRect = pygame.Rect(0,0,600,500)
topSurf = pygame.Surface((600,500))
topSurf = topSurf.convert()
topSurf.fill(BLUE)
#bottom surface
botSurf = pygame.Surface((600,100))
botRect = pygame.Rect(0,500,600,100)
botSurf = botSurf.convert()
botSurf.fill(GREEN)
#rectangle
pygame.draw.rect(topSurf,RED,topRect,10)
pygame.draw.rect(botSurf,WHITE,botRect,10)
### main game loop
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.blit(topSurf,topRect)
screen.blit(botSurf,botRect)
pygame.display.flip()
Screenshot
You're using the botRect's coordinates to draw the white rect and that means you're drawing it at the surfaces local coordinates (0, 500), outside of the area of the botSurf. You have to draw the rect at (0, 0) first and then move the rect afterwards if you also want to use it as the blit position of the surface.
botSurf = pygame.Surface((600,100))
botSurf.fill(GREEN)
botRect = pygame.Rect(0,0,600,100)
pygame.draw.rect(botSurf,WHITE,botRect,10)
botRect.y = 500
Related
I am making a program with a graph that scrolls and I just need to move a section of the screen.
If I do something like this:
import pygame
screen = pygame.display.set_mode((300, 300))
sub = screen.subsurface((0,0,20,20))
screen.blit(sub, (30,40))
pygame.display.update()
It gives the error message: pygame.error: Surfaces must not be locked during blit
I assume it means the child is locked to its parent surface or something but how else could I go about doing this?
screen.subsurface creates a surface, which reference to the original surface. From documentation:
Returns a new Surface that shares its pixels with its new parent.
To avoid undefined behaviour, the surfaces get locked. You've to .copy the surface, before you can .blit it to its source:
sub = screen.subsurface((0,0,20,20)).copy()
screen.blit(sub, (30,40))
Just don't draw to the screen surface directly. Create a Surface for each part of your game/UI, and blit each of those to the screen.
import pygame
def main():
pygame.init()
screen = pygame.display.set_mode((640, 480))
# create two parts: a left part and a right part
left_screen = pygame.Surface((400, 480))
left_screen.fill((100, 0, 0))
right_screen = pygame.Surface((240, 480))
right_screen.fill((200, 200, 0))
x = 100
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
# don't draw to the screen surface directly
# draw stuff either on the left_screen or right_screen
x += 1
left_screen.fill(((x / 10) % 255, 0, 0))
# then just blit both parts to the screen surface
screen.blit(left_screen, (0, 0))
screen.blit(right_screen, (400, 0))
pygame.display.flip()
if __name__ == '__main__':
main()
So I was testing out pygame and I wanted to draw a simple rectangle. There are no error messages when I run the code but the rectangle doesn't show up in the window. What I see is a blank white Pygame window pop up. Does anyone know why?
Currently using Python3 and Pygame 1.9.4 on my mac.
Here is my code,
import pygame
import pygame.font
pygame.init()
# Colours
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
GREEN = ( 0,255, 0)
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
# Dimensions of screen
size = (400,500)
WIDTH = 500
HEIGHT = 400
screen = pygame.display.set_mode(size)
# Loop Switch
done = False
# Screen Update Speed (FPS)
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
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
screen.fill(GREEN)
pygame.display.flip()
#Setting FPS
clock.tick(60)
#Shutdown
pygame.quit()
You do not want to fill the screen with green every 60 ticks
To fix this, simply put screen.fill(GREEN) outside of the Main loop.
The only time you want screen.fill inside your while loop, is when your adding movement into your program.
I strongly suggest you make a function called draw and draw things outside of your while loop.
I have found the problem:
first of, Glitchd is correct, but you forget to update:
import pygame
import pygame.font
pygame.init()
# Colours
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
GREEN = ( 0,255, 0)
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
# Dimensions of screen
size = (400,500)
WIDTH = 500
HEIGHT = 400
screen = pygame.display.set_mode(size)
# Loop Switch
done = False
# Screen Update Speed (FPS)
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
screen.fill(GREEN)
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
pygame.display.flip()
pygame.display.update()
#Setting FPS
clock.tick(60)
#Shutdown
pygame.quit()
U are drawing a shape and then covering it up with green, swap
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
screen.fill(GREEN)
Those 2 around
The problem is that you draw the shape and after that you 'fill' (cover) it with green, so try something like that:
screen.fill(GREEN) #first fill the screen with green
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5) #and after that draw the rectangle
The error is obvious as first you are drawing a shape then covering it with color . Your code is right but need some rearrangement.
screen.fill("your color") # First you should fill the screen with color
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5) # Then u should draw any shape
Each of the previously given answers fail to properly elaborate why this issue occurs. It is not about the order of drawing, filling operations; it is about your timing on calling the pygame.display.flip function, or shortly: updating the screen. Your code draws a rectangle, fills the screen with green, and then updates the screen. What it should have done instead is draw the rectangle, update the screen and then fill the screen with green. That way the screen is updated after you draw the rectangle before the screen is filled with green, therefore you can see it:
import pygame
import pygame.font
pygame.init()
# Colours
BLACK = ( 0, 0, 0)
WHITE = (255,255,255)
GREEN = ( 0,255, 0)
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
# Dimensions of screen
size = (400,500)
WIDTH = 500
HEIGHT = 400
screen = pygame.display.set_mode(size)
# Loop Switch
done = False
# Screen Update Speed (FPS)
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
#In each case you draw the rectangle and then fill the screen with green
pygame.draw.rect(screen,(78,203,245),(0,0,250,500),5)
pygame.display.flip()
screen.fill(GREEN)
#Setting FPS
clock.tick(60)
#Shutdown
pygame.quit()
In a nutshell, you should update after you draw the rectangle.
you should add pygame.display.update() in the while not done loop. pygame.display.update updates the screen. You have this problem because you drew all of the drawings but did not update the screen.
You should first cover the screen with green and then draw your shape because otherwise it will get covered.
I'm writing a program in pygame in which I want to draw circles on several surfaces, so that when I erase a circle (redraw it with the transparent colorkey) I get the picture that was in the layer below back. However, I seem to be stuck at an early step and can't seem to draw a circle on a surface (as opposed to the background display). Here is a minimal example:
import pygame
pygame.init()
width = 400
height = 400
screen = pygame.display.set_mode((width, height))
surf1 = pygame.Surface((width,height))
surf1.fill((0,255,0))
pygame.draw.circle(surf1, (0,0,0), (200,2000), 5)
screen.blit(surf1, (0,0))
exit = False
while not exit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit = True
pygame.display.update()
pygame.quit()
I expected to get a green surface with a black circle in the middle, but I only get a green surface. What am I doing wrong?
Thanks!
You have a typo in the coordinates for the circle, it should be
pygame.draw.circle(surf1, (0,0,0), (200,200), 5)
i.e. a 200 instead of a 2000.
I´m trying to draw a ship on the bottom-right of the screen, but it´s not appearing on the window! Coordinates seem to be off on X, Y by approximately 50 points. No matter what kind of resolution is set through pygame.display.set_mode(), the window is always smaller than the defined dimensions ( by 50 ).
External FULL HD screen is connected to the laptop through HDMI, but disconnecting it had no effect. Using Windows 10, Python 3.6.2 and Pygame 1.9.3.
Using "centerx", "bottom" to display the ship
Same as above, but substracting both "centerx" and "bottom" by 50.
import sys
import pygame
def main():
#Initialize the screen.
pygame.init()
screen = pygame.display.set_mode( ( 1024, 768 ) )
screen_rect = screen.get_rect()
bg_color = ( 235, 235, 235 )
# Load the ship surface, get its rect.
ship_image = pygame.image.load( "images/ship.bmp" )
ship_rect = ship_image.get_rect()
# TRYING TO POSITION THE SHIP TO THE BOTTOM-RIGHT OF THE SCREEN.
screen_bottom_right = screen_rect.centerx, screen_rect.bottom
while True:
for event in pygame.event.get():
if ( event == "QUIT" ):
sys.exit()
# Redraw the screen.
screen.fill( bg_color )
# Blit the ship´s image.
screen.blit( ship_image, ( screen_bottom_right ) )
pygame.display.flip()
main()
Tried searching for answers, but none of them had worked / explicitly mentioned this issue. Tutorials, which used the code didn´t substract the X/Y coordinates to obtain exactly positioned image. "0, 0" as rect drawing position works flawlessly. The bottom-right suffers from the above-mentioned issue.
Pygame blits the image so that its top left corner is positioned at the coordinates that you passed. So by passing the screen bottom as the y-coord you're telling pygame to draw the ship below the screen. To fix this you can assign the bottomright attribute of the screen_rect to the bottomright of the ship_rect and then just blit the image at the ship_rect.
import sys
import pygame
def main():
pygame.init()
screen = pygame.display.set_mode((1024, 768))
screen_rect = screen.get_rect()
bg_color = (235, 235, 235)
ship_image = pygame.Surface((40, 50))
ship_image.fill((20, 10, 100))
ship_rect = ship_image.get_rect()
ship_rect.bottomright = screen_rect.bottomright
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.fill(bg_color)
screen.blit(ship_image, ship_rect)
pygame.display.flip()
main()
pygame.Rects have a lot of other attributes that you can use as well, but keep in mind that only the topleft coords are used as the blit position:
x,y
top, left, bottom, right
topleft, bottomleft, topright, bottomright
midtop, midleft, midbottom, midright
center, centerx, centery
size, width, height
w,h
I am just starting to learn pygame graphics. I drew a circle in pygame and was wondering how I program it to change colors.
For example: it changes colors from blue to red.
I need it to keep changing colors until I close pygame and it would be nice if the colors gradually changed from one to another instead of an instant change? Any ideas how I could do this?
import pygame
pygame.init()
RED = (255, 0, 0)
BLUE = ( 0, 0,255)
BLACK = ( 0, 0, 0)
SIZE = (1000,1000)
screen = pygame.display.set_mode(SIZE)
pygame.draw.circle(screen,RED,(500,500),200)
pygame.display.flip()
pygame.time.wait(3000)
pygame.quit()
I shall progress from simple to harder, and more complex..
Simplest: A for loop that changes the color 3 times, simplest:
import pygame
pygame.init()
RED = (255,0,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
SIZE = (1000,1000)
screen = pygame.display.set_mode(SIZE)
colors = (RED, BLACK, BLUE) # tho allow you to iterate over the colors
for c in colors:
pygame.draw.circle(screen,c,(500,500),200)
pygame.display.flip()
pygame.time.wait(1000)
pygame.quit()
Medium: Now an infinite loop, that ends when you close the window..
import pygame, itertools
RED = (255,0,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
colors = (RED, BLACK, BLUE) # to allow you to iterate over the colors
SIZE = (1000,1000)
screen = pygame.display.set_mode(SIZE)
# to cycle through the colors
cycle = itertools.cycle(colors) # create an infinite series..
clock = pygame.time.Clock() # regulate fps
while True:
# handling events
for event in pygame.event.get():
if event.type == pygame.QUIT: # close window event
pygame.quit()
c = cycle.next()
pygame.draw.circle(screen,c,(500,500),200)
pygame.display.flip()
clock.tick(6) # run at maximum 6 frames per second
Hardest and most complex: This is the final one, the colors fade into the next one..
import pygame, itertools
def fade_into(c1, c2, n):
""" Give the next color to draw \n"""
"Args: c1,c2 => colors, n => int"
dif = [(c1[i]-c2[i])/float(n) for i in range(3)] # calculate the per-frame difference
return [c1[i]-dif[i] for i in range(3)] # subtract that difference
RED = (255,0,0)
BLUE = (0,0,255)
BLACK = (0,0,0)
FADE_SPEED = 80 # no of frames for shifting
colors = (RED, BLACK, BLUE) # to allow you to iterate over the colors
SIZE = (1000,1000)
screen = pygame.display.set_mode(SIZE)
# to cycle through the colors
cycle = itertools.cycle(colors)
## needed for fading
c_color = cycle.next() # RED current_color
n_color = cycle.next() # BLACK next_color
frames = FADE_SPEED
## --------------
clock = pygame.time.Clock() # regulate fps
while True:
# handling events
for event in pygame.event.get():
if event.type == pygame.QUIT: # close window event
pygame.quit()
c_color = fade_into(c_color, n_color, frames) # get next color
pygame.draw.circle(screen,map(int,c_color),(500,500),200)
pygame.display.flip()
frames -= 1
if frames == 0: # translation complete
frames = FADE_SPEED
n_color = cycle.next() # get next color
clock.tick(40) # run at maximum of 40 frames per second
If you have any doubts, please comment below..
Pygame does not have scene graph, so you need to redraw your shape in a loop and call display.flip() to update.