msvcrt getch pauses script, has to continue - python

PYTHON 3.3, msvcrt
import sys, msvcrt
print("Please press a key to see its value")
while 1:
key = msvcrt.getch()
print("the key is")
print(key)
if ord(key) == 27: # key nr 27 is escape
sys.exit()
this is my code, just as an example.
the code pauses when it gets to the key = msvcrt.getch()*, or *key = ord(getch()) for that matter, right here i used the first one.
I'd like to have this code constantly print the key is
instead of just printing the key is when i give a new input (when i press a key).
so the printed output would look something like this:
the key is
the key is
the key is
the key is
the key is
the key is
77
the key is
the key is
the key is
which is needed if you want to make something like snake, where you don't want your game to be paused everytime you want to getch, you don't want it to pause, waiting for an input.

Use msvcrt.kbhit to check whether key was pressed:
import sys, msvcrt
import time
print("Please press a key to see its value")
while 1:
print("the key is")
if msvcrt.kbhit(): # <--------
key = msvcrt.getch()
print(key)
if ord(key) == 27:
sys.exit()
time.sleep(0.1)

Another example to make Python program stop at a certain level, and wait for the user to press Enter "Yes" and/ or Space for "No" can be generated using pygame.
As an example I used Space for "No", but you could use the touche Escape for "No".
You might not need some imported librairies. Needed them while making tic toc toe game.
The code is below :
import numpy as np
import pygame as pg
from math import floor
import sys
import time
pg.init()
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
yellow = (255, 255, 0)
white = (255, 255, 255)
gris = (192, 192, 192)
cell = 100
thickness =2
window = pg.display.set_mode((300, 300))
pg.display.set_caption("by #djilytech")
for col in range(3):
for row in range(3):
pg.draw.rect(window, gris, (row * cell, col * cell, cell - 2, cell - 2), thickness)
pg.time.delay(120)
pg.display.update()
run = False
while not run:
for ev in pg.event.get():
if ev.type == pg.QUIT:
pg.quit()
sys.exit()
if ev.type == pg.KEYDOWN:
if ev.key == pg.K_RETURN:
print(" This mean the user wants to play again or said YES")
# So I can have some code here for what I want
if ev.key == pg.K_SPACE:
print("User does not want to continue")
# Will exit the program
run = True

Related

I am busy creating a simple 2D game. Before the start I would like the players to fill in their names based on the colour of their choice

I am in the process of developing a very basic 2d style board game.
I would like the players to enter their names rather than have Player 1, 2, 3, 4 displayed on the screen. The names need to correlate with a specific colour. There are only four options (red, green, blue, yellow). One colour = One player.
I have the following code:
# create a font object
font = pygame.font.Font(None, 36)
# create a dictionary to store the player names
player_names = {}
# create a list of player colors
player_colors = \['red', 'green', 'blue', 'yellow'\]
# create a loop to get the player names
for color in player_colors:
# initialize the player name to an empty string
player_names\[color\] = ''
# wait for the player to enter their name
while True:
# display a prompt for the player to enter their name
prompt_text = f'Enter name for {color} player: {player_names[color]}'
prompt = font.render(prompt_text, True, (255, 255, 255))
screen.fill((0, 0, 0))
screen.blit(prompt, (100, 100))
pygame.display.flip()
# check for keyboard input
keys = pygame.key.get_pressed()
# process events
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
# add the character to the player name
if event.unicode.isalpha() or event.unicode.isdigit():
player_names[color] += event.unicode
# delete the last character of the player name
elif event.key == pygame.K_BACKSPACE:
player_names[color] = player_names[color][:-1]
# end the loop when the player presses the enter key
elif event.key == pygame.K_RETURN:
break
# main game loop
Problem:
I cannot see the cursor when typing.
I enter the name Aaron. Push enter. Nothing happens.
If I incorrectly type my name I cannot correct it using backspace or the arrow key to move the cursor.
My desired outcome:
I would like to see a cursor so the player knows they can type even when it says type name.
When I am finished entering my name and push enter, I would like it to go to the next colour/player to enter their names.
I would like the players to edit errors before they move on.
How can I do this?

Threading issue with Pygame

I am developing a small game for learning purposes. I have created a simple animation for the title screen. Since there is also a function for full screen in the code, I wanted to create a title screen that:
Displayed the animation
Turned into full screen when the key was activated
Continued the animation at the point it was before activating full screen
In order to do this, I resorted to threading. However, this is the first time I tried to do any multi-threading, and I don´t know what did I do wrong. The result is an undetermined error.
The code for the title screen is this:
try:
GameAnimation = threading.Thread(target=GameTitleAnimation, (Window, WindowDimensions, FontDictionary, CurrentVersion))
GameAnimation.start()
except:
print "There was an error while loading the screen. Press one key to exit the program."
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
Quit()
if event.type == pygame.KEYDOWN:
if event.key == K_ESCAPE:
Quit()
elif event.key == K_f:
Fullscreen(Window, WindowDimensions)
else:
return
The code for the animation is:
TitleWhite = [255, 255, 255, 0]
Black = BASE_BLACK
TitleLetters = ("R", "O", "G", "U", "E", " ", "H", "U", "N", "T", "E", "R")
Title = FontDictionary["TitleFont"][1].render("ROGUE HUNTER", False, TitleWhite)
TextWidth = Title.get_width()
TextHeight = Title.get_height()
TitleXPosition = (WindowDimensions[0] - TextWidth) / 2
TitleYPosition = (WindowDimensions[1] / 2) - (TextHeight / 2)
for letter in TitleLetters:
if letter == " ":
TitleXPosition += CurrentLetterWidth
else:
while TitleWhite[3] < 100:
TitleWhite[3] += 1
CurrentLetter = FontDictionary["TitleFont"][1].render(letter, False, TitleWhite)
CurrentLetter.set_alpha(TitleWhite[3])
Window.blit(CurrentLetter, (TitleXPosition, TitleYPosition))
time.sleep(0.008)
try:
pygame.display.update()
except Exception:
traceback.print_exception
TitleWhite[3] = 0
CurrentLetterWidth = CurrentLetter.get_width()
TitleXPosition += CurrentLetterWidth
FadeInSurface = pygame.Surface((WindowDimensions[0], WindowDimensions[1]))
FadeInSurface.fill(TitleWhite)
OpacityRounds = 1
while TitleWhite[3] < 100.0:
TitleWhite[3] = 1.1 ** OpacityRounds
FadeInSurface.set_alpha(TitleWhite[3])
Window.blit(FadeInSurface, (0, 0))
OpacityRounds += 1
pygame.display.update()
time.sleep (0.015)
time.sleep(0.7)
TitleXPosition = (WindowDimensions[0] - TextWidth) / 2
Version = FontDictionary["BodyFont"][1].render(CURRENT_VERSION, False, TitleWhite)
VersionHeight = Version.get_height()
VersionWidth = Version.get_width()
VersionXPosition = (WindowDimensions[0] - VersionWidth) / 2
VersionYPosition = TitleYPosition + TextHeight
while True:
pygame.draw.rect(Window, Black, (0, 0, WindowDimensions[0], WindowDimensions[1]), 0)
Window.blit(Title, (TitleXPosition, TitleYPosition))
Window.blit(Version, (VersionXPosition, VersionYPosition))
pygame.display.update()
I'd be very grateful if anyone could help me with this. I am going crazy.
There's no reason to use threading in your code. It will only make your code harder to read, harder to debug and error prone.
Usually you want to have some kind of state in your game that you use to determinate what should happen in a frame. You can find a class based example here.
Another way to handle this, which is a bit similar to your code, is to use coroutines.
Look at your animation code and instead of calling pygame.display.update(), give the control back to the main loop. The main loop will handle events, frame limiting and drawing, then give control back to the coroutine (which keeps track of it's own state).
Here's a simple hacky example:
import pygame
import pygame.freetype
pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
def game_state(surf):
rect = pygame.Rect(200, 200, 32, 32)
while True:
events = yield
pressed = pygame.key.get_pressed()
x = 1 if pressed[pygame.K_RIGHT] else -1 if pressed[pygame.K_LEFT] else 0
rect.move_ip(x*5, 0)
pygame.draw.rect(surf, pygame.Color('dodgerblue'), rect)
yield
def title_state(surf):
text = 'Awesome Game'
colors = [[255, 255, 255, 20] for letter in text]
font = pygame.freetype.SysFont(None, 22)
font.origin = True
while True:
for color in colors:
color[3] += 33
if color[3] > 255: color[3] = 0
x = 200
for (letter, c) in zip(text, colors):
bounds = font.get_rect(letter)
font.render_to(surf, (x, 100), letter, c)
x += bounds.width + 1
font.render_to(surf, (180, 150), 'press [space] to start', pygame.Color('grey'))
events = yield
yield
def main():
title = title_state(screen)
game = game_state(screen)
state = title
while True:
events = pygame.event.get()
for e in events:
if e.type == pygame.QUIT:
return
if e.type == pygame.KEYDOWN:
if e.key == pygame.K_ESCAPE:
return
if e.key == pygame.K_SPACE:
state = game if state == title else title
if e.key == pygame.K_f:
if screen.get_flags() & pygame.FULLSCREEN:
pygame.display.set_mode(size)
else:
pygame.display.set_mode(size, pygame.FULLSCREEN)
screen.fill(pygame.Color('grey12'))
next(state)
state.send(events)
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
See how the main loop is clean and simple, and all of the game state is handled in the coroutines. The title screen part of the code does not care about fullscreen or not or how to switch to fullscreen, and the main loop does not care of what the title screen coroutine does. And we don't need threading.
In practice it's not that different from the class based example I linked above, but using coroutines makes it easy to implement the title screen animation.
Basically you have an endless loop, you mutate some state (like the color of a letter), and then say "now draw this!" by just calling yield.
This is a large chunk of code to debug.
I'm not familiar with pygame or python threading, but it seems to me that you need to include some debug lines to determine exactly where the error occurs during your game animation thread (if it's even occuring there at all).
Something like this pattern should help determine the source of the problem:
import logging
logging.info("start animation initialization")
...
logging.info("begin animation loop")
...
logging.info("end animation loop")
https://docs.python.org/2/howto/logging.html

Different page from different functions

I'm trying to get pygame to display different pages based on functions called that's determined randomly. Ideally, when the right buttons are pressed, it'll move on to the next page automatically. When running this, the pygame window just stops responding. Any insight would be appreciated.
Running on Python 3x and pygame 1.9.5
import pygame
from pygame.locals import *
import random
import keyboard
pygame.init()
display_width = 500
display_height = 500
black = (0,0,0)
white = (255,255,255)
gd = pygame.display.set_mode((display_width,display_height))
myfont = pygame.font.SysFont("Arial", 30)
def rw():
gd.fill(white)
letter = myfont.render("Press r and w",0,(black))
gd.blit(letter,(100,100))
pygame.display.flip()
while True:
try:
if keyboard.is_pressed('r+w'):
break
else:
pass
except:
break
def yk():
gd.fill(white)
letter = myfont.render("Press y and k",0,(black))
gd.blit(letter,(100,100))
pygame.display.flip()
while True:
try:
if keyboard.is_pressed('y+k'):
break
else:
pass
except:
break
def ctsh():
gd.fill(white)
letter = myfont.render("Press CTRL and Shift",0,(black))
gd.blit(letter,(100,100))
pygame.display.flip()
while True:
try:
if keyboard.is_pressed('ctrl+shift'):
break
else:
pass
except:
break
my_sample = random.sample(range(3), 3)
for i in my_sample:
if my_sample[i] == 0:
rw()
if my_sample[i] == 1:
yk()
if my_sample[i] == 2:
ctsh()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
pygame.display.update()
As I mentioned in comments, the main part of the problem is your attempt to use something called the keyboard module with pygame, which generally requires you to use its own event-processing model to obtain input from the user.
Normally that wouldn't be too much of a problem, but in this case it's a little more difficult because of three things:
In your current program, you have each page function doing it's own keyboard handling.
The page functions have too much repetitive code.
Some the the keys you want to detect actually correspond to two different physical keys on standard keyboards, namely the Shift and Ctrl keys.
The following shows some methods of addressing these issues. It reduces the code repetition by what is called OOP (object oriented programming)—which in this case is by defining a generic Page class that can represent each of the pages you want to display along with methods containing the common code needed to handle them.
It deals with the dual key mapping by separating them from the regular keys so both physical keys they corresponds to can be detected. (This wouldn't be necessary if you restricted yourself to specifying the exact key, such as the left Shift key (K_LSHIFT) or the right Ctrl key (K_RCTRL), instead of KMOD_SHIFT and KMOD_CTRL which can be used to designate either of pair—a list of all the key name constants is shown here in the pygame documentation.) In other words, the code makes it possible to specify KMOD_CTRL to mean either one of them, whereas passing K_LCTRL and K_RCTRL would mean pressing both of them at the same time is required.
To support event processing for the currently displayed Page, the main event processing loop checks whether the required key(s) are being pressed by calling the current page's keys_pressed() method to determine whether the required key(s) are all being pressed at once.
import pygame
from pygame.locals import *
import random
DISPLAY_WIDTH, DISPLAY_HEIGHT = 500, 500
BLACK = 0, 0, 0
WHITE = 255, 255, 255
# Modifier keys which which correspomd to two different keys on keyboards.
DUAL_MODIFIERS = {KMOD_SHIFT, KMOD_CTRL, KMOD_ALT, KMOD_META}
class Page:
def __init__(self, title, background, message, text_color, *keys):
""" Save everything needed to show page and detect its keys. """
self.title = title
self.background = background
self.message = message
self.text_color = text_color
# Create two lists and put each key into one or the other
# depending on whether it's a "dual modifier".
lists = (self.keys, self.dual_mods) = [], []
for key in keys:
lists[key in DUAL_MODIFIERS].append(key)
def keys_pressed(self):
""" Check whether all keys are all being pressed simultaneously. """
pressed, mods = pygame.key.get_pressed(), pygame.key.get_mods()
return (all(pressed[key] for key in self.keys) and
all((mods & dual_mod) for dual_mod in self.dual_mods))
def show(self, surface, font):
pygame.display.set_caption(self.title)
surface.fill(self.background)
img = font.render(self.message, True, self.text_color)
surface.blit(img, (100, 100))
pygame.display.flip()
def main():
pygame.init()
screen = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
msg_font = pygame.font.SysFont("Arial", 30)
# Create a list of Page instances.
pages = [Page("RW Page", WHITE, "Press r and w", BLACK, K_r, K_w),
Page("YK Page", WHITE, "Press y and k", BLACK, K_y, K_k),
Page("CTSH Page", WHITE, "Press Ctrl and Shift", BLACK, KMOD_CTRL,
KMOD_SHIFT)]
current_page = random.choice(pages) # Start with random initial page.
current_page.show(screen, msg_font)
while True: # Process events until terminated.
event = pygame.event.poll()
if event.type == QUIT:
break
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE: # Keypress to quit?
break
elif current_page.keys_pressed():
# Select a different page to display.
new_page = current_page
while new_page == current_page:
new_page = random.choice(pages)
current_page = new_page
current_page.show(screen, msg_font)
pygame.quit()
# Run application.
main()
A closing comment:
I don't know exactly the purpose of your application, but think you should seriously reconsider the design of its human interface—needing to press multiple keys simultaneously is somewhat awkward and assigning a different combination of them to each page makes them hard to remember due to the lack of consistency (and is unnecessary especially since it always does the same thing of just switching to a different random page).

Pygame text input not on screen

I need to kb input onto a pygame screen
at the moment it appears on the idle shell
any advice would be appreciated.
This code is extracted from a larger program
mostly screen based but i need to input some
data (numeric) from the kb at times
import sys
import pygame
from pygame.locals import *
pygame.init()
N= ''
screen = pygame.display.set_mode((600,600))
font= pygame.font.Font(None,40)
screen.fill((255,255,255))
pygame.display.flip
pygame.display.update()
def score(C,y):
SetWnd = font.render( C,True,(0,0,255))
screen.blit(SetWnd, (15, 100+y))
pygame.display.update()
def start():
while True:
name=''
for evt in pygame.event.get():
if evt.type == KEYDOWN:
if evt.unicode.isalnum(): # unicode
name+=evt.unicode
print name,
elif evt.key == K_BACKSPACE:
name = name[:-1]
print name,
elif evt.key == K_RETURN:
return N
elif evt.type == QUIT:
pygame.quit()
sys.exit()
def Pchange(c,y):
block = font.render(N, True, (0,0,0))
rect = block.get_rect()
rect.move_ip(75,100 + y)
screen.blit(block,rect)
pygame.display.flip()
score('wind', 0)
score('elev',20)
N = start()
Pchange(N,0)
Pchange(N,20)
Firstly you draw the score twice, which i assume works well.
The problem lies in you start function.
You are not calling any draw or update function in your while loop.
In your event foreach, you add a digit to name, and exit the while loop when enter is pressed. Then you draw twice with Pchange, but you are the function does not use the right parameters. You have:
def Pchange(c,y):
block = font.render(N, True, (0,0,0))
you are using the global N which is ''. So to fix that, you need to change N to c.
The next problem is that the game quits right after pressing enter. Since you pasted only a part of the program, this might not be the case. If it is, make another while loop, and just wait for the ESC key to call pygame.quit() and sys.exit()

Combining Code from two programs in Python

My question is kinda complicated as I run it through my head but I will try to explain it as best I can. I have 2 python codes, one that I created with Python for a Mastermind game and then the other in Pygame for a Mastermind board to play it on. My question is simply this: How can I combine both of these codes into 1 to have it play from Pygame and not the command prompt window I usually get?
I'm sorry if this sounds all gibberishy, but thats my question. I merely want to take my Python code and implement it into the Pygame code and have the game run like it's supposed to.
Heres the code for the game:
import random
class InvalidMove(Exception):pass
class Game:
def __init__(self):
self.colors=('r','g','b','y')
self.to_guess=[random.choice(self.colors) for i in range(4)]
def match_guess(self,guess):
if len(guess)!=len(self.to_guess) or [g for g in guess if g not in self.colors]:
raise InvalidMove()
ret=[0,0]
usedindexes=[]
for i,g in enumerate(guess):
if g==self.to_guess[i]:
ret[0]+=1
usedindexes.append(i)
for i,g in enumerate(guess):
if i in usedindexes: continue
for j,c in enumerate(self.to_guess):
if c==g and j not in usedindexes:
ret[1]+=1
usedindexes.append(j)
return ret
class UI:
def make_move(self):
guess=raw_input("Guess: ")
return guess.split()
def main(self):
print("The game begins...")
print("Possible colors (enter first letter): [r]ed [g]reen [b]lue [y]ellow")
print("Enter your guess like: r g b y")
g=Game()
while True:
guess=self.make_move()
try:
bp,wp=g.match_guess(guess)
except InvalidMove:
print("Invalid guess, try again")
continue
print("Black pegs %s"%bp)
print("White pegs %s"%wp)
if bp==4:
print("You won!")
if __name__=="__main__":
u=UI()
u.main()
And here's the code for the board I made in Pygame:
import pygame
from pygame.locals import *
def draw_current(men, turn, spacing, corner):
current = len(men) - 1
pos = corner[0] + current * spacing[0], turn * spacing[1] + corner[1]
screen.blit(images[men[-1]], pos)
images = { K_r: pygame.image.load('red.png'), K_g: pygame.image.load('green.png'),
K_b: pygame.image.load('blue.png'), K_y: pygame.image.load('yellow.png'),
K_SPACE: pygame.image.load('empty.png') }
pygame.init()
SCREEN_SIZE = (640, 480)
background_image_filename = 'mastermind_board.jpg'
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
background = pygame.image.load(background_image_filename).convert()
screen.blit(background, (0, 0))
pygame.display.update()
men = []
margin = 5, 3
spacing = [x + m for m, x in zip(margin, images[K_r].get_size())]
corner = 74, 74
turn = 0
quit = False
while not quit:
for event in pygame.event.get():
if event.type == QUIT:
quit = True
break
if event.type == KEYUP:
if event.key in images:
#print event.key
men.append(event.key)
# update
draw_current(men,turn, spacing, corner)
if len(men) == 4:
turn += 1
men = []
pygame.display.update()
elif event.key in (K_q, K_ESCAPE):
quit = True
break
pygame.quit()
Any and all help/suggestions would be more than greatly appreciated.
As I'm sure you know, you can't just put it all in one file and have it run. You need to encapsulate the Mastermind game so you can run/update it from the pygame loop. It'd be cleaner if you keep the Mastermind game logic in a separate file and just import it, but it's not required.
Here's some semi-psuedocode:
import pygame
class Mastermind(object):
def update(self, *args):
pass #do stuff
pygame.init()
while not quit:
if event:
if event == "quit":
quit = True
else:
#update the game
Mastermind.update(args)
#update the board
pygame.display.update()
pygame.quit()
Of course, this won't work for you exactly, but I hope the idea that I'm explaining comes through.
Step 1. Fix your board so that it's a proper class definition.
Step 2. Write a third file that import the board and the game.
They're now "combined".
Now you have to do the hard work of fixing the Game to use the new, fancy Board you built.

Categories

Resources