Uhh sorry for the super vague title, I have no idea whats wrong with my code either.
if event.type == pygame.K_SPACE:
run= True
There appears to be a problem when running this line, like the code is shaded a different colour on my screen, and it doesn't change run to True
This problem seems to be fixed if i delete:
def mainmenu()
and just use a while loop, however, I think it gets pretty messy and am quite hesitant to delete that.
Furthermore, when I run the mainmenu() function, it takes quite a long time to load up, a problem which I haven't had thus far and I am unsure why or how to fix it.
import pygame
import time
import random
pygame.init()
window = pygame.display.set_mode((1000,700))
White=(255,255,255)
font = pygame.font.SysFont("comicsansms", 25)
#for easier counting of lives, score here starts from 1, just simply subtract 1 from whats displayed later
score = 1
clicks = 1
lives = 3
run=False
intro=True
def mainmenu():
while intro:
window.fill((0, 0, 0))
text = font.render("Press space to start!" , True, White)
window.blit(text, (500, 350))
for event in pygame.event.get():
if event.type == pygame.QUIT:
intro = False
pygame.quit()
quit()
if event.type == pygame.K_SPACE:
run= True
class Circle():
def __init__(self, color, x, y, radius, width):
self.color = color
self.x = x
self.y = y
self.radius = radius
self.width = width
def draw(self, win, outline=None):
pygame.draw.circle(win, self.color, (self.x, self.y), self.radius, self.width)
def isOver(self, mouse):
dx, dy = mouse[0] - self.x, mouse[1] - self.y
return (dx * dx + dy * dy) <= self.radius * self.radius
circles = []
def redrawWindow():
window.fill((0, 0, 0))
for c in circles:
c.draw(window)
text = font.render("Score:" + str(score-1), True, White)
window.blit(text, (0,0))
text = font.render("Lives:" + str(lives), True, White)
window.blit(text, (900, 0))
clock = pygame.time.Clock()
FPS = 60
x = str(pygame.time.get_ticks())
current_time = 0
next_circle_time = 0
while run:
delta_ms = clock.tick()
current_time += delta_ms
if current_time > next_circle_time:
next_circle_time = current_time + 1000 # 1000 milliseconds (1 second)
r = 20
new_circle = Circle((255, 255, 255), random.randint(r, 800-r), random.randint(r, 600-r), r, r)
circles.append(new_circle)
print()
redrawWindow()
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run=False
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN:
clicks += 1
mouse = pygame.mouse.get_pos()
for circle in circles:
if circle.isOver(mouse):
score += 1
circles.pop(circles.index(circle))
lives= 3-(clicks-score)
pygame.display.update()
run is a variable in global namespace. If you want to write a variable in global namespace within a function, then you have to use the global statement, which means that the listed identifiers are to be interpreted as globals:
run=False
intro=True
def mainmenu():
global run, intro
while intro:
window.fill((0, 0, 0))
text = font.render("Press space to start!" , True, White)
window.blit(text, (500, 350))
for event in pygame.event.get():
if event.type == pygame.QUIT:
intro = False
pygame.quit()
quit()
if event.type == pygame.K_SPACE:
run = True
Related
I am making simple game about clicking circles to learn pygame. I initialize pygame and pygame.font but it gives me an error randomly when I play the game. When I close the game before I get that error it gives me a diffrent error (pygame.error: video system not initialized)
import pygame
import random
import time
#I init here
pygame.init()
pygame.font.init()
class Target():
def __init__(self, p, color):
self.visible = True
self.pos = p
self.color = color
self.startT = time.time()
def isAlive(self):
if time.time()-self.startT >= aliveTime:
global gameOver
gameOver = True
return 0
else:
if self.visible:
return 1
return 0
def colisionCheck(self, color):
if color == pygame.Color(self.color):
self.visible = False
global alive
global score
alive -= 1
score += 1
def update(self):
if self.isAlive():
global targetSize
pygame.draw.circle(screen, self.color, self.pos, targetSize)
class Circle(pygame.sprite.Sprite):
def __init__(self, pos, color, *grps):
super().__init__(*grps)
self.image = pygame.Surface((32, 32))
self.image.set_colorkey((1, 2, 3))
self.image.fill((1, 2, 3))
pygame.draw.circle(self.image, pygame.Color(color), (15, 15), 15)
self.rect = self.image.get_rect(center=pos)
running = True
gameOver = False
score = 0
frames = 0
targetSize = 20
aliveTime = 10
startAliveNum = 5
screenX = 1000
screenY = screenX*0.6
alive = startAliveNum
targets = []
screen = pygame.display.set_mode((screenX, screenY))
font = pygame.font.Font('freesansbold.ttf', 12)
player = Circle(pygame.mouse.get_pos(), 'dodgerblue', targets)
pygame.display.set_caption('My Pygame game')
pygame.display.flip()
def newTargets(ammount):
for i in range(ammount):
pos = random.randint(50, screenX-50), random.randint(50, screenY-50)
targets.append(Target(pos, (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))))
newTargets(5)
startT = time.time() + 0.000001
targetStartT = startT
while running:
if gameOver:
running = False
pygame.quit()
frames += 1
text = font.render("{:.2f}fps".format(frames/(time.time()-startT)), True, (0, 0, 0), (255, 255, 255))
##############error here (pygame.error Library not initialized)##############
text2 = font.render("{:.2f} seconds left".format(targetStartT+10-time.time()), True, (0, 0, 0), (255, 255, 255))
text3 = font.render("score: " + str(score), True, (0, 0, 0), (255, 255, 255))
rect = text.get_rect()
rect2 = text2.get_rect()
rect2.center = (rect2.width/2, rect.height*1.5)
rect3 = text3.get_rect()
rect3.center = (rect3.width/2, rect.height*1.5*1.5)
screen.fill((30, 30, 30))
screen.blit(text, rect)
screen.blit(text2, rect2)
screen.blit(text3, rect3)
player.rect.center = pygame.mouse.get_pos()
player.update()
if alive == 0:
startAliveNum += 1
newTargets(startAliveNum)
alive += startAliveNum
aliveTime += 0.5
targetStartT = time.time() + 0.000001
for i in range(len(targets)):
targets[i].update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
color = screen.get_at(pygame.mouse.get_pos())
for i in range(len(targets)):
targets[i].colisionCheck(color)
pygame.display.flip()
########error here when I close the game before It gives me the first error (pygame.error: video system not initialized)########
Could someone please help me fix the errors.
(Sory if I spelled someting incorectly)
The problem is calling pygame.quit() at the beginning of the application loop. When pygame.quit() is called, all pygame modules will not be initialized and all subsequent calls to pygame functions will fail. Because the application loop executes the statement once to the end of the loop, you get an error. Call pygame.quit() after the application loop:
while running:
if gameOver:
running = False
#pygame.quit() <--- DELETE
# your code
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
# pygame.quit() <--- DELETE
running = False # <--- INSERT
# your code
# [...]
pygame.quit() # <--- INSERT
I'm currently making a Python clicking game using Pygame. Right now, there is a coin in the center of the screen that you can click. What I want to add now, it a little green "+$10" icon that appears somewhere next to the coin whenever someone clicks it. This is what I want the game to look like whenever someone clicks the coin:
Here is the code of my coin functions:
def button_collide_mouse(element_x, element_y, x_to_remove, y_to_remove):
mouse_x, mouse_y = pygame.mouse.get_pos()
if mouse_x > element_x > mouse_x - x_to_remove and \
mouse_y > element_y > mouse_y - y_to_remove:
return True
def check_events(coin, settings):
for event in pygame.event.get():
# Change button color if mouse is touching it
if button_collide_mouse(coin.image_x, coin.image_y, 125, 125):
coin.image = pygame.image.load('pyfiles/images/click_button.png')
if event.type == pygame.MOUSEBUTTONUP:
settings.money += settings.income
else:
coin.image = pygame.image.load('pyfiles/images/click_button_grey.png')
Using my current code, how can I add that kind of effect?
See How to make image stay on screen in pygame?.
Use pygame.time.get_ticks() to return the number of milliseconds since pygame.init() was called. When the coin is clicked, calculate the point in time after that the text image has to be removed. Add random coordinates and the time to the head of a list:
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
# [...]
if event.type == pygame.MOUSEBUTTONDOWN:
if coin_rect.collidepoint(event.pos):
pos = ... # random position
end_time = current_time + 1000 # 1000 milliseconds == 1 scond
text_pos_and_time.insert(0, (pos, end_time))
Draw the text(s) in the main application loop. Remove the text when the time has expired from the tail of the list:
for i in range(len(text_pos_and_time)):
pos, text_end_time = text_pos_and_time[i]
if text_end_time > current_time:
window.blit(text, text.get_rect(center = pos))
else:
del text_pos_and_time[i:]
break
Minimal example:
import pygame
import random
pygame.init()
window = pygame.display.set_mode((400, 400))
font = pygame.font.SysFont(None, 40)
clock = pygame.time.Clock()
coin = pygame.Surface((160, 160), pygame.SRCALPHA)
pygame.draw.circle(coin, (255, 255, 0), (80, 80), 80, 10)
pygame.draw.circle(coin, (128, 128, 0), (80, 80), 75)
cointext = pygame.font.SysFont(None, 80).render("10", True, (255, 255, 0))
coin.blit(cointext, cointext.get_rect(center = coin.get_rect().center))
coin_rect = coin.get_rect(center = window.get_rect().center)
text = font.render("+10", True, (0, 255, 0))
text_pos_and_time = []
run = True
while run:
clock.tick(60)
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
if coin_rect.collidepoint(event.pos):
pos = pygame.math.Vector2(coin_rect.center) + pygame.math.Vector2(105, 0).rotate(random.randrange(360))
text_pos_and_time.insert(0, ((round(pos.x), round(pos.y)), current_time + 1000))
window.fill(0)
window.blit(coin, coin_rect)
for i in range(len(text_pos_and_time)):
pos, text_end_time = text_pos_and_time[i]
if text_end_time > current_time:
window.blit(text, text.get_rect(center = pos))
else:
del text_pos_and_time[i:]
break
pygame.display.flip()
pygame.quit()
exit()
I am trying to make my drawing game draw a circle where I drag my mouse, but the circles won't update often enough to create a smooth line. How can I fix this?
import pygame
from random import randint
width=800
height=600
pygame.init() #As necessary as import, initalizes pygame
global gameDisplay
gameDisplay = pygame.display.set_mode((width,height))#Makes window
pygame.display.set_caption('Demo')#Titles window
clock = pygame.time.Clock()#Keeps time for pygame
gameDisplay.fill((0,0,255))
class Draw:
def __init__(self):
self.color = (255, 0, 0)
def update(self, x, y):
self.x = x
self.y = y
pygame.draw.circle(gameDisplay, self.color, (self.x, self.y), (5))
end = False
down = False
Line = Draw()
while not end:
x, y = pygame.mouse.get_pos()
#drawShape()
#pygame.draw.rect(gameDisplay, (0,255,0), (10, 10, 4, 4))
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
down = True
if event.type == pygame.MOUSEBUTTONUP:
down = False
if down:
Line.update(x, y)
if event.type == pygame.QUIT:
end = True
lastx, lasty = pygame.mouse.get_pos()
pygame.display.update()
clock.tick(60)
pygame.quit()
This is what my problem looks like
I recommend to draw a line from the previous mouse position to the current mouse position. Additionally draw a dot at the start and the end of the line. That causes a round beginning and end.
Track the previous position of the mouse (lastx, lasty) and draw the line in the main application loop rather than the event loop:
e.g.:
import pygame
width, height = 800, 600
pygame.init() #As necessary as import, initalizes pygame
gameDisplay = pygame.display.set_mode((width,height)) #Makes window
pygame.display.set_caption('Demo') #Titles window
clock = pygame.time.Clock() #Keeps time for pygame
gameDisplay.fill((0,0,255))
class Draw:
def __init__(self):
self.color = (255, 0, 0)
def update(self, from_x, from_y, to_x, to_y):
pygame.draw.circle(gameDisplay, self.color, (from_x, from_y), 5)
pygame.draw.line(gameDisplay, self.color, (from_x, from_y), (to_x, to_y), 10)
pygame.draw.circle(gameDisplay, self.color, (to_x, to_y), 5)
end = False
down = False
line = Draw()
while not end:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
lastx, lasty = event.pos
down = True
if event.type == pygame.MOUSEBUTTONUP:
down = False
if event.type == pygame.QUIT:
end = True
x, y = pygame.mouse.get_pos()
if down:
line.update(lastx, lasty, x, y)
lastx, lasty = x, y
pygame.display.update()
clock.tick(60)
pygame.quit()
Can any one see what I did wrong, please? I want the block to jump but it doesnt work properly. This is my first python project so please try to explain what I did wrong so I dont do it again, thanks.
import pygame
pygame.init()
bg = pygame.image.load('bg.jpg')
class Player():
def __init__(self, x, y, height, width):
self.x = x
self.y = y
self.height = height
self.width = width
self.Jumpcount = 10
self.Isjump = False
def draw(self, window):
pygame.draw.rect(window, (255, 0, 0), (self.x, self.y, self.width, self.height))
pygame.draw.rect(window, (0, 255, 0), (self.x, self.y, self.width / 2, self.height / 2))
pygame.draw.rect(window, (0, 255, 0), (self.x + self.width / 2, self.y + self.height / 2, self.width / 2, self.height / 2))
pygame.draw.rect(window, (139, 26, 26), (0, 400 + self.height, 500, 500 - self.height))
def Jump(self, Jumping):
if Jumping:
self.Isjump = True
if self.Isjump:
if self.Jumpcount >= -10:
neg = 1
if self.Jumpcount < 0:
neg = -1
self. y = self.Jumpcount**2 * 0.25 * neg
self.Jumpcount -= 1
else:
self.Isjump = False
self.Jumpcount = 10
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption('Test')
Jumping = False
run = True
man = Player(70, 400, 40, 40)
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('123')
Jumping = True
man.Jump(Jumping)
win.blit(bg, (0, 0))
man.draw(win)
pygame.display.update()
pygame.quit()
There is no error message but when I press space it doesnt do anything.
Remove the second pygame.event.get() loop. The first loop is consuming all the events, but checks only the QUIT event and does nothing for other events. The second loop is likely empty. Do all the event checks in the first loop.
You want to have only one event loop each iteration of the main loop.
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('123')
Jumping = True
man.Jump(Jumping)
I think your problem lies in having two for loops event in pygame.event.get()
To fix this you just want to have the two if statements under one for loop like so:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
print('123')
Jumping = True
man.Jump(Jumping)
that should fix your problem.
I'm trying to have the for loop run 5 iterations of the code below it but once it runs once and i try to click the rectangle the code goes unresponsive.
I can't see why this is happening so i'm looking for some help.
def Reaction_game():
intro = True
while intro == True:
for event in pygame.event.get():
#Stops game when close is selected
if event.type == pygame.QUIT:
file=open('currentuser.txt', 'w')
file.close()
pygame.quit()
quit()
Reaction_times=[]
for x in range (5):
clicked = False
BackGround = Background("background1.png",[0,0])
screen.fill(white)
screen.blit(BackGround.image, BackGround.rect)
pygame.draw.rect(screen, black,(0,0,1000,55))
Font = pygame.font.SysFont('TitilliumWeb.ttf',72)
Label = Font.render("Get Ready:", 1, white)
screen.blit(Label, (380,0,325,75))
pygame.display.update()
time.sleep(2)
screen.blit(BackGround.image, BackGround.rect)
pygame.draw.rect(screen, black,(0,0,1000,55))
Font = pygame.font.SysFont('TitilliumWeb.ttf',72)
Label = Font.render("Go:", 1, white)
screen.blit(Label, (450,0,325,75))
pygame.display.update()
RectX = randrange(50,950)
RectY = randrange(60,513)
round_rect(screen,(RectX,RectY,75,40),(black),10,5,(white))
pygame.display.update()
TimeStart = time.time()
while clicked !=True:
mouse = pygame.mouse.get_pos()
if RectX+75 > mouse[0] > RectX and RectY+40 > mouse[1] > RectY:
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
else:
pass
Reaction_game()
I expect the code to run 5 iterations of this little reaction time game but it doesn't even get past the first loop before going unresponsive.
You have to use for event in pygame.event.get(): inside while clicked to get new events from system. Without this you have the same values in event.type and even.button.
Even pygame.mouse.get_pos() can't work correclty because it uses data created by pygame.event.get() (or similar)
If you have event MOUSEBUTTONDOWN, MOUSEBUTTONUP then you have mouse position in event.pos and you don't need pygame.mouse.get_pos()
while not clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if RectX+75 > event.pos[0] > RectX and RectY+40 > event.pos[1] > RectY:
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
EDIT:
You can keep Rectangle position and size in pygame.Rect()
RectX = randrange(50,950)
RectY = randrange(60,513)
rect = pygame.Rect(RectX, RectY, 75, 40)
and then you can use rect instead of (RectX,RectY,75,40)
round_rect(screen, rect, black , 10, 5, white)
and you can use rect to check if you clicked in rectangle rect.collidepoint(event.pos)
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if rect.collidepoint(event.pos):
TimeEnd = time.time()
ReactionTime = TimeEnd - TimeStart
Reaction_times.append(ReactionTime)
clicked = True
EDIT: working example with other changes - ie. I use pygame.time.wait() instead of time.sleep() and pygame.time.get_ticks() instead of time.time(). Both use miliseconds instead of seconds.
import pygame
import random
# --- constants ---
WHITE = (255, 255, 255)
BLACK = ( 0, 0, 0)
# --- main ---
pygame.init()
screen = pygame.display.set_mode((1000, 600))
reaction_times= []
for x in range(5):
clicked = False
screen.fill(WHITE)
pygame.draw.rect(screen, BLACK, (0, 0, 1000, 55))
font = pygame.font.SysFont(None, 72)
label = font.render("Get Ready:", 1, WHITE)
screen.blit(label, (380, 0, 325, 75))
pygame.display.update()
pygame.time.wait(2000) # 2000ms = 2s
pygame.draw.rect(screen, BLACK, (0, 0, 1000, 55))
font = pygame.font.SysFont(None, 72)
label = font.render("Go:", 1, WHITE)
screen.blit(label, (450, 0, 325, 75))
pygame.display.update()
x = random.randrange(50, 950)
y = random.randrange(60, 513)
rect = pygame.Rect(x, y, 75, 40)
pygame.draw.rect(screen, BLACK, rect)
pygame.display.update()
time_start = pygame.time.get_ticks()
while not clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
if rect.collidepoint(event.pos):
print('clicked')
time_end = pygame.time.get_ticks()
reaction_time = (time_end - time_start)/1000 # convert to seconds
reaction_times.append(reaction_time)
clicked = True
print(reaction_times)
pygame.quit()