How do I display text in a grid-like structure in Pygame? - python

I'm new to pygame and currently I'm working on creating a memory game where the computer displays boxes at random positions for like a second and then the user has to click on where he/she thinks those boxes are. It's kind of like this game:
However I'm not really sure how to make the computer display the boxes with like a letter or symbol e.g. 'T' or '%'. (I've already made the grid).
Could anyone please help? It would be really appreciated.
import pygame
size=[500,500]
pygame.init()
screen=pygame.display.set_mode(size)
# Colours
LIME = (0,255,0)
RED = (255, 0, 0)
BLACK = (0,0,0)
PINK = (255,102,178)
SALMON = (255,192,203)
WHITE = (255,255,255)
LIGHT_PINK = (255, 181, 197)
SKY_BLUE = (176, 226, 255)
screen.fill(BLACK)
# Width and Height of game box
width=50
height=50
# Margin between each cell
margin = 5
# Create a 2 dimensional array. A two dimesional
# array is simply a list of lists.
grid=[]
for row in range(20):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(20):
grid[row].append(0) # Append a cell
# Set row 1, cell 5 to one. (Remember rows and
# column numbers start at zero.)
grid[1][5] = 1
# Set title of screen
pygame.display.set_caption("Spatial Recall")
#Loop until the user clicks the close button.
done=False
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while done==False:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
if event.type == pygame.MOUSEBUTTONDOWN:
# User clicks the mouse. Get the position
pos = pygame.mouse.get_pos()
# Change the x/y screen coordinates to grid coordinates
column=pos[0] // (width+margin)
row=pos[1] // (height+margin)
# Sete t hat location to zero
grid[row][column]=1
print("Click ",pos,"Grid coordinates: ",row,column)
# Draw the grid
for row in range(10):
for column in range(10):
color = LIGHT_PINK
if grid[row][column] == 1:
color = RED
pygame.draw.rect(screen,color,[(margin+width)*column+margin,(margin+height)*row+margin,width,height])
# Limit to 20 frames per second
clock.tick(20)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
pygame.quit ()

In order to display text, you have to go through a series of steps. First you will want to get a font by using the command `pygame.font.Font(font name, size). For example:
arialfont=pygame.font.Font('arial', 12)
All available fonts can be gotten from the command pygame.font.get_fonts(). Remember to initialize pygame (pygame.init()) before any of this.
Next, you will have to use the Font.render(text, antialias, color, background=None). For example:
text=arialfont.render('Hello World!', True, (0, 0, 0))
This will return a surface. You can use it just like you would any other surface. Use text.get_rect() to get its rect, then reposition the rect to put it where you want it to be, and blit it to the window. If you don't know anything about surface objects, just ask me.
Here is a working code.
import pygame, sys
pygame.init()#never forget this line
window=pygame.display.set_mode((100, 100))
font=pygame.font.SysFont('arial', 40)
text=font.render('#', True, (0, 0, 0))
rect=text.get_rect()
window.fill((255, 255, 255))
window.blit(text, rect)
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()

Related

How do you clear sprites in Pygame?

Pygame has the method clear for the Group class which is used to group sprites together. When I call clear on my Group object I can successfully clear the images of all my sprites in that group, but the hitboxes of my sprites remain. I was wondering if there is another way to remove both my sprite's image AND the rectangle hitbox without destroying the sprite object.
You should check mouse position with elements in group and kill() element to remove from group. After that you can use clean() to remove all elements from screen and draw() again to redraw only elements which are still in group
x, y = pygame.mouse.get_pos()
for item in my_group:
if item.rect.collidepoint(x, y):
print("Collision detected")
item.kill()
my_group.clear(screen, background)
my_group.draw(screen)
I created two elements in group so you will see difference if you remove draw() after clear() - it will remove all elements from screen
import pygame
# --- constants ---
# Define some colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
SIZE = (700, 500)
# --- classes ---
class Block(pygame.sprite.Sprite):
# Constructor. Pass in the color of the block,
# and its x and y position
def __init__(self, color, width, height):
# Call the parent class (Sprite) constructor
super().__init__()
# Create an image of the block, and fill it with a color.
# This could also be an image loaded from the disk.
self.image = pygame.image.load("Obrazy/images/square-1.png").convert()
# Fetch the rectangle object that has the dimensions of the image
# Update the position of this object by setting the values of rect.x and rect.y
self.rect = self.image.get_rect()
# --- functions ---
# empty
# --- main ---
pygame.init()
# Set the height and width of the screen
screen = pygame.display.set_mode(SIZE)
pygame.display.set_caption("Testing Screen")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
my_block1 = Block(WHITE, 20, 20)
my_block2 = Block(WHITE, 20, 20)
my_block2.rect.x = 100
my_group = pygame.sprite.Group()
my_group.add(my_block1)
my_group.add(my_block2)
background = pygame.Surface(SIZE)
screen.fill(BLACK)
#screen.blit(background, (0,0))
my_group.draw(screen)
# -------- Main Program Loop -----------
while not done:
# Set the screen background
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = pygame.mouse.get_pos()
for item in my_group:
if item.rect.collidepoint(x, y):
print("Collision detected")
item.kill()
my_group.clear(screen, background)
my_group.draw(screen)
# Limit to 60 frames per second
clock.tick(60)
#my_group.clear(screen, background)
#my_group.draw(screen)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
BTW: in Python 3 you can use
super().__init__()
instead of
pygame.sprite.Sprite.__init__(self)

Pygame drawing not showing in Pygame window

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.

pyGame image scale does not work as expected

I am new into Python and pyGame and i have a problem with scaling an image.
I want to zoom an image in pygame.
The pygame documentation claims that
pygame.transform.scale()
should scale to a new resolution.
But in my example below it does not work - it crops the image instead of resizing it!?
What am i doing wrong?
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = pic.get_rect()
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, pic_position_and_size)
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.scale(pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()
pygame.transform.scale() does not work very well for your case. If you shrink a Surface by such a small amount, the algorithm just crops the last column and row of pixels. If you now repeat this process over and over again with the same Surface, you get the strange behaviour you see.
A better approach would be to keep a copy of your original Surface around, and use that for creating the scaled image. Also, using smoothscale instead of scale may also lead to a better effect; it's up to you if you want to use it.
Here's a "fixed" version of your code:
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
org_pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = org_pic.get_rect()
pic = pygame.transform.scale(org_pic, pic_position_and_size.size)
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, (0,0))
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.smoothscale(org_pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()

Basic Pygame Graphics

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.

Different colors for shapes through iterations in Python / Pygame?

I'm new to stackoverflow, but was hoping for a little insight from more advanced programmers. I am switching majors to Computer Science next semester and am taking an intro class learning some beginner's Python programming. I have already finished the program below (the assignment was to make a program that draws ovals on the window surface by filling in some of the professor's code, not too bad at all) but I wanted to add a little something extra: As you can see, I have the color of the ovals set to be random, but it stays the same until the program is restarted entirely i.e. all of the ovals are that particular color for the length of the program. With the code written the way it is, I can't figure out a way to get the color to change for each oval. Keep in mind, this is all for kicks, but if anyone's feeling especially helpful or creative, I'm curious to see what you have to say. Let me know if I can expound on anything. Thanks!
import pygame, random, sys
WINDOWWIDTH = 700
WINDOWHEIGHT = 700
BACKGROUNDCOLOR = (150,160,100)
#A different color every run
OVAL_COLOR = (random.randint (0,255),random.randint (0,255),
random.randint (0,255))
pygame.init()
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption("Mobile Ovals")
#The draw variable is used later to indicate the mouse is still pressed
ovals = []
completedOvals = []
finished = False
draw = False
startXY = (-1, -1)
while not finished:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYUP and
event.key == pygame.K_ESCAPE):
finished = True
elif event.type == pygame.KEYDOWN:
pressed = pygame.key.get_pressed()
if pressed[pygame.K_F4] and (pressed[pygame.K_LALT] or
pressed[pygame.K_RALT]):
finished = True
elif event.type == pygame.MOUSEBUTTONDOWN:
startXY = event.pos
draw = True
elif event.type == pygame.MOUSEBUTTONUP:
draw = False
for oval in ovals:
completedOvals.append (oval)
if draw == True:
del ovals [:]
#The above function ensures only one oval is onscreen at any given time
endXY = event.pos
width = (abs(endXY[0]-startXY[0]))
height = (abs(endXY[1]-startXY[1]))
#The code below allows the user to drag any direction
if endXY[0] < startXY[0]:
left = endXY[0]
else:
left = startXY[0]
if endXY[1] < startXY[1]:
top = endXY[1]
else:
top = startXY[1]
ovals.append (pygame.Rect (left, top, width, height))
windowSurface.fill(BACKGROUNDCOLOR)
for oval in ovals:
pygame.draw.ellipse(windowSurface, OVAL_COLOR, oval)
for completedOval in completedOvals:
pygame.draw.ellipse(windowSurface, OVAL_COLOR, completedOval)
pygame.display.update()
pygame.quit()
Your problem is quite simple. You set OVAL_COLOR once. But every time you make reference to the variable OVAL_COLOR, you're not creating a new random color, you're re-using the RGB color that was randomly generated when you created the variable.
Now, the way your program is structured, you maintain a list of all complete ovals that you're re-drawing every time the draw variable is set to true. If you place the OVAL_COLOR variable inside the for loop, you will update the color with every mouse movement, changing the color of the oval being drawn, as well as the color of all the old ovals being re-drawn.
The solution to have a new random oval color is to set the variable OVAL_COLOR when the mouse button goes down. That way, the oval color won't change as you drag the mouse to adjust the oval. But, given the current structure of the program, you'll need to save the oval colors assigned to completed ovals, or you'll still have the oval color change each time.
When the mouse button is pressed down, we want a new random color for our circle. Generate a random value, which will be used every time the circle is re-drawn.
elif event.type == pygame.MOUSEBUTTONDOWN:
startXY = event.pos
OVAL_COLOR = (random.randint (0,255),random.randint (0,255),
random.randint (0,255))
draw = True
When the mouse button is released, save the coordinates for the oval, along with the color that it was drawn with.
elif event.type == pygame.MOUSEBUTTONUP:
draw = False
# print len(ovals) # (always ==1)
completedOvals.append ((ovals[-1], OVAL_COLOR))
When we iterate through these completed ovals, draw them with the same color each time.
for (completedOval, color) in completedOvals:
pygame.draw.ellipse(windowSurface, color, completedOval)
Create a simple Oval() class, that contains it's color, and size.
import pygame
from pygame.locals import *
class Oval(object):
"""handle, and draw basic ovals. stores Rect() and Color()"""
def __init__(self, startXY, endXY):
self.color = Color(random.randint(0,255), random.randint(0,255), random.randint(0,255))
self.rect = Rect(0,0,1,1)
self.coord_to_oval(startXY, endXY)
def draw(self):
pygame.draw.ellipse(windowSurface, self.color, self.rect)
def coord_to_oval(self, startXY, endXY):
width = (abs(endXY[0]-startXY[0]))
height = (abs(endXY[1]-startXY[1]))
#The code below allows the user to drag any direction
if endXY[0] < startXY[0]:
left = endXY[0]
else:
left = startXY[0]
if endXY[1] < startXY[1]:
top = endXY[1]
else:
top = startXY[1]
self.rect = Rect(left, top, width, height)
# main loop
while not finished:
for event in pygame.event.get():
# events, and creation:
# ... your other events here ...
elif event.type == MOUSEBUTTONDOWN:
startXY = event.pos
draw = True
elif event.type ==MOUSEBUTTONUP:
# on mouseup, create instance.
endXY = event.pos
oval_new = Oval(startXY, endXY)
completedOvals.append(oval_new)
# draw them:
for oval in ovals:
oval.draw()
for oval in completedOvals:
oval.draw()
I mostly left out your non-completed ovals. Was that to show the size before clicking?

Categories

Resources