I have a function that detects key presses but, when i use the function and detect 'a' it detects but if i detect 'd' it doesnt detect it, but if i put the function that detects the key 'd' before the function that detects the key 'a' it detects 'd', why so?
here is my code:
keys = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','space','1','2','3','4','5','6','7','8','9','0']
pygame_keys = [pygame.K_a,pygame.K_b,pygame.K_c,pygame.K_d,pygame.K_e,pygame.K_f,pygame.K_g,pygame.K_h,pygame.K_i,pygame.K_j,pygame.K_k,pygame.K_l,pygame.K_m,pygame.K_n,pygame.K_o,pygame.K_p,pygame.K_q,pygame.K_r,pygame.K_s,pygame.K_t,pygame.K_u,pygame.K_v,pygame.K_w,pygame.K_x,pygame.K_y,pygame.K_z,pygame.K_SPACE,pygame.K_1,pygame.K_2,pygame.K_3,pygame.K_4,pygame.K_5,pygame.K_6,pygame.K_7,pygame.K_8,pygame.K_9,pygame.K_0]
def key_pressed(key_press,one_click =False):
global key_function_run
if one_click:
key_function_run = True
if not one_click:
if kb.is_pressed(key_press):
return True
if one_click:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for i in range(len(keys)):
if event.type == pygame.KEYDOWN:
if key_press == keys[i]:
if event.key == pygame_keys[i]:
print(i)
return True
pass
And here is how i am using the function:
if x == 205:
player_lane = 2
if x == 60:
player_lane = 1
if x == 347:
player_lane = 3
#player movement
if peasy.key_pressed('a',True) and player_lane == 2:
x = 60
if peasy.key_pressed('a',True) and player_lane == 3:
x = 205
if peasy.key_pressed('d',True) and player_lane == 2:
x = 347
if peasy.key_pressed('d',True) and player_lane == 1:
x = 205
Make a dictionary from your lists:
key_dict = dict(zip(keys, pygame_keys))
And use pygame.key.get_pressed:
def key_hold(keys, key):
return keys[key_dict[key]]
keys = pygame.key.get_pressed()
is_a = key_hold(keys, 'a')
is_d = key_hold(keys, 'd')
If you want to use the KEYDOWN event, you have to be aware that pygame.event.get() get all the messages and remove them from the queue. See the documentation:
This will get all the messages and remove them from the queue. [...]
So you can call pygame.event.get only once per frame. Also see Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?. However you can use unicode property of the KEYDOWN event:
def key_down_event(event_list, c):
return any(e for e in event_list if e.type == pygame.KEYDOWN and e.unicode == c)
event_list = pygame.event.get()
is_a = key_down_event(event_list, 'a')
is_d = key_down_event(event_list, 'd')
If you want a function that detects both whether a key is held down or has been pressed, you need to count the frames of how long a key is pressed, for each key. Return True if the count for a key is 1 when you want to determine if the key was just pressed:
import pygame
key_count = {}
def key_pressed(keys, key, one_click):
pressed = keys[key]
key_count[key] = (key_count.get(key, 0) + 1) if pressed else 0
return key_count[key] == 1 if one_click else pressed
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()
run = True
while run:
clock.tick(100)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
a_once = key_pressed(keys, pygame.K_a, True)
d_hold = key_pressed(keys, pygame.K_d, False)
if a_once:
print(f'key event: {pygame.key.name(pygame.K_a)}')
if d_hold:
print(f'key pressed: {pygame.key.name(pygame.K_d)}')
pygame.display.flip()
pygame.quit()
exit()
You shouldn't need to make a custom function for input handling, you can use something like this:
running = True
def main():
# Your normal game loop
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Gets a list of the currently pressed keys,
# this is updated because we put it in the while loop
kbd = pygame.key.get_pressed()
if kbd[pygame.K_a]:
print("I just pressed the A button!") # You can run here whatever ya want
Edit: I realized OP wanted to use pygame.KEYDOWN instead of pygame.key.get_pressed(), so in that case, you can use something like this
while running:
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_d:
print("Pressed D!")
Hope I helped. If you have any questions, just leave a comment/reply/whatever!
I'm using Python 3.5 and I want to make multi-keystroke function. I want to make a function that notices Ctrl+Q but my program didn't notice it.
Here's my code:
import threading, pygame
from pygame.locals import *
from time import sleep
pygame.init()
screen = pygame.display.set_mode((1160, 640), 0, 0)
screen.fill((255, 255, 255))
pygame.display.flip()
def background():
number = 0
while True:
if number < 10:
number = number + 1
print(number)
sleep(1)
else:
print("10 seconds are over!")
break
def foreground():
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.key.get_mods() & pygame.KMOD_CTRL and pygame.K_q:
print('HELLO_WORLD')
b = threading.Thread(name='background', target=background)
f = threading.Thread(name='foreground', target=foreground)
b.start()
f.start()
I also changed
def foreground():
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.key.get_mods() & pygame.KMOD_CTRL and pygame.K_q:
print('HELLO_WORLD')
to
def foreground():
while True:
key = pygame.key.get_pressed()
if key[pygame.key.get_mods() & pygame.KMOD_CTRL and pygame.K_q]:
print('HELLO_WORLD')
but it didn't notice Ctrl+Q.
How can I make it?
Here's a possible fix for your code:
import threading
import pygame
from pygame.locals import *
from time import sleep
import sys
pygame.init()
screen = pygame.display.set_mode((1160, 640), 0, 0)
screen.fill((255, 255, 255))
pygame.display.flip()
def background():
number = 0
while True:
if number < 10:
number = number + 1
print(number)
sleep(1)
else:
print("10 seconds are over!")
break
def foreground():
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if pygame.key.get_mods() & pygame.KMOD_CTRL and event.key == pygame.K_q:
print('HELLO_WORLD')
pygame.display.update()
b = threading.Thread(name='background', target=background)
b.start()
foreground()
I'm trying to implement a pause function in my tamagotchi clone (I'm practising for my controlled assessment next year) and I can't get the left and up keys to work simultaneously as a pause button. If possible I want to stay as true to the original game as possible so I would prefer not to use on-screen buttons. Thanks!
import pygame
import time
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
size =(200, 200)
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Tama v4.5')
screen.fill(WHITE)
pygame.init()
clock = pygame.time.Clock()
sprites = ['AdultSpriteAAA.png']
up_pressed = False
left_pressed = False
right_pressed = False
def main():
controls()
if up_pressed == True and left_pressed == True:
time.sleep(2)
pause()
player_position = pygame.mouse.get_pos()
x = player_position[0]
y = player_position[1]
screen.blit(background, [0,0])
screen.blit(sprite, [x, y])
pygame.display.flip()
clock.tick(60)
def controls():
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
elif event.type == pygame.MOUSEBUTTONDOWN:
print(animate())
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
global up_pressed
right_pressed = True
if event.key == pygame.K_LEFT:
global left_pressed
left_pressed = True
if event.key == pygame.K_RIGHT:
global right_pressed
right_pressed = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_UP:
global up_pressed
right_pressed = False
if event.key == pygame.K_LEFT:
global left_pressed
left_pressed = False
if event.key == pygame.K_RIGHT:
global right_pressed
right_pressed = False
def info():
return 0
def food():
return 1
def toilet():
return 2
def game():
return 3
def connect():
return 4
def talk():
return 5
def medic():
return 6
def post():
return 7
def history():
return 8
def animate():
return 9
def pause():
time.sleep(2)
while True:
controls()
if up_pressed == True and left_pressed == True:
time.sleep(2)
break
sprite = pygame.image.load(sprites[0]).convert()
background = pygame.image.load('Background 200x200.png').convert()
sprite.set_colorkey(BLACK)
while True:
main()
A way to make it pause when both left iey and up key are pressed is this:
import pygame
from pygame.locals import *
#game code
…
def pause():
keyspressed = pygame.keys.get_pressed()
if keyspressed[K_LEFT] and keyspressed[K_UP]:
#pause code
…
This code should be correct, but if you find any weird things, try to research the pygame key module. Keep in note that K_LEFT and K_UP are from pygame.locals, which is imported seperately from pygame
Here is a method that I have found really useful when writing games in PyGame:
if event.type == pygame.KEYDOWN
if event.key == (pygame.K_RIGHT and pygame.K_LEFT):
while True: # Infinite loop that will be broken when the user press the space bar again
event = pygame.event.wait()
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: # decid how to unpause?
break #Exit infinite loop
An interesting tid-bit I only recently discovered is that pygame.key.get_pressed() returns a tuple of 1s and 0s representing all of the keys on the keyboard, and these can be used as booleans or indexed to get the effective "value" of a key. Some great tuts at http://programarcadegames.com/
I have been searching around and trying to fix this for hours. I have two scripts, one labeled main.py, and the other menu.py. I am trying to use a variable from main.py to control the actions of menu.py. The variable is set to the last keyboard input, in the main.py script, it does what it's supposed to. However, when I try to do it in menu.py, nothing happens, not error thrown, nor does the original animation I was trying to use happen. I have omitted parts of the code that I don't think are part of the problem to make it easier to read.
main.py code:
#!/usr/bin/env python
WIDTH = 512
HEIGHT = 416
FPS = 20
VERSION = "0.0.3"
FULLSCREEN = False
import pygame,sys,os,time
pygame.init()
display = pygame.display.set_mode((WIDTH,HEIGHT), pygame.DOUBLEBUF)
alpha_display = display.convert_alpha()
fpsClock = pygame.time.Clock()
keyPressed = 0
sys.path.insert(0, "scripts/")
from pygame.locals import *
from media import *
import color
import menu
def run():
display.fill(color.BLACK)
if (menu.active == True):
menu.update()
else:
pass
while (True): # Code to run loop
for event in pygame.event.get():
if (event.type == QUIT):
pygame.quit()
sys.exit()
if (event.type == pygame.KEYDOWN):
time.sleep(0.1)
keyPressed = event.key
elif (event.type == pygame.KEYUP):
keyPressed = 0
run()
pygame.display.update()
fpsClock.tick(FPS)
menu.py code:
from __main__ import *
page = "main"
selObj = 1
active = True
class o:
dee = False
def update():
if o.dee == False:
o.dee = True
global page
global selObj
global active
if page == "main": # Main menu
if (keyPressed == pygame.K_RETURN):
if (selObj == 1):
page = "singleplayer"
elif (selObj == 2):
pygame.quit()
sys.exit()
if (keyPressed == pygame.K_UP):
selObj -= 1
elif (keyPressed == pygame.K_DOWN):
selObj += 1
if (selObj >= 3):
selObj = 1
elif (selObj <= 0):
selObj = 2
if (selObj == 1):
print("test1"
elif (selObj == 2):
print("test2")
I believe I have found your problem. You are looking for pygame events in the update() function (by using keypressed), but you never call that function in the pygame events loop. I don't know if somewhere in the lines you left out you initialize keyPressed, but from what I see you don't (which should raise a ValueError exception). If you did initialize keyPressed in the menu.py file, you are not transferring the changed value from main.py to menu.py. The way I would recommend to fix that would be to call menu.update() within the event loop and have keyPressed as an argument.
from __main__ import *
page = "main"
selObj = 1
active = True
class o:
dee = False
def update(keyPressed):#<----#
if o.dee == False:
o.dee = True
global page
global selObj
global active
if page == "main": # Main menu
if (keyPressed == pygame.K_RETURN):
...
and in the main file:
...
def run():
display.fill(color.BLACK)
if (menu.active == True):
menu.update(keyPressed)#<-------#
else:
pass
while (True): # Code to run loop
for event in pygame.event.get():
if (event.type == QUIT):
pygame.quit()
sys.exit()
if (event.type == pygame.KEYDOWN):
time.sleep(0.1)
keyPressed = event.key
elif (event.type == pygame.KEYUP):
keyPressed = 0
menu.update(keyPressed)#<----#
run()
pygame.display.update()
fpsClock.tick(FPS)
...
You may have to modify your code further to make sure that your menu does not reset each time the mouse moves.
Hope this helped.
I'm trying to make a game in pygame, but for some reason actor and inp has the same value.
I tried to have them as arrays instead of classes, but it didn't solve the problem.
import pygame, sys
from pygame.locals import *
pygame.init()
screen=pygame.display.set_mode((640,360),0,32)
a=pygame.image.load('a.png')
class xy:
x=0
y=0
jump=0
actor=xy
inp=xy
def events():
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
return
elif event.type == KEYDOWN:
if event.key==K_LEFT:
inp.x=-1
elif event.key==K_RIGHT:
inp.x=1
elif event.key==K_UP:
inp.y=-1
elif event.key==K_DOWN:
inp.y=1
elif event.key==K_SPACE:
inp.jump=True
elif event.type==KEYUP:
if event.key==K_LEFT:
inp.x=0
elif event.key==K_RIGHT:
inp.x=0
elif event.key==K_UP:
inp.y=0
elif event.key==K_DOWN:
inp.y=0
elif event.key==K_SPACE:
inp.jump=False
return
def controller():
if inp.x<0:
actor.x-=1
elif inp.x>0:
actor.x+=1
if inp.y<0:
actor.y-=1
elif inp.y>0:
actor.y+=1
## actor.x+=inp.x
## actor.y+=inp.y
return
def screen_update():
pygame.draw.rect(screen, 0x006633, ((0,0),(640,360)),0)
screen.blit(a, (actor.x,actor.y))
pygame.display.update()
if __name__ == '__main__':
while True:
events()
print 'inp='+str(inp.x)+','+str(inp.y)
print 'actor='+str(actor.x)+','+str(inp.y)
controller()
screen_update()
Why can't the things I make work properly? :(
To put it simply, you're doing classes completely wrong.
class xy:
def __init__(self):
self.x = 0
self.y = 0
self.jump = 0
actor = xy()
inp = xy()