My python character only moves 1 pixel at a time - python
I am making a small little Parkour Minigame where the character jumps from platform to platform, but I can't seem to get the character to move properly. I made another game and it worked correctly, but this one doesn't. When I hold down the left/right arrow key it only moves 1 pixel at a time. Here are the V
Parkour_MoveLeft=Parkour_MoveRight=Parkour_Jump='no'
Parkour_Speed=1
Parkour_X=0
Parkour_Y=0
Parkour_Rows=0
Parkour_Col=0
Now here is my code for the part of the game I am having trouble with :
if location=='Parkour':
Window.fill(Black)
WindowW = 700
WindowH = 700
Window=pygame.display.set_mode((WindowW, WindowH),0, 32)
pygame.draw.rect(Window, Blue, Parkour_Character)
num=0
for point in Parkour_Grids:
mat=Parkour_Lvl_1[num]
num+=1
if mat=='a':
point['collide']='no'
if mat=='p':
pygame.draw.rect(Window, Green, point['rect'])
point['collide']='yes'
for point in Parkour_Grids:
if point['collide']=='yes':
if Parkour_Character.colliderect(point['left']):
Parkour_MoveRight='no'
if Parkour_Character.colliderect(point['right']):
Parkour_MoveLeft='no'
if Parkour_Character.colliderect(point['bottom']):
Parkour_MoveUp='no'
if Parkour_Character.colliderect(point['top']):
Parkour_MoveDown='no'
Parkour Movement
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
Parkour_MoveRight='yes'
if event.key == K_LEFT:
Parkour_MoveLeft='yes'
if event.type == KEYUP:
if event.key == K_RIGHT:
Parkour_MoveRight='no'
if event.key == K_LEFT:
Parkour_MoveLeft='no'
if Parkour_MoveLeft=='yes':
Parkour_Character.right-=Parkour_Speed
if Parkour_MoveRight=='yes':
Parkour_Character.right+=Parkour_Speed
Level Map
Parkour_Lvl_1=['a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','p','p','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','p','p','p','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a',
'a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a','a']
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
Parkour_Grids.append({'rect':pygame.Rect(Parkour_X, Parkour_Y, 80, 30),'right':1,'left':1,'top':1,'bottom':1,'type':'air','collide':'yes'})
Parkour_X+=80
Parkour_Col+=1
if Parkour_Col==40:
Parkour_Col=0
Parkour_X=0
Parkour_Y+=70
Parkour_Rows+=1
if Parkour_Rows==10:
break
for point in Parkour_Grids:
point['right']=pygame.Rect(point['rect'].left+70,point['rect'].top , 6, 70)
point['left']=pygame.Rect(point['rect'].right-76,point['rect'].top , 6, 70)
point['top']=pygame.Rect(point['rect'].left+6,point['rect'].top-15 , 58, 6)
point['bottom']=pygame.Rect(point['rect'].left+6,point['rect'].bottom+6 , 58,6)
Anyone have any help on what I can do? It's the exact same code at another game I made (with different variables), but this one doesn't seem to work.
You need to raise Parkour_Speed. It is set to one, and because it does not look like you have ever multiplied it or implemented a movement twice, that is exactly how many pixels it will move. Upping this number will make it move more pixels at one time. However, while it isn't explicitly clear if this is your issue, it is also possible that it is not moving continuously when you press the button. If the event finder is not being run constantly, this will definitely happen, however because checking events is implemented at the same time, this is probably not the case (with more code it would be easier to know). Another thing that you must repeatedly implement to continuously move your sprite across the screen is where you sync Parkour_X and Y with the screen. I do not see where you do this in the code, but I think it should be easiest to use the move_ip function to solve your problems. Provided that the screen is being updated, this modification to your code should solve your issues:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_RIGHT:
Parkour_MoveRight='yes'
if event.key == K_LEFT:
Parkour_MoveLeft='yes'
if event.type == KEYUP:
if event.key == K_RIGHT:
Parkour_MoveRight='no'
if event.key == K_LEFT:
Parkour_MoveLeft='no'
if Parkour_MoveLeft=='yes':
Parkour_Character.move_ip(-Parkour_Speed,0)
if Parkour_MoveRight=='yes':
Parkour_Character.move_ip(Parkour_Speed,0)
If this also does not solve your problem, everything else seems fine, so it may be useful to include even more code. I know you have a lot of code up already, but simple features in graphical programs such as this one tend to be very interconnected.
Related
I want my character to do something as long as I'm holding a button, then go back to normal once I let go of the button
I'm creating my first game. I'm working with Python and PyGame. So far everything has been going great, but I've ran into a problem that I can't seem to solve: I want my character to do a certain movement as long as I'm pressing a button. Normally when you want to make your character move, I would do if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: With this, the character does something when you press space, but it only does it once if you HOLD space. I thought I'd do this if event.type == pygame.KEYDOWN: while event.key = pygame.K_SPACE But when I run this and press space, the program blocks, and I get the 'program isn't reacting' thing. So, one last time. I want my character to do something when I hold space, and when I let go I want it to go back to how it was. For example: My character is walking by default. When I hold space I want it to crawl for as long as I hold space. And then finally I want it to go back to normal walking once I let go of space. Is this possible?
Set a state (spacePressed) if SPACE is pressed when the KEYDOWN event is received. Reset the state and rest the position of the character if the SPACE is released and KEYUP is received. Move the character dependent on spacePressed in the main application loop e.g.: spacePressed = False while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: spacePressed = True if event.type == pygame.KEYUP: if event.key == pygame.K_SPACE: spacePressed = False # reset character # [...] if spacePressed: # move character # [...] Another option is to use pygame.key.get_pressed() to get the pressed keys in the main application loop and reset the position of the character if the KEYUP event is received: while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYUP: if event.key == pygame.K_SPACE: # reset character # [...] keys = pygame.key.get_pressed() if keys[pygame.K_SPACE]: # move character # [...]
Pygame function with loops
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 ...]
Pygame, move a rectangle and remove the old rectangle in precedent position
I'm writing this code because I want to move a rectangle using the arrow keys. It works, but the loop cycle doesn't move the rectangle, instead it creates a new one every time. The result is like a contrail. You can see it in the pic:the result of the code after some key pressure Here the code I wrote: import sys import pygame pygame.init() pygame.display.set_caption('SAGA') clock=pygame.time.Clock() FPS=30 #the initial position POS_X=300 POS_Y=300 ship = pygame.image.load("fighter_0.png") while True: #if cycle for detect the key pressure 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_UP: POS_Y=POS_Y-10 if event.type == pygame.KEYDOWN: if event.key ==pygame.K_DOWN: POS_Y=POS_Y+10 if event.type == pygame.KEYDOWN: if event.key ==pygame.K_RIGHT: POS_X=POS_X+10 if event.type == pygame.KEYDOWN: if event.key ==pygame.K_LEFT: POS_X=POS_X-10 #here i draw the rectangle pygame.draw.rect(screen,(255,255,255),(POS_X,POS_Y,30,30)) clock.tick(FPS) pygame.display.update() pygame.quit() I think I don't understand some principle of pygame, but honestly I don't know which one.
It's doing exactly what you told it to do: draw a new rectangle each time. Computers are frustrating that way. You used draw instead of moving an object. To fix this, you have two basic alternatives: In each iteration, first obliterate the previous rectangle with one that matches the background (black). Then draw the new rectangle. Use a movable object, such as a sprite, and update your game with the move method instead of redrawing. If you search StackOverflow or the internet for "pygame move object" you'll likely find a lot of code you can adapt for this purpose.
Each time you run your loop, you draw over the old screen's image. So in your case you are drawing rectangles on top of the previous rectangles. You need to clear the screen of what was there on the previous iteration of the loop. The easiest way to do this is to fill the screen with a single colour or image: import sys import pygame # Colours black = [0, 0, 0] pygame.init() screen = pygame.display.set_mode((640,480)) pygame.display.set_caption('SAGA') clock=pygame.time.Clock() FPS=30 #the initial position POS_X=300 POS_Y=300 ship = pygame.image.load("fighter_0.png") while True: #if cycle for detect the key pressure 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_UP: POS_Y=POS_Y-10 if event.type == pygame.KEYDOWN: if event.key ==pygame.K_DOWN: POS_Y=POS_Y+10 if event.type == pygame.KEYDOWN: if event.key ==pygame.K_RIGHT: POS_X=POS_X+10 if event.type == pygame.KEYDOWN: if event.key ==pygame.K_LEFT: POS_X=POS_X-10 #here i draw the rectangle screen.fill(black) # Fill the entire screen with black pygame.draw.rect(screen,(255,255,255),(POS_X,POS_Y,30,30)) clock.tick(FPS) pygame.display.update() pygame.quit()
Pygame I can move an image once but don't know how to move it twice
I have a box that i want to move in increments, i know how to move it by an increment but only once. I don't how i'd do this multiple times. anyone got any ideas? The box: highlight = pygame.draw.rect(window, (darkYellow),(30, 300, 130, 40),0) Moving the box (this is to move it once) while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit(); sys.exit() if event.type == pygame.KEYDOWN and pygame.K_RIGHT: highlight = pygame.draw.rect(window, (darkYellow),(260, 300, 130, 40),0) difficultyText = myFont.render("Difficulty", 1, red) window.blit(difficultyText, (260, 300)) pygame.display.update() Takes any key input when i only want it to activate when the key "ARROW DOWN" is pushed if event.type == pygame.KEYDOWN and pygame.K_DOWN: window.blit(arrowImg, (5,400)) pygame.display.update()
There are few issues with your code. You are drawing, rendering text and bliting in your event loop. You should move them out of the loop body. It seems that you want to have a cursor that will change its position with the right arrow key. To do this have a variable that will tell you where your cursor is. Then your draw statement will look like this: pygame.draw.rect(window, (darkYellow),(30+cursorPos*230, 300, 130, 40),0) EDIT: As for why event.type == pygame.KEYDOWN and pygame.K_DOWN is true for all KEY_DOWN events, is because it can be translated to (event.type==pygame.KEYDOWN) and pygame.K_DOWN. Since pygame.K_DOWN is a non zero value, it is true when evaluated as a boolean value. To fix this you want to do something like this: event.type == pygame.KEYDOWN and event.key == pygame.K_DOWN
Pygame: key.get_pressed() does not coincide with the event queue
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