I am learning about text input in pygame for a game I am creating and currently adding scores into. I have learnt how to write text to a file then read and display the text on the screen. Now I am trying to learn how I can limit names to 3 or 4 characters so scores are neatly aligned. Currently the player can input a name as long as they want. So for example they could do the ABC's but I just want 3 or 4 characters. Here is my code I am working on:
import pygame, random
from pygame.locals import *
FONT_SIZE = 60
def name():
screen = pygame.display.set_mode((1280, 720))
name = ""
lol = random.randint(0, 100)
font = pygame.font.SysFont(None, FONT_SIZE)
while True:
# readlines returns a list; having this in
# loop allows pygame to draw recently added
# string; no need to close and open a window
namefile = open('test.txt', 'r')
names = namefile.readlines()
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.unicode.isalpha():
if event.unicode == 3:
name += 0
else:
name += event.unicode
elif event.key == K_BACKSPACE:
name = name[:-1]
elif event.key == K_RETURN:
f = open("test.txt", "a")
f.write(str(name) + " " + str(lol) + "\n")
f.close()
name = ""
elif event.type == QUIT:
return
# create a Rectangle container, where yours
# text variable will be drawn
# Rect(left, top, width, height)
textrect = Rect(0, 0, 100, FONT_SIZE)
screen.fill((0, 0, 0))
for i in names:
# iterate through lines from text file (it is stored
# in names variable and it is a list)
# create text variable and draw it to textrect
text = font.render(i[:-1], True, (255,0,0), (0,0,0))
screen.blit(text, textrect)
# change y coordinate of textrect; in next iteration
# next line will appear below the previous line
textrect.centery += FONT_SIZE
block = font.render(name, True, (255, 255, 255))
rect = block.get_rect()
rect.center = screen.get_rect().center
screen.blit(block, rect)
pygame.display.update()
pygame.display.flip()
if __name__ == "__main__":
pygame.init()
name()
pygame.quit()
Here is an example of what I am after:
You could do something like this
if event.unicode.isalpha():
if len(name) < 3:
if event.unicode == 3:
name += 0
else:
name += event.unicode
this way, you only add a character if the name is not to long
Related
I am making a simple input box in pygame, where you should be able to type anything, press backspace, and add a newline by pressing enter. I can't seem to make a newline though because I don't know how. I want to be able to add a newline when pressing enter and keep the other text above it.
I have tried using text = text + "/n" but that didn't work.
This is my Code:
import pygame
pygame.init()
winheight = 600
winwidth = 1200
font = pygame.font.Font(None, 32)
input_box = pygame.Rect(50, 50, winwidth - 100, winheight - 100)
blue = (0, 0, 255)
Text = ''
Writing = True
win = pygame.display.set_mode((winwidth, winheight))
pygame.display.set_caption("Clogging Cuesheet Writer")
while Writing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Writing = False
break
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
print ("replace this with the command to make Text plus a newline")
elif event.key == pygame.K_BACKSPACE:
Text = Text[:-1]
else:
Text += event.unicode
#clear screen, draw text, draw inputbox, then update
win.fill((0, 0, 0))
txt_surface = font.render(Text, True, blue)
win.blit(txt_surface, (input_box.x+15, input_box.y+15))
pygame.draw.rect(win, blue, input_box, 2)
pygame.display.update()
pygame.quit()
PLEASE HELP
That's because you have a typo in "/n". What you really want is "\n":
if event.key == pygame.K_RETURN:
print (text = text + '\n')
ok bro here is my code for displaying a text in a window of dimentions of
width, height
the way i get the new lines is that the ord(event.unicode) is 13
offsetX = 0
offsetY = 0
font = pygame.font.Font(None, 20)
tmp_text = 'hi Qdfhasdj' # here u add the text u need with tmp_text+=event.unicode
line_counter=0
while tmp_text!='':
line_text = ''
while tmp_text!='':
word = tmp_text[0]
if font.render(line_text+word, True, tmp_currentTextColor, tmp_currentColor).get_rect()[2]>width-20:
break
if ord(word) == 13: #for new line because the '\n' not working for some reason
if len(tmp_text)==1:
tmp_text = ''
break
tmp_text = tmp_text[1:]
break
line_text=line_text+word
if len(tmp_text)==1:
tmp_text = ''
break
tmp_text = tmp_text[1:]
line_text = font.render(line_text, True, tmp_currentTextColor, tmp_currentColor)
screen.blit(line_text, [offsetX +padding[0]/2,offsetY + padding[1]/2 + 1.5*padding[1]*line_counter])
line_counter+=1
I'm trying to display what the user types onto the screen as a preview and when they left click with the mouse, it blits the text onto the screen.
from pygame import *
init()
screen = display.set_mode((640, 480))
clock = time.Clock()
running = True
font = font.SysFont("comicsansms", 72) # Default font
textC = "a" # Stores user input
text = font.render(textC, True, (255,0,0)) # Render Text
while running:
mx, my = mouse.get_pos()
mb = mouse.get_pressed()
for e in event.get():
if e.type == QUIT:
running = False
if e.type == KEYDOWN:
print(textC)
if key.get_pressed()[K_BACKSPACE]:
textC = textC[:-1] # removes last letter
else:
textC += e.unicode # adds letter
screen.fill((255, 255, 255)) #fill screen white
screen.blit(text, (mx, my)) # display text
display.flip()
clock.tick(60)
quit()
First, you are not catching the mouse event correctly. You can use MOUSEBUTTONDOWN event in the same way as using KEYDOWN for key event and then use mouse.get_pressed to know which mouse button is being pressed.
Second, the problem is that each time screen.fill executes, all the surface is erased so it is necessary to somehow track the text and the position of rendered text. It can be a list.
So you're code can look something like this
from pygame import *
init()
screen = display.set_mode((640, 480))
clock = time.Clock()
running = True
font = font.SysFont("comicsansms", 72) # Default font
textC = "a" # Stores user input
text = font.render(textC, True, (255,0,0)) # Render Text
text_rendered = []
def rerender_text():
for surface, pos in text_rendered:
screen.blit(surface, pos) # display text
while running:
screen.fill((255, 255, 255)) # fill screen white
mx, my = mouse.get_pos()
for e in event.get():
if e.type == QUIT:
running = False
if e.type == KEYDOWN:
keys = list(key.get_pressed())
index = keys.index(1)
if key.get_pressed()[K_BACKSPACE]:
textC = textC[:-1] # removes last letter
else:
textC += e.unicode # adds letter
if e.type == MOUSEBUTTONDOWN:
if mouse.get_pressed()[0]: # Left click
screen.blit(text, (mx, my)) # display text
# save the text and the position for rerendering
text_rendered.append((text,(mx,my)))
text = font.render(textC, True, (255, 0, 0)) # Render Text
rerender_text()
screen.blit(text, (mx, my)) # display text
display.flip()
clock.tick(60)
quit()
I've modified your example, to put the stored text where you click. You need to update your text surface when you change your textC. I also clear the textC buffer on mouse-click.
from pygame import *
init()
screen = display.set_mode((640, 480))
clock = time.Clock()
running = True
font = font.SysFont("comicsansms", 72) # Default font
textC = "a" # Stores user input
text = font.render(textC, True, (255,0,0)) # Render Text
pos = None # store mouse click location
while running:
mx, my = mouse.get_pos()
mb = mouse.get_pressed()
for e in event.get():
if e.type == QUIT:
running = False
if e.type == KEYDOWN:
print(textC)
if key.get_pressed()[K_BACKSPACE]:
textC = textC[:-1] # removes last letter
else:
textC += e.unicode # adds letter
# need to update the text surface:
text = font.render(textC, True, (255,0,0)) # Render Text
elif e.type == MOUSEBUTTONDOWN:
pos = mouse.get_pos()
locked_text = font.render(textC, True, (0,255,0))
textC = ""
text = font.render(textC, True, (255,0,0)) # Clear text
screen.fill((255, 255, 255)) #fill screen white
if pos:
screen.blit(locked_text, pos)
screen.blit(text, (mx, my)) # display text
display.flip()
clock.tick(60)
quit()
If you want the text to persist, then you'll need to create a list of text surfaces and their positions and then iterate through them every frame. Might be worth considering Sprites in this case.
I want to make some sort of typing game in python using pygame. So, if the key pressed character is the same as the character in the word, it should return true... Is there any way to do this in python?
For example:
the word is "cat", if the user presses the key 'c', then it returns true... and so on for the rest of the characters.
here's my main.py file
from time import sleep
import pygame
import random
import winsound
from words import Words
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
done = False
clock = pygame.time.Clock()
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
w1 = Words(screen) #making a single word (for now) to see if typing works
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(WHITE)
w1.draw()
#attempting to write code here to compare word and user input
pygame.display.flip()
clock.tick(60)
pygame.init()
exit()
here's my words.py file
from random_words import RandomWords
import pygame
import random
from queue import *
rw = RandomWords()
class Words():
def __init__(self, screen):
self.screen = screen
self.x_point = 400
self.y_point = 400
self.word = rw.random_word() #generates a random word
self.queue = Queue() #was hoping to use the queue so that if the user types the char correctly in the right order, then the letter would change color or something (but that's further down the line)
for c in self.word: #iterate through randomized word..
self.queue.put(c) #add each char in randomized word to queue, for typing reasons
def getY(self):
return self.y_point
def draw(self):
#creates a new object
myfont = pygame.font.SysFont('Comic Sans MS' ,30)
#creates a new surface with text drawn on it
textsurface = myfont.render(self.word, False, (0,0,0))
self.screen.blit(textsurface,(self.x_point,self.y_point))
Event KEYDOWN has event.unicode, event.key, event.mod
You can compare
if event.type == pygame.KEYDOWN:
if event.unicode == "a":
or even
if event.type == pygame.KEYDOWN:
if event.unicode.lower() == "a":
to check "a" and "A"
To check char in word
if event.type == pygame.KEYDOWN:
if event.unicode.lower() in your_word.lower():
Example code use event.unicode to render text with pressed keys.
BTW: It is not some Entry widget so it doesn't delete char when you press backspace.
import pygame
# --- constants ---
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
SCREEN_WIDTH = 300
SCREEN_HEIGHT = 200
FPS = 5 # `FPS = 25` is enough for human eye to see animation.
# If your program don't use animation
# then `FPS = 5` or even `FPS = 1` can be enough
# --- main ---
# - init -
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# - objects -
font = pygame.font.SysFont(None, 30)
text = ""
text_image = font.render(text, True, GREEN)
text_rect = text_image.get_rect() # get current size
text_rect.center = screen_rect.center # center on screen
# - mainloop -
clock = pygame.time.Clock()
done = False
while not done:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
text += event.unicode
text_image = font.render(text, True, GREEN)
text_rect = text_image.get_rect() # get current size
text_rect.center = screen_rect.center # center on screen
# - draws -
screen.fill(BLACK)
screen.blit(text_image, text_rect)
pygame.display.flip()
clock.tick(FPS)
# - end -
pygame.quit() # <-- quit(), not init()
I have just added in some code I had tried out into my game as a scoreboard and I have encountered an error. Only my background will display. No text or anything will appear. Here is the code I am using:
class MenuScores(MenuClass):
def __init__(self, surface, engine):
MenuClass.__init__(self, surface)
self.MoonSurvival = engine
self.text = "Name"
def name():
size = 36
screen = pygame.display.set_mode((1280, 720))
name = ""
font = pygame.font.SysFont('data/fonts/score.ttf', size)
background = pygame.image.load('data/images/bg.jpg')
while True:
# readlines returns a list; having this in
# loop allows pygame to draw recently added
# string; no need to close and open a window
namefile = open('score.txt', 'r')
names = namefile.readlines()
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.unicode.isalpha():
if len(name) < 4:
if event.unicode == 3:
name += 0
else:
name += event.unicode
elif event.key == K_BACKSPACE:
name = name[:-1]
elif event.key == K_RETURN:
f = open("data/scores/score.txt", "a")
f.write(str(name) + " " + str(self.MoonSurvival.total_score) + "\n")
f.close()
name = ""
self.text = ""
elif event.type == QUIT:
return
# create a Rectangle container, where yours
# text variable will be drawn
# Rect(left, top, width, height)
textrect = Rect(0, 0, 100, size)
screen.fill((0, 0, 0))
for i in names:
# iterate through lines from text file (it is stored
# in names variable and it is a list)
# create text variable and draw it to textrect
text = font.render(i[:-1], True, (255,0,0), (0,0,0))
screen.blit(text, textrect)
# change y coordinate of textrect; in next iteration
# next line will appear below the previous line
textrect.centery += size
block = font.render(name, True, (255, 255, 255))
rect = block.get_rect()
rect.center = screen.get_rect().center
screen.blit(background, (0, 0))
screen.blit(block, rect)
pygame.display.update()
pygame.display.flip()
def draw(self):
self.renderText()
self.drawHint()
self.surface.blit(self.background, (0, 0))
# update surface
pygame.display.update()
def _handleEvents(self, event):
def pressed(key):
keys = pygame.key.get_pressed()
if keys[key]:
return True
else:
return False
if pressed(pygame.K_SPACE):
self.MoonSurvival.game_state = STATE_MENU
self.MoonSurvival.level = 1
def renderText(self):
# split texts at \n (newline)
texts = self.text.split('\n')
for i in range(len(texts)):
textSurface = self.menufont.render(texts[i], 0, (255, 0, 0))
textRect = textSurface.get_rect()
textRect.centerx = SCREEN_WIDTH / 2
textRect.centery = SCREEN_HEIGHT / 2 + i * self.menufont.size(texts[i])[1]
self.surface.blit(textSurface, textRect)
def drawHint(self):
textSurface = self.menufont.render('(Press SPACE to return to menu)', 0, (255, 0, 0))
textRect = textSurface.get_rect()
textRect.centerx = SCREEN_WIDTH / 2
textRect.centery = SCREEN_HEIGHT - 50
self.surface.blit(textSurface, textRect)
I really don't know how to fix this. The text appeared fine when it was on its own (the def name()) So why does it not work here?
self.renderText()
self.drawHint()
self.surface.blit(self.background, (0, 0))
Here, you are drawing the text on self.surface, then drawing the hint on self.surface, and then painting the background image on self.surface, over top everything else.
Instead, you should draw the background first, and everything else after it.
self.surface.blit(self.background, (0, 0))
self.renderText()
self.drawHint()
And I don't know why??? Everything else seems to be working just fine.. but when you click the wrong "button" in the game the error sounds works and it resets the pattern, but the lives that I have put up (which is 3) doesn't go down at all. Wondering if anyone could help me out with this please? (I won't be pasting my entire code, but this is where the command happens and all). Also if you couldn't tell, I'm creating a memory game. If anyone could lead me into the right direction then that could be a big help for me. Thanks in advance!
def main():
global FPSCLOCK, DISPLAYSURF, BASICFONT, BEEP1, BEEP2, BEEP3, BEEP4
pygame.init()
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Simulate')
# font
BASICFONT = pygame.font.Font(None, 30)
# load the sound files
BEEP1 = pygame.mixer.Sound('beep1.wav')
BEEP2 = pygame.mixer.Sound('beep2.wav')
BEEP3 = pygame.mixer.Sound('beep3.wav')
BEEP4 = pygame.mixer.Sound('beep4.wav')
SOUNDTRACK = pygame.mixer.Sound('soundtrack.wav')
ERROR = pygame.mixer.Sound('error.wav')
# initialize some variables for a new game
pattern = [] # stores the pattern of colors
currentStep = 0 # the color the player must push next
lastClickTime = 0 # timestamp of the player's last button push
score = 0
# plays the soundtrack music
SOUNDTRACK.play(-1, 0, 1000)
# start-up screen
text = BASICFONT.render('Press enter to play!', 1, WHITE)
textRect = text.get_rect()
textRect.centerx = DISPLAYSURF.get_rect().centerx
textRect.y = 150
DISPLAYSURF.blit(text, textRect)
# update the screen
pygame.display.update()
# the "press enter" command
waiting = True
while waiting:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
waiting = False
# when False, the pattern is playing. when True, waiting for the player to click a colored button:
waitingForInput = False
while True: # main game loop
clickedButton = None # button that was clicked (set to YELLOW, RED, GREEN, or BLUE)
DISPLAYSURF.fill(bgColor)
drawButtons()
# amount of lives
lives = 3
img = BASICFONT.render('I'*lives, 1, WHITE)
livesRect = img.get_rect()
livesRect.topleft = (10, 10)
DISPLAYSURF.blit(img, livesRect)
scoreSurf = BASICFONT.render('Score: ' + str(score), 1, WHITE)
scoreRect = scoreSurf.get_rect()
scoreRect.topleft = (WIDTH - 100, 10)
DISPLAYSURF.blit(scoreSurf, scoreRect)
checkForQuit()
for event in pygame.event.get(): # event handling loop
if event.type == MOUSEBUTTONUP:
mousex, mousey = event.pos
clickedButton = getButtonClicked(mousex, mousey)
if not waitingForInput:
# play the pattern
pygame.display.update()
pygame.time.wait(1000)
pattern.append(random.choice((YELLOW, BLUE, RED, GREEN)))
for button in pattern:
flashButtonAnimation(button)
pygame.time.wait(FLASHDELAY)
waitingForInput = True
else:
# wait for the player to enter buttons
if clickedButton and clickedButton == pattern[currentStep]:
# pushed the correct button
flashButtonAnimation(clickedButton)
currentStep += 1
lastClickTime = time.time()
if currentStep == len(pattern):
# pushed the last button in the pattern
score += 1
waitingForInput = False
currentStep = 0 # reset back to first step
elif (clickedButton and clickedButton != pattern[currentStep]) or (currentStep != 0 and time.time() - TIMEOUT > lastClickTime):
# pushed the incorrect button, or has timed out
pattern = []
currentStep = 0
waitingForInput = False
lives = lives - 1
SOUNDTRACK.stop()
ERROR.play()
pygame.time.wait(1000)
SOUNDTRACK.play(-1, 0, 1000)
pygame.display.update()
if lives < 1:
gameOverAnimation()
# reset the variables for a new game:
pattern = []
currentStep = 0
waitingForInput = False
score = 0
pygame.time.wait(1000)
pygame.display.update()
FPSCLOCK.tick(FPS)
You set lives = 3 inside your main loop, instead of before it.
This means that you reset it to 3 on every iteration of the loop.