Newline in Pygame With Unicode In Input Box - python

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

Related

Pygame Not Responding First Time

I'm just adding some finishing touches to my tank game, but there's this slight thing that's been bothering me. It's just that, at the menu screen, when the user presses a different set of keys to access different things such as the instruction screen, game screen, or custom username input screen, it takes two presses of the button to respond and not the desired one single press. Here's the little excerpt of code:
menu = True
instruct = False
run = False
name1 = False
name2 = False
while menu:
pygame.event.get()
theKey = pygame.key.get_pressed()
if theKey[pygame.K_RETURN]:
menu = False
run = False
instruct = True
name1 = False
if theKey[pygame.K_LSHIFT] or theKey[pygame.K_RSHIFT]:
menu = False
run = True
begin = time.time()
if theKey[pygame.K_BACKSPACE]:
menu = False
run = False
instruct = False
name1 = True
user_input = ''
menu_screen()
FONT = pygame.font.Font(None, 40) # A font object which allows you to render text.
BG_COLOR = pygame.Color('gray12')
BLUE = pygame.Color('dodgerblue1')
USEFONT = pygame.font.Font(None, 70)
yourText1 = "Player 1, Enter Your Name: "
yourText2 = "Player 2, Enter Your Name: "
userNamePrompt = USEFONT.render(yourText1, True, BLUE)
userNamePrompt2 = USEFONT.render(yourText2, True, BLUE)
while name1:
theKey = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
name1 = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_BACKSPACE:
user_input = user_input[:-1]
elif event.key == pygame.K_RETURN:
name1 = False
name2 = True
user2_input = ''
else:
user_input += event.unicode
screen.fill(BG_COLOR)
# Create the text surface.
text = FONT.render(user_input, True, BLUE)
# And blit it onto the screen.
screen.blit(userNamePrompt, (20,20))
screen.blit(text, (20, 300))
pygame.display.flip()
clock.tick(30)
while name2:
theKey = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
name1 = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_BACKSPACE:
user2_input = user2_input[:-1]
elif event.key == pygame.K_RETURN:
name2 = False
run = True
begin = time.time()
else:
user2_input += event.unicode
screen.fill(BG_COLOR)
# Create the text surface.
text = FONT.render(user2_input, True, BLUE)
# And blit it onto the screen.
screen.blit(userNamePrompt2, (20,20))
screen.blit(text, (20, 300))
pygame.display.flip()
clock.tick(30)
playName1 = user_input
playName2 = user2_input
while instruct:
pygame.event.get()
theKey = pygame.key.get_pressed()
if theKey[pygame.K_BACKSPACE]:
instruct = False
run = False
menu = True
if theKey[pygame.K_LSHIFT] or theKey[pygame.K_RSHIFT]:
instruct = False
run = True
begin = time.time()
instruct_screen()
In this case, the code takes two taps of the "return" or enter button to get the instruction screen and two taps of the shift key to show the game screen - and I've tried to fix it, but to no avail. Does anyone know why this may be occurring and what/how the code needs to be modified in order for it to work as desired?
It's because you're calling pygame.key.get_pressed() twice, once in the menu loop and once in the name1 loop. Each time you call it, it's popping the keypress event off the stack, so the second time it will wait for a second keypress. You should store the result the first time, and use that in the second loop.

I have code in pygame to display text when a certain screen is shown, but it disappears straight away

I want the code to display text for an options screen on my computer science project. The problem is that when I change to the options screen the text is not visible. I have found that switching quickly between the screens shows it briefly sometimes. I have put code for the text to display in 2 places either when you click on the settings in the top right of the main screen or when you press enter on the keypad.
import pygame
import sys
import time
from pygame.locals import *
displaytext = False
fadedout = False
timechange = 0
played = False
musicUp = pygame.K_o
musicDown = pygame.K_l
pygame.init() # initialize pygame
pygame.font.init()
myfont = pygame.font.SysFont('Comic Sans MS', 30)
pygame.mixer.music.set_volume(0.50)
clock = pygame.time.Clock()
screen = pygame.display.set_mode((1600,800))
pygame.mouse.set_cursor(*pygame.cursors.tri_left)
currentBack = 'welcome'
bg = pygame.image.load("welcome1600new.jpg")
def callText():
textsurface = myfont.render('Some Text', True, (10, 10, 10))
textpos = textsurface.get_rect()
screen.blit(textsurface,textpos)
def options():
pausePos = play_time()/1000
pygame.mouse.set_cursor(*pygame.cursors.arrow)
bg = pygame.image.load("Optionsback.jpg")
displaytext = True
return bg,displaytext
def play_time():
playTime = pygame.mixer.music.get_pos()
return playTime
while True:
clock.tick(60)
screen.blit(bg, (0,0))
pygame.display.update()
for event in pygame.event.get():
pygame.mixer.init()
if (pygame.mixer.music.get_busy() == False) and (fadedout == False):
pygame.mixer.music.load("dududududu.ogg")
pygame.mixer.music.play(-1,0.0)
if (displaytext) == True:
textsurface = myfont.render('Some Text', 1, (10, 10, 10))
textpos = textsurface.get_rect()
screen.blit(textsurface,textpos)
if ((currentBack == 'welcome') and (event.type ==
pygame.MOUSEBUTTONUP) and (pygame.mouse.get_pos()[0] >= 1540) and
(pygame.mouse.get_pos()[0] <= 1600) and (pygame.mouse.get_pos()[1] >= 0) and
(pygame.mouse.get_pos()[1] <= 70)):
currentBack = 'options'
bg, displaytext = options()
if event.type == KEYDOWN:
if ((event.key == pygame.K_h) and (currentBack == 'welcome')):
pausePos = play_time()/1000
pygame.mouse.set_cursor(*pygame.cursors.arrow)
bg = pygame.image.load("Help1600.jpg")
currentBack = 'help'
#pygame.mixer.pause()
pygame.mixer.music.fadeout(1000)
pygame.display.update()
fadedout = True
displaytext = False
if event.key == musicUp:
if (pygame.mixer.music.get_volume()<=0.90) and
timechange+0.25<time.time():
timechange = time.time()
pygame.mixer.music.set_volume(pygame.mixer.music.get_volume()+.10)
pygame.display.update()
displaytext = False
if event.key == musicDown:
if pygame.mixer.music.get_volume()>=.10 and
timechange+0.25<time.time():
timechange = time.time()
pygame.mixer.music.set_volume(pygame.mixer.music.get_volume()-.10)
pygame.display.update()
displaytext = False
if (event.key == pygame.K_ESCAPE):
pygame.mouse.set_cursor(*pygame.cursors.tri_left)
bg = pygame.image.load("welcome1600new.jpg")
currentBack = 'welcome'
pygame.mixer.music.play(-1, pausePos)
pygame.display.update()
fadedout = False
displaytext = False
if event.key == (pygame.K_KP_ENTER):
callText()
bg, displaytext = options()
currentBack = 'options'
There are several strange things there.
What causes the specific behavior you are complaining about is that you only draw your text inside the for loop that checks for events. If there are no events, such as keypresses or mouse movement in a frame, the block that blits your text is not run at all.
Another thing that might bring you closer to a working thing, is to make one and only single call to pygame.display.update() or the equivalent .flip() in each frame.
And work the code around it so that it makes sense. Each time you call ...display.update() above, you had redrawn the whole screen. And whatever text was there will be gone.
The for event in pygame.event.get() loop is not a magic entity from outer space. It is simply a way for you to check for the pygame events that happen at each frame.
Every single thing in there that is not testing the event variable have to go out.
Also pygame.mixer.init() should be called one single time, at the beginning of the program - while you put it being called multiple times each frame. If you have to reset the mixer, to restart the music, check the docs for another call to do that.
All in all, more or less the code bellow. I did not try to run it, but I just unmangled some of the stuff you have around.
import pygame
import sys
import time
from pygame.locals import *
def init():
global clock, screen
pygame.init() # initialize pygame
screen = pygame.display.set_mode((1600,800))
pygame.font.init()
pygame.mixer.init()
pygame.mixer.music.set_volume(0.50)
pygame.mouse.set_cursor(*pygame.cursors.tri_left)
clock = pygame.time.Clock()
# put stuff inside a function.
def main():
myfont = pygame.font.SysFont('Comic Sans MS', 30)
displaytext = False
fadedout = False
timechange = 0
played = False
musicUp = pygame.K_o
musicDown = pygame.K_l
currentBack = 'welcome'
bg_image = pygame.image.load("Help1600.jpg")
bg = img_welcome = pygame.image.load("welcome1600new.jpg")
while True:
screen.blit(bg, (0,0))
if (pygame.mixer.music.get_busy() == False) and (fadedout == False):
pygame.mixer.music.load("dududududu.ogg")
pygame.mixer.music.play(-1,0.0)
if (displaytext) == True:
textsurface = myfont.render('Some Text', 1, (10, 10, 10))
textpos = textsurface.get_rect()
screen.blit(textsurface,textpos)
# Use a rectangle and Rect.collidepoint instead of this mess:
# https://www.pygame.org/docs/ref/rect.html#pygame.Rect.collidepoint
if ((currentBack == 'welcome') and
(event.type == pygame.MOUSEBUTTONUP) and
(pygame.mouse.get_pos()[0] >= 1540) and
(pygame.mouse.get_pos()[0] <= 1600) and
(pygame.mouse.get_pos()[1] >= 0) and
(pygame.mouse.get_pos()[1] <= 70)
):
currentBack = 'options'
bg, displaytext = options()
for event in pygame.event.get():
# just check for _events_ inside here.
if event.type == KEYDOWN:
if ((event.key == pygame.K_h) and (currentBack == 'welcome')):
pausePos = play_time()/1000
pygame.mouse.set_cursor(*pygame.cursors.arrow)
# DOn't load images with pygame.image.load inside the game loop!!
bg = bg_image
currentBack = 'help'
#pygame.mixer.pause()
pygame.mixer.music.fadeout(1000)
fadedout = True
displaytext = False
if event.key == musicUp:
if (pygame.mixer.music.get_volume()<=0.90) and timechange+0.25<time.time():
timechange = time.time()
pygame.mixer.music.set_volume(pygame.mixer.music.get_volume()+.10)
displaytext = False
if event.key == musicDown:
if pygame.mixer.music.get_volume()>=.10 and timechange+0.25<time.time():
timechange = time.time()
pygame.mixer.music.set_volume(pygame.mixer.music.get_volume()-.10)
displaytext = False
if (event.key == pygame.K_ESCAPE):
pygame.mouse.set_cursor(*pygame.cursors.tri_left)
bg = img_welcome
currentBack = 'welcome'
pygame.mixer.music.play(-1, pausePos)
fadedout = False
displaytext = False
if event.key == (pygame.K_KP_ENTER):
callText()
bg, displaytext = options()
currentBack = 'options'
# single call to update:
pygame.display.update()
# after you display the image, you can pause
# until the next frame:
clock.tick(60)
init()
main()

Number To Key Dictionary

For a program using pygame, I need an input box. I tried to make one myself, but I need a dict which translates the numbers from pygame to keys. I used to have a dict which included numbers and characters, but I need symbols.
Here's a simple text input box example. You can just add the .unicode attribute of KEYDOWN events to a string.
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
font = pg.font.Font(None, 32)
clock = pg.time.Clock()
input_box = pg.Rect(100, 100, 140, 32)
color_unfocused = pg.Color('lightskyblue3')
color_focused = pg.Color('dodgerblue2')
color = color_unfocused
focused = False
text = ''
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if input_box.collidepoint(event.pos):
focused = not focused
else:
focused = False
color = color_focused if focused else color_unfocused
if event.type == pg.KEYDOWN:
if focused:
if event.key == pg.K_RETURN:
print(text)
text = ''
elif event.key == pg.K_BACKSPACE:
text = text[:-1]
else:
text += event.unicode
screen.fill((30, 30, 30))
txt_surface = font.render(text, True, color)
width = max(200, txt_surface.get_width()+10)
input_box.w = width
screen.blit(txt_surface, (input_box.x+5, input_box.y+5))
pg.draw.rect(screen, color, input_box, 2)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()

Pygame: Limit Name to 3 or 4 Letters

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

Losing a "life" won't go down after an error? pygame

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.

Categories