Okay, so I am writing a script that controls the motors using a sbc motor shield board with my raspberry pi 3b.
The issue I am having is that if I just run the script a window will pop up for a split second allowing to press the a key to move the motor forward or any other keys that I have already defined within the script but it only last for a second before the window auto exits and I am returned to the terminal.
Now when I attempt to add a loop to keep the code running the window will stay open however it no longer recognizes when I press a key defined in the script.. I have spent hours researching and modifying the script I have wrote and have not been able to find a solution. I am very new to python and I appreciate any input given.
Also I am running python 3.6 thanks in advance
import pygame
import sys
import pygame.locals
import PiMotor
import time
m1 = PiMotor.Motor("MOTOR1",1)
m2 = PiMotor.Motor("MOTOR2",1)
pygame.init()
(width, height) = (300, 200)
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Johnny, motor controls!')
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.locals.QUIT:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
m1.forward(100), time.sleep(0)
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
m1.stop()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
m1.forward(100)
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
m1.stop()
You just need to add a while True: when you get the events and check when to quit.
If you tried it and it didn't work maybe you had your indentation wrong? I see that it is wrong now in the code that you posted.
Something like:
while True:
for event in pygame.event.get():
if event.type == pygame.locals.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
m1.forward(100), time.sleep(0) # BTW, do you really need this sleep?
[... Rest of your code ...]
I'm using pygame and pyautogui to move the mouse around the screen in python 2.7. My code looks like:
import pyautogui
import pygame
pygame.init()
pygame.display.set_mode()
loop = True
while loop:
for event in pygame.event.get():
if event.type == pygame.quit:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
pyautogui.moveRel(-50,0)
My code moves the mouse to the left when I press "a" but I have to repeatedly press the button when I want to move the mouse across the screen. Is there a way to be able to press and hold a and move the mouse across the screen? I've looked at other tutorials on this topic but they seem very project specific.
Basically, what you want to do is set a variable indicating whether the key is down on keydown and update it once key is up.
Here, I updated your code to do just that as it might be easier to understand.
import pyautogui
import pygame
loop = True
a_key_down = False # Added variable
while loop:
for event in pygame.event.get():
if event.type == pygame.quit:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
a_key_down = True # Replaced keydown code with this
if event.type == pygame.KEYUP: # Added keyup
if event.key == pygame.K_a:
a_key_down = False
if a_key_down: # Added to check if key is down
pyautogui.moveRel(-50,0)
I am using a function to wait until a controller is present, but i ran into a problem. I wanted the function to stop when I press a key. Usually these events are handled just fine, but in this part it works terrible. The event seems to be added to the event queue very late or sometimes not at all. My guess is that it is because of the uninitialisation and reinitialisation of pygame.joystick. I just don't know how to solve it. I used this program to create the error:
import pygame, sys
from pygame.locals import *
pygame.init()
SCREEN = pygame.display.set_mode((500,500))
ChangeRun = False
pygame.joystick.init()
if pygame.joystick.get_count() == 0:
while pygame.joystick.get_count() == 0:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type in [KEYUP, KEYDOWN]:
if event.key == K_ESCAPE:
ChangeRun = True
if ChangeRun == True:
break
pygame.joystick.quit()
pygame.joystick.init()
pygame.quit()
sys.exit()
I wanted to use the escape key to end the program, but only after a lot of pressing it works. The same happens with the QUIT event. When printing the events I found that most of the time no event was found.
I use windows 8.1 and python 3.4 and pygame 1.9.2
I have no joystick so I can't test it but normally I would do this similar to mouse and I wouldn't wait for controller:
import pygame
from pygame.locals import *
pygame.init()
pygame.joystick.init()
screen = pygame.display.set_mode((500,500))
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
elif event.type == JOYBUTTONDOWN:
print 'joy:', event.joy, 'button:', event.button
# the end
pygame.joystick.quit()
pygame.quit()
I'm using pygame to draw a line:
import pygame
from pygame.locals import*
import sys
pygame.init()
screen = pygame.display.set_mode((600,500))
pygame.display.set_caption("Drawing Lines")
while True:
for event in pygame.event.get():
if event.type == KEYDOWN and event.key == K_DOWN:
sys.exit()
screen.fill((0,80,0))
color = 100,255,200
width = 8
pygame.draw.line(screen, color, (100,100), (500,400), width)
pygame.display.update()
for some reason, I can't get this is work:
while True:
for event in pygame.event.get():
if event.type == KEYDOWN and event.key == K_DOWN:
sys.exit()
It doesnt show any error, it just doesnt work. I want to be able to press the down key and have it quit the program but it doesnt do that. I have to quit the idle. Any help will do. thanks.
This is because KEYDOWN is just the event that a key is pressed down, not that the down key has been pushed. To fix this, you have to first check if a KEYDOWN event has happened, and if it has, check what key that was pushed.
for event in pygame.event.get():
if event.type == KEYDOWN and event.key == K_DOWN:
sys.exit()
Check out the docs on this subject to learn more.
I'm attempting to work out simple controls for an application using pygame in Python. I have got the basics working, but I'm hitting a weird wall: I am using the arrow keys to control my character. If I hold down one arrow key, then hold down another arrow key (to move diagonally), the character moves as expected. However, if I release the second key that I pressed (while still holding down the first key), the character stops moving, even though I am still holding down that first key. Here is my simple movement code:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if pygame.key.get_pressed()[K_LEFT]:
player.pos = (player.pos[0] - 2, player.pos[1])
if pygame.key.get_pressed()[K_RIGHT]:
player.pos = (player.pos[0] + 2, player.pos[1])
if pygame.key.get_pressed()[K_UP]:
player.pos = (player.pos[0], player.pos[1] - 2)
if pygame.key.get_pressed()[K_DOWN]:
player.pos = (player.pos[0], player.pos[1] + 2)
Now, I was naturally very confused by this. So I tried to print some lines to debug. In the top of the main control loop, I wrote:
print (pygame.key.get_pressed()[K_DOWN], pygame.key.get_pressed()[K_RIGHT])
print pygame.event.get()
...to output a tuple displaying the state of the down and right arrow keys, and then display the pygame event queue. My results baffled me even more. If I move the character diagonally down and right, pressing the down key first and then the right key, then release the right key to make it move simply downward, the character stops moving as before... but this is printed to the shell:
(1, 0)
[]
That is, when I release the right arrow key and still hold down the down arrow key, pygame.key.get_pressed() understands that the down arrow key is still being held down, but there is nothing in the event queue.
Also, earlier in the code (before the control loop) I am invoking
pygame.key.set_repeat(1, 2)
to make the character continue to move while the key is held down.
Any help will be appreciated! Thanks :)
For things like movement, you should not check for events (like KEYDOWN or KEYUP), but check every iteration of your mainloop if your movement keys are pressed (using get_pressed).
In your code, you check the pressed keys only if there's also a KEYDOWN event.
There are also some other things to consider:
You should seperate the key-mapping and the speed of your player, so it will be easier later on to change either of this.
You should determine a movement vector and normalize it first, since otherwise, if your vertical and horizontal movement speed is 10, your diagonal movement speed would be ~14.
Working example:
import pygame
pygame.init()
screen = pygame.display.set_mode((200, 200))
run = True
pos = pygame.Vector2(100, 100)
clock = pygame.time.Clock()
# speed of your player
speed = 2
# key bindings
move_map = {pygame.K_LEFT: pygame.Vector2(-1, 0),
pygame.K_RIGHT: pygame.Vector2(1, 0),
pygame.K_UP: pygame.Vector2(0, -1),
pygame.K_DOWN: pygame.Vector2(0, 1)}
while run:
for e in pygame.event.get():
if e.type == pygame.QUIT: run = False
screen.fill((30, 30, 30))
# draw player, but convert position to integers first
pygame.draw.circle(screen, pygame.Color('dodgerblue'), [int(x) for x in pos], 10)
pygame.display.flip()
# determine movement vector
pressed = pygame.key.get_pressed()
move_vector = pygame.Vector2(0, 0)
for m in (move_map[key] for key in move_map if pressed[key]):
move_vector += m
# normalize movement vector if necessary
if move_vector.length() > 0:
move_vector.normalize_ip()
# apply speed to movement vector
move_vector *= speed
# update position of player
pos += move_vector
clock.tick(60)
just use the events return data, instead of trying to poll, you're already checking if its a keydown event TYPE, now just interrogate the KEY index, like so:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_LEFT:
player.pos = (player.pos[0] - 2, player.pos[1])
rest of code.....
also consider using a separate data structure to store the state of your controls, then just use the events to update that data structure. That will help make the controls a bit more flexible as you wont be relying on the event queue to cause your character to move, which in my experience causes problems like: not being able to push more than two buttons at a time, and odd delay or timing issues with character movements. so something like:
keystates={'up':False, 'down':False, 'left':False, 'right':False}
running=True
#start main pygame event processing loop here
while running:
for event in pygame.event.get():
if event.type == QUIT:
running=False
#check for key down events
if event.type == KEYDOWN:
if event.key == K_UP:
keystates['up']=True
if event.key == K_DOWN:
keystates['down']=True
if event.key == K_LEFT:
keystates['left']=True
if event.key == K_RIGHT:
keystates['right']=True
#check for key up events
if event.type == KEYUP:
if event.key == K_UP:
keystates['up']=False
if event.key == K_DOWN:
keystates['down']=False
if event.key == K_LEFT:
keystates['left']=False
if event.key == K_RIGHT:
keystates['right']=False
#do something about the key states here, now that the event queue has been processed
if keystates['up']:
character.moveUp() #or whatever your call for these are...
if keystates['down']:
character.moveDown()
if keystates['left']:
character.moveLeft()
if keystates['right']:
character.moveRight()
#gracefully exit pygame here
pygame.quit()
You are using event-based input , but in this case you want polling-based input. Then you don't mess with key-repeats.
import pygame
from pygame.locals import *
done = False
player.pos = Rect(0,0,10,10)
while not done:
for event in pygame.event.get():
# any other key event input
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESC:
done = True
elif event.key == K_F1:
print "hi world mode"
# get key current state
keys = pygame.key.get_pressed()
if keys[K_LEFT]:
player.pos.left -= 10
if keys[K_RIGHT]:
player.pos.left += 10
if keys[K_UP]:
player.pos.top -= 10
if keys[K_DOWN]:
player.pos.left += 10
if keys[K_SPACE]:
print 'firing repeated gun'
My guess is that set repeat doesn't work the way that you think it will. Basically, after your second key goes up, the repeat doesn't happen. This would seem to make sense to me: open up a text editor and hold down the "A" key. "A"s will spill out across the screen. Then, press the "J" key with the "A" key still held down. The "A"s stop. That is a typical key repeat system.
I'm not sure using this "set_repeat" method is going to work out in the end anyway. Basically, any key that the player presses will now "repeat", even if they click "fire" or "jump".
As an alternative, try saving the state when the user presses or releases. Don't use the set_repeat, but do something like the following:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if pygame.key.get_pressed()[K_LEFT]:
player.moving_left = True
if pygame.key.get_pressed()[K_RIGHT]:
player.moving_right = True
if pygame.key.get_pressed()[K_UP]:
player.moving_up = True
if pygame.key.get_pressed()[K_DOWN]:
player.moving_down = True
elif event.type == KEYUP:
if pygame.key.get_pressed()[K_LEFT]:
player.moving_left = False
if pygame.key.get_pressed()[K_RIGHT]:
player.moving_right = False
if pygame.key.get_pressed()[K_UP]:
player.moving_up = False
if pygame.key.get_pressed()[K_DOWN]:
player.moving_down = False
# Somewhere else in your game loop...
if player.moving_left:
player.pos[0] -= 2
if player.moving_right:
player.pos[0] += 2
if player.moving_up:
player.pos[1] -= 2
if player.moving_right:
player.pos[1] += 2