I'm a new programmer working on a memory game for my computer science summative.The game goes like this: the computer displays random boxes at random positions and then the user has to guess where the boxes are and click on it.
I'm basically done, except right now I'm trying to create 5 different levels that range in level of difficulty. eg level 1 will display 2 boxes and level 2 will display 5, etc. And then if the user gets through all levels they can play again. I know its a lot but I really want to get an A on this.
But right now I'm stuck because it doesn't really work until I try to close the window, and even then it only goes halfway. Any help would be appreciated.
import pygame , sys
import random
import time
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
rows = 20
columns = 20
# Set title of screen
pygame.display.set_caption("Spatial Recall")
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
coord=[]
# Create a 2 dimensional array. A two dimesional
# array is simply a list of lists.
def resetGrid():
grid = []
for row in range(rows):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(columns):
grid[row].append(0) # Append a cell
return grid
def displayAllPink(pygame):
for row in range(rows):
for column in range(columns):
color = LIGHT_PINK
pygame.draw.rect(screen,color,[(margin+width)*column + margin,(margin+height)*row+margin,width,height])
pygame.display.flip()
def displayOtherColor(pygame,grid):
coord = []
for i in range(random.randint(2,5)):
x = random.randint(2, rows-1)
y = random.randint(2, columns-1)
color = LIME
pygame.draw.rect(screen,color,[(margin+width)*y + margin,(margin+height)*x+margin,width,height])
coord.append((x,y))
grid[x][y] = 1
pygame.display.flip()
time.sleep(1)
return coord
def runGame(gameCount,coord,pygame,grid):
pygame.event.clear()
pygame.display.set_caption("Spatial Recall: Level "+ str(gameCount))
pygame.time.set_timer(pygame.USEREVENT,1000)
time = 0
#clock.tick(
# -------- Main Program Loop -----------
#Loop until the user clicks the close button.
done = False
while done==False:
event = pygame.event.wait() # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
pygame.event.clear()
print "Game ",gameCount, "ends"
elif event.type == pygame.USEREVENT:
time = time + 1
pygame.display.set_caption("Spatial Recall: Level "+ str(gameCount) + " Time: "+ str(time))
if time == 100:
done = True
pygame.display.set_caption("Time out, moving to next level")
pygame.event.clear()
return False
elif 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)
if (row,column) in coord:
print coord
coord.remove((row,column))
print coord
color = LIME
pygame.draw.rect(screen,color,[(margin+width)*column + margin,(margin+height)*row+margin,width,height])
if coord == []:
done=True
pygame.display.set_caption("Time out, moving to next level")
pygame.event.clear()
return True
else:
color = RED
pygame.draw.rect(screen,color,[(margin+width)*column + margin,(margin+height)*row+margin,width,height])
pygame.display.flip()
def startTheGame(gameCount):
grid = resetGrid()
displayAllPink(pygame)
coord = displayOtherColor(pygame,grid)
displayAllPink(pygame)
runGame(gameCount,coord,pygame,grid)
for i in range(2):
startTheGame(i+1)
pygame.quit ()
You may want to use the pygame.font module. http://pygame.org/docs/ref/font.html
First, load a font, either from a file or from one of the system font functions.
Call YourFontObject.render(your_text_string). That'll return a Surface that contains the string rendered in the given font. Note, you can't use newline (\n) characters! You'll have to do the spacing yourself.
Blit this Surface onto the screen after everything else so nothing will obscure it.
Also, you don't need the pygame parameter in your functions.
Hope this helps.
Related
I am creating a game with pygame in which the color of a letter changes when you type that letter. Like nitrotype.com. However the problem is that I don't know how to change the colour of individual letters.
I can't clear the screen and then do it because then that would change the color of the entire line.
So either I need a way to change the colour of individual letters or a way to just put single letters on the screen one at a time. However I don't know how to uniformly put the letters(such that the end sentence is centered). Please could someone help me out here. Either by telling me how to change the color of individual letters or how to put individual letters in a perfect manner and then change their color.
import pygame as pg
import pygame
pg.init()
screenHeight, screenWidth = 600, 800
gameDisplay = pg.display.set_mode((screenWidth, screenHeight))
pg.display.set_caption("Nitrotype")
black = (255, 255, 255)
white = (0, 0, 0)
gameDisplay.fill(white)
pg.display.update()
gameOn = True
with open("text.txt", "r") as f:
contents = f.read()
def msgToScreen(msg, color, size):
cur = []
strings = []
words = msg.split(" ")
for i in words:
cur.append(i)
if len(" ".join(cur)) >= 35:
strings.append(" ".join(cur))
cur = []
if cur != []:strings.append(" ".join(cur))
curY = 20
for string in strings:
font = pg.font.SysFont(None, size)
text = font.render(string, True, color)
text_rect = text.get_rect(center=(screenWidth/2, curY))
gameDisplay.blit(text, text_rect)
curY += 40
return text
textOnScreen = msgToScreen(contents, black, 50)
pg.display.update()
curIdx = 0
keyCombination = {"a":pg.K_a, "b":pg.K_b, "c":pg.K_c, "d":pg.K_d, "e":pg.K_e, "f":pg.K_f,
"g":pg.K_g, "h":pg.K_h, "i":pg.K_i, "j":pg.K_j, "k":pg.K_k, "l":pg.K_l,
"m":pg.K_m, "n":pg.K_n, "o":pg.K_o, "p":pg.K_p, "q":pg.K_q, "r":pg.K_r,
"s":pg.K_s, "t":pg.K_t, "u":pg.K_u, "v":pg.K_v, "w":pg.K_w, "x":pg.K_x,
"y":pg.K_y, "z":pg.K_z}
while gameOn:
for event in pygame.event.get():
if event.type == pg.QUIT:
gameOn = False
if event.type == pg.KEYDOWN:
if event.key == keyCombination[contents[curIdx].lower()]:
#Here is where the color of the current letter should change
curIdx += 1
pg.quit()
You can't change the color of a single letter during font rendering; you'll have to render your text letter by letter.
You can either use render() to render each letter to its own surface and blit them to your screen, but you have to calculate where each letter should go manually.
It's a little bit easier if you use the new freetype module, which has a lot of handy functions in the Font class like origin, get_rect and get_metrics which can calculate how big each letter is.
Here's a simple example I hacked together. It's not perfect but you'll get the idea.
import pygame
import pygame.freetype
from itertools import cycle
def main():
pygame.init()
screen = pygame.display.set_mode((800, 600))
# just some demo data for you to type
data = cycle(['This is an example.', 'This is another, longer sentence.'])
current = next(data)
current_idx = 0 # points to the current letter, as you have already guessed
font = pygame.freetype.Font(None, 50)
# the font in the new freetype module have an origin property.
# if you set this to True, the render functions take the dest position
# to be that of the text origin, as opposed to the top-left corner
# of the bounding box
font.origin = True
font_height = font.get_sized_height()
# we want to know how much space each letter takes during rendering.
# the item at index 4 is the 'horizontal_advance_x'
M_ADV_X = 4
# let's calculate how big the entire line of text is
text_surf_rect = font.get_rect(current)
# in this rect, the y property is the baseline
# we use since we use the origin mode
baseline = text_surf_rect.y
# now let's create a surface to render the text on
# and center it on the screen
text_surf = pygame.Surface(text_surf_rect.size)
text_surf_rect.center = screen.get_rect().center
# calculate the width (and other stuff) for each letter of the text
metrics = font.get_metrics(current)
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.KEYDOWN:
if e.unicode == current[current_idx].lower():
# if we press the correct letter, move the index
current_idx += 1
if current_idx >= len(current):
# if the sentence is complete, let's prepare the
# next surface
current_idx = 0
current = next(data)
text_surf_rect = font.get_rect(current)
baseline = text_surf_rect.y
text_surf = pygame.Surface(text_surf_rect.size)
text_surf_rect.center = screen.get_rect().center
metrics = font.get_metrics(current)
# clear everything
screen.fill('white')
text_surf.fill('white')
x = 0
# render each letter of the current sentence one by one
for (idx, (letter, metric)) in enumerate(zip(current, metrics)):
# select the right color
if idx == current_idx:
color = 'lightblue'
elif idx < current_idx:
color = 'lightgrey'
else:
color = 'black'
# render the single letter
font.render_to(text_surf, (x, baseline), letter, color)
# and move the start position
x += metric[M_ADV_X]
screen.blit(text_surf, text_surf_rect)
pygame.display.flip()
if __name__ == '__main__':
main()
Centering the text is easy using a second Surface and using the Rect class' center property.
I am new to python and Pygame. I am trying to make a Schulte table game.
Here's what the game is doing:
I have a 5 * 5 grid of total 25 pictures of numbers from 1-25.
(5*5 Schulte grid)
The number position is displayed in random order.
When you tap the correct number's picture, the number changes color. When you click on the wrong number, a sound is played to indicate the wrong click, and the number does not change color.
(Image changing colors or mouse click)
There's a start button and the restart button.
And finally, it displays the total elapsed time it took you to click all the numbers in order.
The program works as intended. Once a button is clicked, the colored number image is updated and a counter for each click is updated. But the problem is, if I click again on an already clicked number image, it keeps updating the counter.
For example, picture 1 is clicked, it turns red and now the click counter is 1. Then if I click again on the same picture 1, the program keep updating the counter. This way, if the counter reaches 25 even though I have not clicked all of the number pictures from 1-25 in order, the game will be over. I have tried to use pygame.event.set_allowed(pygame.MOUSEBUTTONDOWN), but it does not work(perhaps I don't know where in the loop to use it).
I am not sure where and how to exactly include this logic that the Mousebutton click will not update after a single click on the same picture. Please refer to the code below. Any help/tips is greatly appreciated. Thanks!
import pygame # import pygame library
import sys # import sys library
import random # import random library
import numpy as np # import numpy library
import itertools # Import the itertools library
import time # import time library
# Initialize settings
pygame.init() # Initialize pygame
size = width, height = 240, 320 # set the window size
screen = pygame.display.set_mode(size) # display the window
pygame.display.set_caption("Schulte Grid") # Give the window a name
# Image preparation
Xpts = [0, 48, 96, 144, 192]
Ypts = [0, 48, 96, 144, 192]
map = np.array(list(itertools.product(Xpts, Ypts))) # 25 picture coordinates
# load sound
wavFileName = 'sounds/fire.wav'
sndTrack = pygame.mixer.music.load(wavFileName)
# Timer text preparation
myfont = pygame.font.SysFont('Comic Sans MS', 60)
GREEN = (0, 255, 0)
BLUE = (0, 0, 128)
def ready():
global list1
list1 = [[i] for i in range(25)]
random.shuffle(list1)
# start interface
def start(start_page):
while start_page:
for event in pygame.event.get(): # Traverse all events
if event.type == pygame.QUIT: # if click to close the window, exit
sys.exit() # exit
screen.blit(pygame.image.load(
"pic/start-0.png"), (30, 190)) # show start screen
global t_x, t_y
t_x, t_y = pygame.mouse.get_pos() # Get the position of the mouse
if 30 <= t_x <= 200 and 190 <= t_y <= 250: # 18*50 #Mouse over the picture
screen.blit(pygame.image.load("pic/start-1.png"),
(30, 190)) # Get the mouse position and change color when moving to a certain position
if event.type == pygame.MOUSEBUTTONDOWN and 30 <= t_x <= 200 and 190 <= t_y <= 250:
start_page = False # start page
game_page = True # game page
global time_start # Define the global variable to start timing
time_start = time.time() # timing
pygame.display.flip() # update all display
# game interface
def gamepage(game_page):
# A variable is added here to make sure to start with the smallest number.
zero = 0
waiting_for_sleep_to_over = False
# The status of the question interface, it is guaranteed that only one question will be generated.
pic_zero = 1
while game_page:
while pic_zero:
for i in range(25): # must be 25 here
screen.blit(pygame.image.load(
"pic/pic" + str(*list1[i - 1]) + ".png"), map[i])
pic_zero = 0
for event in pygame.event.get(): # Traverse all events
if event.type == pygame.QUIT: # if click to close the window, exit
sys.exit()
for i in range(25):
# Determine the mouse position and whether it is pressed down. :
if event.type == pygame.MOUSEBUTTONDOWN and map[i][0] <= event.pos[0] <= map[i][0] + 48 and map[i][1] <= event.pos[1] <= map[i][1] + 48:
# print(i)
if int(*list1[i-1]) <= zero:
screen.blit(pygame.image.load(
"pic/qic" + str(*list1[i-1]) + ".png"), map[i]) # Display the color map
# waiting_for_sleep_to_over = True
zero = zero + 1
# if event.type == pygame.MOUSEBUTTONDOWN and map[i][0] <= event.pos[0] <= map[i][0] + 48 and map[i][1] <= event.pos[1] <= map[i][1] + 48:
# waiting_for_sleep_to_over = FALSE
# pygame.event.set_blocked(pygame.MOUSEBUTTONDOWN)
# time.sleep(0.5)
# zero = zero
# pygame.event.clear()
# pygame.event.set_allowed(pygame.MOUSEBUTTONDOWN)
print(zero)
if zero == 25:
time_end = time.time() # end timing
time_c = round(
time_end - time_start, 2) # time spent running
print('time cost:', int(time_c), 's')
textImage = myfont.render(
str(time_c) + 's', True, GREEN, BLUE)
screen.blit(textImage, (30, 250))
# screen.blit(pygame.image.load("pic/start-0.png"), (30, 210))
if event.type == pygame.MOUSEBUTTONDOWN and 30 <= t_x <= 210 and 200 <= t_y <= 250:
start_page = True
game_page = False
pygame.display.flip() # update all display
else:
pygame.mixer.music.play() # play music on error
pygame.display.flip() # update all display
# main loop
start_page = True
game_page = True
while True:
ready()
start(start_page)
gamepage(game_page)
The line if int(*list1[i-1]) <= zero: should be if int(*list1[i-1]) == zero:.
Whenever I run the program, the pygame screen will open straight away. I am trying to get the pygame screen to open once the user input has been completed, however if I change the position of screen = pygame.display.set_mode((1024, 768)), the program will not draw any lines anymore. Is there a way to have the screen open only once the user input has been collected?
import pygame
from pygame.locals import *
gray = (100,100,100)
lightgray = (200,200,200)
red = (255,0,0)
blue = (0,0,255)
p = [] #empty points array
#gets 4 control points from user input
def get_points():
#loops through 4 times to get 4 control points
for i in range(4):
while True:
#user input
p_input = input("Enter X,Y Coordinates for p" + str(i) + ":")
#splits the string into x and y coordinates
p_components = p_input.split(',')
#checks to see if user hasnt entered two coordinates
if len(p_components) != 2:
print("Missing coordinate please try again.")
p_input = input("Enter X,Y Coordinates for p" + str(i) + ":")
p_components = p_input.split(',')
#checks to see if the values can not be converted into floats
try:
x = float(p_components[0])
y = float(p_components[1])
except ValueError:
print("Invalid coordinates", p_components, "please try again.")
#appends the x and y coordinates as a 2 dimensional array
else:
p.append([float(p_components[0]), float(p_components[1])])
break
#gets parameter 't' interval from user input
def get_interval():
while True:
try:
i = int(input("Please enter an interval for the parameter t:"))
except ValueError:
print("Invalid interval, please try again")
else:
i = abs(i)
break
return i
#calculates required coordinates for plotting bezier curve.
def bezier():
result = [] #empty result array, which will store values x and y values from the bezier curve equation
get_points() #gets the 4 control points
i = get_interval() #gets the parameter 't' interval
for x in range(i+1): #i+1 so that it includes the last value
t = x/i #x/i due to python not being able to have a step value of a float, so this is a work around
x=(p[0][0]*(1-t)**3+p[1][0]*3*t*(1-t)**2+p[2][0]*3*t**2*(1-t)+p[3][0]*t**3) #calculates x coordinate
y=(p[0][1]*(1-t)**3+p[1][1]*3*t*(1-t)**2+p[2][1]*3*t**2*(1-t)+p[3][1]*t**3) #calculates y coordinate
result.append((int(x), int(y))) #appends coordinates to result array.
return result
def main():
pygame.init()
screen = pygame.display.set_mode((1024, 768))
points = bezier()
clock = pygame.time.Clock()
#draws the control points
for i in p:
pygame.draw.circle(screen, blue, (int(i[0]), int(i[1])), 4)
#draws the lines between control points
pygame.draw.lines(screen, lightgray, False, p)
#draws the bezier curve
pygame.draw.lines(screen, pygame.Color("red"), False, points, 2)
pygame.display.flip()
clock.tick(100)
if __name__ == "__main__":
main()
The window will be created as soon as you call pygame.display.set_mode. If you want to open it after the points are input, call it below bezier().
Also, put your drawing code into a while loop, otherwise you run that code only once and the program will stop afterwards.
def main():
pygame.init()
points = bezier()
screen = pygame.display.set_mode((1024, 768))
clock = pygame.time.Clock()
done = False
while not done:
for event in pygame.event.get():
# Close the window by pressing the x button.
if event.type == pygame.QUIT:
done = True
#draws the control points
for i in p:
pygame.draw.circle(screen, blue, (int(i[0]), int(i[1])), 4)
#draws the lines between control points
pygame.draw.lines(screen, lightgray, False, p)
#draws the bezier curve
pygame.draw.lines(screen, pygame.Color("red"), False, points, 2)
pygame.display.flip()
clock.tick(100)
Okay, I'am trying to create a Tom and Jerry game with the pygame library.
The game focuses on catching mice by clicking on them as they appear in their holes. The problem
is that sometimes a cat appears instead of a mouse and should the player erroneously click on the
cat (s)he looses all earned points, but the game continues.
The mouse is an image of a mouse and the cat is an image of an cat.
If you click on the mouse, you get mouse, otherwise the cat gets the points.
The code is a mess, that's because I don't know what I'am doing and just set an another event loop because then it works, because it runs after I create the mouse. It works to click on the mouse but then you click somewhere else and after that it's like you did not clicked on the mouse.
The mouse is created in a loop and is supposed to wait for 5 seconds and if you click on the mouse within these seconds then an appropriate message prints out in the console ,,Jerry clicked!" else "1 click". If you don't click on the mouse within 5 seconds a image covers the mouse so she disappears.
Now, what I'am trying to do right now is to print the message 1 click when the player does not click on anything but print 1 click jerry clicked when the player clicks on the mouse. I have a image of the mousehole and then I put the mouse on the mousehole, that is, on an another image.
This code works with one image at least:
pygame.init()
width=350;
height=400
screen = pygame.display.set_mode( (width, height ) )
pygame.display.set_caption('clicked on image')
redSquare = pygame.image.load("images/red-square.png").convert()
x = 20; # x coordnate of image
y = 30; # y coordinate of image
screen.blit(redSquare , ( x,y)) # paint to screen
pygame.display.flip() # paint screen one time
running = True
while (running):
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
x, y = event.pos
if redSquare.get_rect().collidepoint(x, y):
print('clicked on image')
#loop over, quite pygame
pygame.quit()
My problem is that, when I click on the mouse and then I don't click on the mouse I can't click on the mouse again at another position.
So what's wrong? What I'am doing wrong here?
Here is my code:
import pygame
from pygame import *
from random import *
init()
run = True
screen = (800,800)
screen = display.set_mode(screen)
xpos = 0
ypos = 0
mouseorcatxpos = 5
mouseorcatypos = 0
mousehole = image.load("mousehole.png").convert()
cat = image.load("tom.png")
jerry = image.load("jerry.png")
def makeholes():
global ypos
global xpos
for holey in range(1,9):
for holex in range(1,9):
screen.blit(mousehole,(xpos,ypos))
display.flip()
xpos += 100
ypos += 100
xpos = 0
def mouseorcat():
global xpos
mouseorcatxpos = 5
ypos = 0
for mousecaty in range(1,9):
pygame.event.pump()
for mousecatx in range(1,9):
randommouse = randint(1, 3)
randomcat = randint(1, 10)
if(randommouse == 2):
screen.blit(jerry, (mouseorcatxpos, ypos))
display.flip()
for event in pygame.event.get():
if (event.type == MOUSEBUTTONDOWN):
if jerry.get_rect().collidepoint(xpos, ypos) == False:
print("l clicked!")
x, y = event.pos
if jerry.get_rect().collidepoint(xpos, y):
print("JERRY CLICKED!!")
x, y = event.pos
print(x, y)
time.wait(5000)
#screen.blit(mousehole, (mouseorcatxpos - 5, ypos))
display.flip()
elif(randomcat == 2):
screen.blit(cat, (mouseorcatxpos, ypos))
display.flip()
time.wait(1500)
screen.blit(mousehole, (mouseorcatxpos-5, ypos))
display.flip()
mouseorcatxpos += 100
mouseorcatxpos = 0
ypos += 100
makeholes()
while run == True:
for event in pygame.event.get():
mouseorcat()
if event.type == QUIT:
run = False
I rewrote your game to show you how I would do it.
To keep track of the time and to limit the framerate I used a pygame.time.Clock and a timer variable. The clock returns the time in milliseconds since clock.tick was called the last time, which is used to increase the timer variable. The cat just replaces the mouse after two seconds and the mouse is set to a new position. I use pygame.Rects to store the positions, but you could also use lists or tuples.
import sys
import random
import pygame
pygame.init()
size = (800, 800)
screen = pygame.display.set_mode(size)
# Images replaced by pygame.Surface. Do that too
# in the future before you post your code.
mousehole = pygame.Surface((40, 40)).convert()
mousehole.fill(pygame.Color(30, 30, 30))
cat = pygame.Surface((40, 40)).convert()
cat.fill(pygame.Color(110, 110, 130))
jerry = pygame.Surface((40, 40)).convert()
jerry.fill(pygame.Color(190, 130, 0))
# Create the background image and blit the holes.
background = pygame.Surface(size).convert()
for holey in range(8):
for holex in range(8):
background.blit(mousehole, (holex*100, holey*100))
def new_position():
"""Return a random position between 0-700 in steps of 100."""
return (random.randrange(0, 701, 100), random.randrange(0, 701, 100))
def main():
fps = 30
clock = pygame.time.Clock()
jerry_rect = jerry.get_rect() # Stores jerry's position and size.
jerry_rect.topleft = new_position() # New random position.
# The cat is outside of the screen first.
cat_rect = cat.get_rect(topleft=(-100, -100))
points = 0
timer = 0
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if jerry_rect.collidepoint(event.pos):
points += 1
print('Jerry caught! Points:', points)
timer = 0
jerry_rect.topleft = new_position()
else:
print('Missed. Points:', points)
# Run logic.
timer += clock.tick(fps) / 1000 # timer + seconds since last tick.
if timer > 2: # Cat catches mouse after 2 seconds.
cat_rect.topleft = jerry_rect.topleft
jerry_rect.topleft = new_position()
timer = 0
points = 0
print('Tom caught Jerry.')
# Draw.
# Clear the screen by blitting the bg.
screen.blit(background, (0, 0))
screen.blit(jerry, jerry_rect)
screen.blit(cat, cat_rect)
pygame.display.flip()
if __name__ == '__main__':
main()
pygame.quit()
sys.exit()
Side notes:
Don't use star imports (from module import *), because that can make code harder to read. If you want you can use from pygame.locals import *, if it's the only star import.
Don't use global variables, because they can make code harder to read, understand and maintain. Pass variables to functions as arguments and then return the result.
Update: Some notes about your program:
The first big problem is that your game has two event loops and the important one is deeply nested inside of two other for loops and a if. The event loop should be directly under the main while loop (one indentation level (when you have more experience you can put it into a function or class method)).
The two for loops seem to have the purpose to let the code run until randommouse or randomcat are 2. To run code until a condition is met is the purpose of a while loop. But in this case you should better just pick a random number and write the if/elif conditions so that they always apply. For example, you want a 2/3 chance for mouse and 1/3 for a cat,
random_number = random.randint(1, 3)
if random_number < 3:
print("2/3 probability. It's a mouse")
else:
print("1/3 probability. It's a cat")
Or use random.choice with a list:
>>> random.choice(['mouse', 'mouse', 'cat'])
'mouse'
time.wait(5000) shouldn't be used because the game just hangs in this time. You can't even close the window. Limit the framerate and get the time since the last tick with a pygame.time.Clock.
pygame.event.pump() is not needed.
If you call get_rect() without an argument, the rect is positioned at (0, 0).
if jerry.get_rect().collidepoint(xpos, y):
That's the reason why clicking on jerry only works in the top row, and because you use the global xpos here. Since xpos is 0, the whole top row counts as Jerry.
You can pass coordinates to get_rect like so (you can also use center or other args instead of topleft):
jerry_rect = jerry.get_rect(topleft=(50, 100))
I'm sorry but I don't think I can simply fix your code. I've tried it several times, but I always end up re-writing it completely.
I begin by extracting the event loop out of the two nested for loops, then remove these loops, create rects for the mouse and cat, fix the collision detection, add a timer and so on. Take a close look at my example and try to rewrite your game in a similar way, and keep asking questions if you don't understand something.
I'm a new programmer working on a memory game for my computer science summative.The game goes like this: the computer displays random boxes at random positions and then the user has to guess where the boxes are and click on it.
I'm basically done, except right now I'm trying to create like 5 different levels that range in level of difficulty. eg level 1 will display like 2 boxes and level 2 will display like 5, etc. And then if the user gets through all levels they can play again. I know its a lot but I really want to get an A on this.
But right now I'm stuck because it doesnt really work until I try to close the window, and even then it only goes halfway. I'm thinking its how I defined the functions but I'm not to certain.
Any help would be appreciated.
import pygame , sys
import random
import time
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
rows = 20
columns = 20
# Set title of screen
pygame.display.set_caption("Spatial Recall")
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
coord=[]
# Create a 2 dimensional array. A two dimesional
# array is simply a list of lists.
def resetGrid():
grid = []
for row in range(rows):
# Add an empty array that will hold each cell
# in this row
grid.append([])
for column in range(columns):
grid[row].append(0) # Append a cell
return grid
def displayAllPink(pygame):
for row in range(rows):
for column in range(columns):
color = LIGHT_PINK
pygame.draw.rect(screen,color,[(margin+width)*column + margin,(margin+height)*row+margin,width,height])
pygame.display.flip()
def displayOtherColor(pygame,grid):
coord = []
for i in range(random.randint(2,5)):
x = random.randint(2, rows-1)
y = random.randint(2, columns-1)
color = LIME
pygame.draw.rect(screen,color,[(margin+width)*y + margin,(margin+height)*x+margin,width,height])
coord.append((x,y))
grid[x][y] = 1
pygame.display.flip()
time.sleep(1)
return coord
def runGame(gameCount,coord,pygame,grid):
pygame.event.clear()
pygame.display.set_caption("Spatial Recall: Level "+ str(gameCount))
pygame.time.set_timer(pygame.USEREVENT,1000)
time = 0
#clock.tick(
# -------- Main Program Loop -----------
#Loop until the user clicks the close button.
done = False
while done==False:
event = pygame.event.wait() # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
pygame.event.clear()
print "Game ",gameCount, "ends"
elif event.type == pygame.USEREVENT:
time = time + 1
pygame.display.set_caption("Spatial Recall: Level "+ str(gameCount) + " Time: "+ str(time))
if time == 100:
done = True
pygame.display.set_caption("Time out, moving to next level")
pygame.event.clear()
return False
elif 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)
if (row,column) in coord:
print coord
coord.remove((row,column))
print coord
color = LIME
pygame.draw.rect(screen,color,[(margin+width)*column + margin,(margin+height)*row+margin,width,height])
if coord == []:
done=True
pygame.display.set_caption("Time out, moving to next level")
pygame.event.clear()
return True
else:
color = RED
pygame.draw.rect(screen,color,[(margin+width)*column + margin,(margin+height)*row+margin,width,height])
pygame.display.flip()
def startTheGame(gameCount):
grid = resetGrid()
displayAllPink(pygame)
coord = displayOtherColor(pygame,grid)
displayAllPink(pygame)
runGame(gameCount,coord,pygame,grid)
for i in range(2):
startTheGame(i+1)
pygame.quit ()
the main problem why it is not working at the moment is:
your globals rows and columns are set to 20 but your board has only 9 fields, this is why most randomly selected coords are off the board
then, you do not control that the same coord is chosen 2 times.
in general, I would advise choosing better names, especially for displayOtherColor which assembles your target coordinates for each level.
for your question how to display score, I would propose setting it as caption, as you are already doing with the running time.