I was following this tutorial on how to make a typing speed calculator using pygame and whenever I run the code everything renders out as it should but when I try clicking on the text field to input some text it just freezes and nothing happens. I tried to search online or watch tutorials but everything came up empty.
import sys
import time
import random
import pygame
from pygame.locals import *
"""Python Script for a typing speed test game"""
class Game(object):
def __init__(self):
self.h = 720
self.w = 1280
self.reset = True
self.active = False
self.word = ""
self.input_text = ""
self.time_start = 0
self.total_time = 0
self.accuracy = "0%"
self.wpm = 0
self.results = "Speed(WPM):0 Accuracy:0% Time:0"
self.end = False
self.head_col = (255,213,102)
self.text_col = (255,255,255)
self.result_color = (53,209,29)
pygame.init()
self.open_image = pygame.image.load("splash.jpg")
self.open_image = pygame.transform.scale(self.open_image, (self.w,self.h))
self.background = pygame.image.load("background.jpg")
self.background = pygame.transform.scale(self.background, (self.w, self.h))
self.screen = pygame.display.set_mode((self.w,self.h))
pygame.display.set_caption = "Type Speed Test"
def draw_text(self, screen, msg, y, fsize, color):
font = pygame.font.SysFont("consolas", fsize)
text = font.render(msg, 1, color)
text_rect = text.get_rect(center=(self.w/2, y))
screen.blit(text, text_rect)
pygame.display.update()
def get_sentences(self):
f = open("sentences.txt").read()
sentence = f.split("\n")
sentences = random.choice(sentence)
return sentences
def show_results(self, screen):
if(not self.end):
#Calculate Time
self.total_time = time.Time() - self.time_start
#Calcualte Accuracy
count = 0
for i,c in enumarate(self.word):
try:
if self.input_text[i] == c:
count += 1
except:
pass
self.accuracy = count/len(self.word)*100
#Calculate wpm
self.wpm = len(self.input_text)*60/(5*self.total_time)
self.end = True
print(self.total_time)
self.results = "Time:" + str(round(self.total_time))
+ " secs Accuracy: " + str(round(self.accuracy)) + "%"
+ " WPM: " + str(round(self.wpm))
#restart icon
self.time_img = pygame.image.load("icon.png")
self.time_img = pygame.transform.scale(self.time_img, (80,320))
#screen.blit(self.time_img, (80,320))
screen.blit(self.time_img, (self.w/2-75, self.h-140))
self.draw_text(screen, "Reset", self/h - 70, 26, (100,100,100))
print(self.results)
pygame.display.update()
def run(self):
self.reset_game()
self.running=True
while(self.running):
clock = pygame.time.Clock()
self.screen.fill((0,0,0), (50,250,650,50))
pygame.draw.rect(self.screen,self.head_col, (50,250,650,50), 2)
# update the text of user input
self.draw_text(self.screen, self.input_text, 274, 26,(250,250,250))
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT:
self.running = False
sys.exit()
elif event.type == pygame.MOUSEBUTTONUP:
x,y = pygame.mouse.get_pos()
# position of input box
if(x>=50 and x<=650 and y>=250 and y<=300):
self.active = True
self.input_text = ''
self.time_start = time.time()
# position of reset box
if(x>=310 and x<=510 and y>=390 and self.end):
self.reset_game()
x,y = pygame.mouse.get_pos()
elif event.type == pygame.KEYDOWN:
if self.active and not self.end:
if event.key == pygame.K_RETURN:
print(self.input_text)
self.show_results(self.screen)
print(self.results)
self.draw_text(self.screen, self.results,350, 28, self.RESULT_C)
self.end = True
elif event.key == pygame.K_BACKSPACE:
self.input_text = self.input_text[:-1]
else:
try:
self.input_text += event.unicode
except:
pass
pygame.display.update()
clock.tick(60)
def reset_game(self):
self.screen.blit(self.open_image, (0,0))
pygame.display.update()
time.sleep(1)
self.reset=False
self.end = False
self.input_text=''
self.word = ''
self.time_start = 0
self.total_time = 0
self.wpm = 0
# Get random sentence
self.word = self.get_sentences()
if (not self.word): self.reset_game()
#drawing heading
self.screen.fill((0,0,0))
self.screen.blit(self.background,(0,0))
msg = "Typing Speed Test"
self.draw_text(self.screen, msg,80, 80,self.head_col)
# draw the rectangle for input box
pygame.draw.rect(self.screen,(255,192,25), (50,250,650,50), 2)
# draw the sentence string
self.draw_text(self.screen, self.word,200, 28,self.text_col)
pygame.display.update()
Game().run()
How can this be fixed?
Your never handeling KEYDOWN Events. because the else if statement is indented to far.
You should change the following.
class Game(object):
...
def run(self):
...
while(self.running):
...
for event in pygame.event.get():
if event.type == QUIT:
...
elif event.type == pygame.MOUSEBUTTONUP:
...
elif event.type == pygame.KEYDOWN:
...
in to this:
class Game(object):
...
def run(self):
...
while(self.running):
...
for event in pygame.event.get():
if event.type == QUIT:
...
elif event.type == pygame.MOUSEBUTTONUP:
...
elif event.type == pygame.KEYDOWN:
...
In Game.reset_game you recusively call Game.reset_game() with no exit.
Remove the call to self.reset_game so the game can be reset.
You also sleep for 1 second in reset_game without listening to events. This will make the pygame window seem inresponsive.
And it lets the process take 1000 seconds or ~ 17 minutes before the RecursionError is triggerd from recursively calling reset_game. Rather then seconds.
Related
I made a background music ingame, i put a volume muted & unmuted sprite and made it clickable,
When you mute the music, i want screen.blit(unmute) to disappear.
Source Code:
...
x = 0
pygame.mixer.music.load("soundtrack.wav")
volume = pygame.image.load("volume.png")
mute = pygame.image.load("mute.png")
resized_volume = pygame.transform.scale(volume, (100, 100))
resized_mute = pygame.transform.scale(mute, (100,100))
pygame.mixer.music.play(-1,0.0)
while Loop: # main game loop
...
if event.type == MOUSEBUTTONDOWN:
if event.button == 1: # 1 == left
vol_rect = volume.get_rect(topleft = (700,500))
if vol_rect.collidepoint(event.pos):
x += 1
if x > 2:
x = 1
if x == 1:
screen.blit(mute,(700,500))
pygame.mixer.music.pause()
else:
if x == 2:
screen.blit(volume, (700,500))
pygame.mixer.music.unpause()
...
pygame.quit()
sys.exit()
You have to redraw the scene in every frame. Draw the sprites depending on the value of the variable x. e.g.:
while Loop: # main game loop
# [...]
if event.type == MOUSEBUTTONDOWN:
if event.button == 1: # 1 == left
# [...]
# [...]
if x == 0:
# [...] draw something different
elif x == 1:
screen.blit(mute,(700,500))
elif x == 2:
screen.blit(volume, (700,500))
# [...]
I didn't try but I hope it works:
class MuteUnmute_Button:
def __init__(self):
self.x = 500
self.y = 400
self.state = True
self.mute_image = pygame.image.load("mute_image.png")
self.unmute_image = pygame.image.load("unmute_image.png")
self.image = mute_image
self.screen = screen
def redraw(self):
self.screen.blit(self.image,(self.x,self.y))
def checkCollision(self):
rect = self.image.get_rect()
return rect.collidepoint(pygame.mouse.pos)
def changeImage(self):
if self.state:
self.image = self.mute_image
else:
self.image = self.unmute_image
mute_unmute_button = MuteUnmuteButton()
while Loop:
for event in pygame.event.get():
if event.type == MOUSEBUTTONDOWN:
if event.button == 1:
if mute_unmute_button.checkCollision():
if mute_unmute_button.state:
mute_unmute_button.state = False
mute_unmute_button.changeImage()
pygame.mixer.music.pause()
else:
mute_unmute_button.state = True
mute_unmute_button.changeImage()
pygame.mixer.music.unpause()
screen.fill((255,255,255)) #Fills background
mute_unmute_button.redraw()
pygame.display.flip()
I gave a example, you can change code for your program.
It works perfectly if I do not add it in a class, but if I do it does not respond, I have tried using pygame.update, as pygame.event.pump/get and even jumbling were event should start from, still the problem persists. What am I doing wrong?Code below
.
.
class start_game:
def __init__(self,path,width = 400,height = 600):
self.width = width
self.height = height
self.head = None
self.running = False
self.path = path
pygame.init()
pygame.mixer.init()
self.background = load_img(self.path + '\AnimatedStreet.png')
self.enemy = pygame.image.load(self.path + '\Enemy.png')
self.backg0_pos = [0,0]
self.screen = pygame.display.set_mode((self.width,self.height))
def _run(self):
self.running = True
while self.running:
#pygame.event.pump()
self.screen.fill([0,0,0])
self.screen.blit(self.background, self.backg0_pos)
pygame.display.flip()
pygame.display.update()
self.backg0_pos[1] += 1
self._init_controls()
return
def _init_controls(self):
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_RIGHT:
self.player_pos[0] += 5
if event.key == K_q:
pygame.quit()
return
a = start_game(path)
a._run()
The error was the return function put inside of the while loop caused it stop.
The solution was putting the return function inside of the run function.
I want to view my blit() however once i add the line self.screen_dim.fill([255, 255, 255])
pygame.display.update() it overlaps
def __init__(self):
self.width = 500
self.height = 500
self.screen_dim = pygame.display.set_mode((self.width, self.height))
self.mole = pygame.image.load("mole.png")
self.mole_hit = pygame.image.load("mole-hit.png")
I am confused on how to get my pygame screen the images within that function is working however it overlaps if i added a new background color
def start(self):
stat = True
num_display = 1
x_array = []
y_array = []
for i in self.mole_pos:
x_array.append(i[0])
y_array.append(i[1])
while stat:
Rand_Pos = random.randint(0, 8)
if num_display == 1:
self.screen_dim.blit(self.mole, (x_array[Rand_Pos], y_array[Rand_Pos]))
for Event in pygame.event.get():
if Event.type == pygame.QUIT:
stat = False
if self.mouse_clicked(mouse.get_pos(), self.mole_pos[Rand_Pos]):
num_display = 0
self.screen_dim.blit(self.mole_hit, (x_array[Rand_Pos], y_array[Rand_Pos]))
continue
pygame.display.flip()
This ahs nothing to to with class. It is just a matter of Indentation. You have to draw self.mole_hit in the application loop rather than the event loop:
def start(self):
# [...]
while stat:
# [...]
for Event in pygame.event.get():
if Event.type == pygame.QUIT:
stat = False
#<--| INDENTATION
if self.mouse_clicked(mouse.get_pos(), self.mole_pos[Rand_Pos]):
num_display = 0
self.screen_dim.blit(self.mole_hit, (x_array[Rand_Pos], y_array[Rand_Pos]))
pygame.display.flip()
I want to have my background alternate between night and day (sprites) every 15 seconds or so, but I want this to happen only while the game is running (True), I've placed it in every place in my while loop, can't seem to get it going. The code we're looking at is the following:
if event.type == BACKCHANGE:
screen.blit(back_change,(0,0))
else:
screen.blit(bg_image,(0,0))
Here's how it fits into my game:
import pygame, sys, time, random
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((500, 800))
pygame.display.set_caption('FALLING MAN')
#Game elements
gravity = 0.15
mov_of_man_x = 0
mov_of_man_y = 0
right_mov = 50
left_mov = 50
game_active = True
#day background
bg_image = pygame.image.load("/Users/apple/Downloads/Python Projects/Climbing_Game/bckwall.jpg").convert()
bg_image = pygame.transform.scale(bg_image,(500, 900))
#night background
bg_image2 = pygame.image.load("/Users/apple/Downloads/Python Projects/Climbing_Game/bckwall2.jpg").convert()
bg_image2 = pygame.transform.scale(bg_image2,(500, 900))
#background swap
back_changer = [bg_image, bg_image2]
back_change = random.choice(back_changer)
#the player
man = pygame.image.load("/Users/apple/Downloads/Python Projects/Climbing_Game/man.png").convert_alpha()
man = pygame.transform.scale(man, (51, 70))
man_rec = man.get_rect(center = (250, -500))
#the platforms player moves on
platform = pygame.image.load("/Users/apple/Downloads/Python Projects/Climbing_Game/platform.png").convert_alpha()
platform = pygame.transform.scale(platform,(300,60))
platform_rec = platform.get_rect(center = (250,730))
#game over screen
game_over_screen = pygame.image.load("/Users/apple/Downloads/Python Projects/Climbing_Game/End_screen.png").convert_alpha()
game_over_screen = pygame.transform.scale(game_over_screen,(500,800))
#moving platforms
def create_plat():
random_plat_pos = random.choice(plat_pos)
new_plat = platform.get_rect(center = (random_plat_pos, 800))
return new_plat
def mov_plat(plats):
for plat in plats:
plat.centery -= 4
return plats
def draw_plat(plats):
for plat in plats:
screen.blit(platform, plat)
#collison detection
def detect_plat(plats):
for plat in plats:
if man_rec.colliderect(plat):
global mov_of_man_y
mov_of_man_y = -4
return
def detect_man(mans):
for man in mans:
if man_rec.top <= -700 or man_rec.bottom >= 900:
return False
if man_rec.left <= -100 or man_rec.right >= 500:
return False
else:
return True
#score
def display_score():
pass
#moving platforms
plat_list = []
PLATMOV = pygame.USEREVENT
pygame.time.set_timer(PLATMOV, 1200)
plat_pos = [100,200,300,400]
#back change
BACKCHANGE = pygame.USEREVENT
pygame.time.set_timer(BACKCHANGE, 1200)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
mov_of_man_x += right_mov
man_rec.centerx += mov_of_man_x
mov_of_man_x -= 50
if event.key == pygame.K_LEFT:
mov_of_man_x += left_mov
man_rec.centerx -= mov_of_man_x
mov_of_man_x -= 50
if event.type == PLATMOV:
plat_list.append(create_plat())
#surfaces
screen.blit(bg_image,(0,0))
if game_active == True:
#gravity
mov_of_man_y += gravity
man_rec.centery += mov_of_man_y
#plats
plat_list = mov_plat(plat_list)
draw_plat(plat_list)
detect_plat(plat_list)
game_active = detect_man(man_rec)
#character
screen.blit(man, man_rec)
"""
if event.type == BACKCHANGE:
screen.blit(back_change,(0,0))
else:
screen.blit(bg_image,(0,0))
"""
else:
screen.blit(game_over_screen, (0,0))
pygame.display.update()
clock.tick(120)
Add a variable that indicates which background to draw:
bg_images = [bg_image, bg_image2]
bg_index = 0
Change the background index when the BACKCHANGE event occurs:
for event in pygame.event.get():
if event.type == BACKCHANGE:
bg_index += 1
if bg_index >= len(bg_images):
bg_index = 0
blit the current background in the application loop:
while True:
# [...]
screen.blit(bg_images[bg_index], (0,0))
# [...]
Application loop:
bg_images = [bg_image, bg_image2]
bg_index = 0
# [...]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
# [...]
if event.type == pygame.KEYDOWN:
# [...]
if event.type == PLATMOV:
# [...]
if event.type == BACKCHANGE:
bg_index += 1
if bg_index >= len(bg_images):
bg_index = 0
if game_active == True:
screen.blit(bg_images[bg_index], (0,0))
# [...]
else:
screen.blit(game_over_screen, (0,0))
pygame.display.update()
clock.tick(120)
I just started learning Pygame and I'm doing a little game (school project), where using mouse I can click on the image and drag it. There are a lot of images, so my question is how I can identify what image is chosen. Thank you!
Here are some code:
def Transformation(element):
element = pygame.transform.scale(element,(50,75))
fire = pygame.image.load("ElementIcon/fire.png").convert_alpha()
Transformation(fire)
fire.set_colorkey(BLACK)
fire_rect = fire.get_rect()
earth = pygame.image.load("ElementIcon/earth.png").convert_alpha()
Transformation(earth)
earth.set_colorkey(BLACK)
earth_rect = earth.get_rect()
while not done:
screen.fill(WHITE)
#Update the screen with drawings
screen.blit(fire,(408,450))
screen.blit(earth,(419, 350))
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
print("User quits the game :(")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
print("Game stopped early by user :( ")
if event.type == pygame.MOUSEBUTTONDOWN:
print mouse_pos
print fire_rect
if fire_rect.collidepoint(mouse_pos):
print "over fire"
if earth_rect.collidepoint(mouse_pos):
print "mama"
When I try to print fire_rect I get <0,0,62,75>
Have a play with this code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((600,600))
clock = pygame.time.Clock()
FPS = 60
class MovableImage(pygame.Surface):
def __init__(self, image, xpos=0, ypos=0):
self.image = image
self.xpos = xpos
self.ypos = ypos
self.width = image.get_width()
self.height = image.get_height()
self.selected = False
self.rect = pygame.Rect(xpos, ypos, image.get_width(), image.get_height())
def move(self, move):
self.xpos += move[0]
self.ypos += move[1]
self.rect = pygame.Rect(self.xpos, self.ypos, self.width, self.height)
def Transformation(element):
element = pygame.transform.scale(element,(50,75))
def init():
global ImageList
fire = pygame.Surface((50,50))
fire.fill((255,0,0))
#fire = pygame.image.load("ElementIcon/fire.png").convert_alpha()
#Transformation(fire)
#fire.set_colorkey(BLACK)
#fire_rect = fire.get_rect()
earth = pygame.Surface((50,50))
earth.fill((255,255,0))
#earth = pygame.image.load("ElementIcon/earth.png").convert_alpha()
#Transformation(earth)
#earth.set_colorkey(BLACK)
#earth_rect = earth.get_rect()
fire_obj = MovableImage(fire, 408, 450)
earth_obj = MovableImage(earth, 419,350)
ImageList =[]
ImageList.append(fire_obj)
ImageList.append(earth_obj)
def run():
global done
done = False
while not done:
check_events()
update()
clock.tick(60)
def check_events():
global done
global ImageList
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
print("User quits the game :(")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
done = True
print("Game stopped early by user :( ")
if event.type == pygame.MOUSEBUTTONDOWN:
for im in ImageList:
if im.rect.collidepoint(mouse_pos):
im.selected = not im.selected
if event.type == pygame.MOUSEBUTTONUP:
for im in ImageList:
if im.rect.collidepoint(mouse_pos):
im.selected = False
if event.type == pygame.MOUSEMOTION:
for im in ImageList:
if im.rect.collidepoint(mouse_pos) and im.selected:
xmv = event.rel[0]
ymv = event.rel[1]
if event.buttons[0]:
if xmv < 0:
if im.xpos > 0:
im.move((xmv,0))
elif event.rel[0] > 0:
if im.xpos < screen.get_width():
im.move((xmv,0))
elif event.rel[1] < 0:
if im.ypos > 0:
im.move((0,ymv))
elif event.rel[1] > 0:
if im.ypos < screen.get_height():
im.move((0,ymv))
def update():
global ImageList
screen.fill((255, 255, 255)) #WHITE)
#Update the screen with drawings
for im in ImageList:
screen.blit(im.image, (im.xpos, im.ypos))
pygame.display.update()
if __name__=="__main__":
init()
run()
You can get the mouse pos and the image rect and check for collision:
pos = pygame.mouse.get_pos()
if image.rect.collidepoint(pos)
# move it
If you want to move the image with the mouse you can get the relative x/y movement with pygame.mouse.get_rel() and use that to change the image location.