I have this 2D platformer game in PyGame where a character moves left, right and up (jump). I recently implemented a function to pause the game, which works great.
However since the code stops the character on pygame.KEYUP then if the user lets off the side-moving keys (A for left, D for right) AFTER they have paused the game then after resuming the character will be stuck running since it never got the KEYUP event.
Any ideas that makes the character stop X-axis movement after pause? Thankful for any help!
Pause function:
def game_pause:
pause = True
while pause == True:
pygame.init()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
pause = False
Main
loop:
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
#---Key presses---
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
player.go_left()
elif event.key == pygame.K_d:
player.go_right()
elif event.key == pygame.K_SPACE:
player.jump()
elif event.key == pygame.K_RETURN:
game_pause()
elif event.type == pygame.KEYUP:
if event.key == pygame.K_a and player.change_x < 0:
player.stop()
elif event.key == pygame.K_d and player.change_x > 0:
player.stop()
Functions that moves the player-class:
def go_left(self):
self.change_x = -5
def go_right(self):
self.change_x = 5
def stop(self):
self.change_x = 0
Maybe you could set
pause = False
in the main loop and in the go_left(), go_right(), stop() functions make an if statement like
def go_left(self):
if not pause :
self.change_x = -5
so when you pause the game the if statement becomes false
Related
I'm a beginner in python and I am trying to learn the features of pygame in order to make a simple game. I want to move an image using the wasd keys, but it's not working. Please help.
I'm using python (3.7.0) on windows 10.
The following is the code:
import pygame
from pygame.locals import *
pygame.init()
pygame.display.init()
keys = [False, False, False, False]
screen=pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
background=pygame.Surface(screen.get_size())
background.fill((255,255,255))
playerpos=[100,100]
player=pygame.image.load("Copper.png")
while 1:
pygame.display.init()
screen.fill(0)
screen.blit(background,(0,0))
screen.blit(player,playerpos)
for event in pygame.event.get():
pygame.display.init()
pygame.display.flip()
if event.type == pygame.KEYDOWN:
if event.key==pygame.K_RETURN:
pygame.display.quit()
pygame.display.flip()
# 8 - loop through events
for event in pygame.event.get():
# 9 - check if event is X button
if event.type==pygame.QUIT:
# 10 - quit the game
pygame.quit()
exit(0)
if event.type == pygame.KEYDOWN:
if event.key==K_w:
keys[0]=True
elif event.key==K_a:
keys[1]=True
elif event.key==K_s:
keys[2]=True
elif event.key==K_d:
keys[3]=True
if event.type == pygame.KEYUP:
if event.key==pygame.K_w:
keys[0]=False
elif event.key==pygame.K_a:
keys[1]=False
elif event.key==pygame.K_s:
keys[2]=False
elif event.key==pygame.K_d:
keys[3]=False
# 9 - Move player
if keys[0]:
playerpos[1]-=500
elif keys[2]:
playerpos[1]+=500
if keys[1]:
playerpos[0]-=500
elif keys[3]:
playerpos[0]+=500
I expect the image "Copper.png" to move when I press w,a,s,d but the image does not move. The image does refresh everytime I press w,a,s,d but does not move.
Get rid of the multiple even handling loops. Use a single loop to handle all the events.
Further it is sufficient to init the display once (pygame.display.init())
Create a variable speed, which defines the number of pixels, the position of the image changes by each step
First evaluate the pygame.QUIT event and stop running the main loop when the event happens:
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
Then handle the other events like the pygame.KEYDOWN and pygame.KEYUP.
For a continuously movement, the manipulation of the player position has to be done outside the event loop. If it would be don in the loop, the the position of the player would only change if en event occurs. Note use a small "speed" (speed = 1), else the player would rapidly moved out of the window.
for event in pygame.event.get():
# event handling
if keys[0]:
playerpos[1]-=speed
elif keys[2]:
playerpos[1]+=speed
if keys[1]:
playerpos[0]-=speed
elif keys[3]:
playerpos[0]+=speed
Do the drawing of the scene at the end of main loop:
speed = 1
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key==pygame.K_RETURN:
done = True
for i in range(4):
if event.key == (K_w, K_a, K_s, K_d)[i]:
keys[i]=True
elif event.type == pygame.KEYUP:
for i in range(4):
if event.key == (K_w, K_a, K_s, K_d)[i]:
keys[i]=False
if keys[0]:
playerpos[1]-=speed
elif keys[2]:
playerpos[1]+=speed
if keys[1]:
playerpos[0]-=speed
elif keys[3]:
playerpos[0]+=speed
screen.fill(0)
screen.blit(background,(0,0))
screen.blit(player,playerpos)
pygame.display.flip()
Note, alternatively you can use pygame.key.get_pressed() to get all states of of all keyboard buttons at once. So you don't need to evaluate the key events separately:
speed = 1
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
done = True
allKeys = pygame.key.get_pressed()
playerpos[0] += -speed if allKeys[K_a] else speed if allKeys[K_d] else 0
playerpos[1] += -speed if allKeys[K_w] else speed if allKeys[K_s] else 0
screen.fill(0)
screen.blit(background,(0,0))
screen.blit(player,playerpos)
pygame.display.flip()
I know this question can be seen as a duplicate, but I spent some hours searching and figuring out what is wrong at my code.
My problem is that my object, called player, doesn't move constantly when left or right key is being held down:
for event in pygame.event.get():
if event.type == QUIT:
self.terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
self.terminate()
if event.key == K_LEFT or event.key == K_a:
self.moveRight = False
self.moveLeft = True
if event.key == K_RIGHT or event.key == K_d:
self.moveLeft = False
self.moveRight = True
if event.type == KEYUP:
if event.key == K_LEFT or event.key == K_a:
self.moveLeft = False
if event.key == K_RIGHT or event.key == K_d:
self.moveRight = False
# Move the player around
if self.moveLeft :
# Moves the player object to left with self.PLAYERMOVERATE pixels.
self.player.setLeftRight(-1 * self.PLAYERMOVERATE)
if self.moveRight :
self.player.setLeftRight(self.PLAYERMOVERATE)
I also tried this alternative:
while True:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.player.setLeftRight(-1 * self.PLAYERMOVERATE)
if keys[pygame.K_RIGHT]:
self.player.setLeftRight(self.PLAYERMOVERATE)
I think that the problem is that you are not handling the input in the main game loop.
In your code you seem to be handling the input inside a method of the object Player. This is not how input should be handled. In your second code example there is a while True: loop which will mean the loop is never exited from and thus the method's execution is never finished. I suspect that there may be a similar issue in your first example.
Instead you should:
Create all objects and classes.
Write the main game loop.
The main game loop should handle input, then process the logic of the game and then render whatever should be rendered.
Here is a short code example.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit() # Exit from pygame window
quit() # End python thread
if event.type == KEYDOWN:
if event.key == K_LEFT or event.key == K_a:
player.moveRight = False
player.moveLeft = True
if event.key == K_RIGHT or event.key == K_d:
player.moveLeft = False
player.moveRight = True
if event.type == KEYUP:
if event.key == K_LEFT or event.key == K_a:
player.moveLeft = False
if event.key == K_RIGHT or event.key == K_d:
player.moveRight = False
# Move player using method
if player.moveLeft:
# Move player
# ...
# Render player
I hope that this helped you and if you have any further questions please feel free to post them in the comment section below!
I am trying to get user keyboard input using pygame. However, the problem is that after I run my code on IDLE, the keyboard input is never read by the program, and whatever I type is shown on the shell. Same issue if I run my code on PyCharm. Any idea? Below is my code:
pygame.init()
screen = pygame.display.set_mode((800, 600))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == KEYDOWN and event.key == pygame.K_w:
print("Yup!")
pygame.display.flip()
I'm having the exact same issue, also on a Mac using Pycharm and python 3.6. I'm printing the events and only MouseMotion events are recorded, rather than KeyDown.
Edit: apparently it's a known issue: Window does not get focus on OS X with Python 3
This is my code, and it also should work:
while not crashed:
for event in pygame.event.get():
print(event)
if event.type == pygame.QUIT:
crashed = True
# get current list
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]:
print("UP")
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_1:
print('this DOES work! :)')
elif event.key == pygame.K_LEFT:
x_change = -5
elif event.key == pygame.K_RIGHT:
x_change = 5
elif pressed[pygame.K_UP]:
print("UP")
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
pygame.display.flip()
x += x_change
gameDisplay.fill(black)
ship(x, y)
pygame.display.update()
clock.tick(60)
This code works perfectly for me
import pygame
pygame.init()
windowSize = width,height = 800,600
screen = pygame.display.set_mode(windowSize)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
print("Yup!")
pygame.display.flip()
I'm making a simple top-down game with moving and collision between player and walls, using pygame.
I made my code so that when keys[pygame.K_LSHIFT] is True during the pygame.key.get_pressed at the state of the keyboard when it's called, block_speed changes to 5 instead of 3. So it works and when I hold SHIFT and move with WASD keys at the same time my speed becomes 5.
Now, the problem is when I let go of SHIFT while still moving, my speed doesn't change back to 3 but stays at 5. But if I stop moving, then move, block_speed changes back to 3 as expected. It seems as if any change to block_speed only happens when I stop moving then move again.
I'm guessing it only receives the new value of block_speed after the current copy of block_speed is done being used.
How do I change block_speed with SHIFT while this variable is being used by the program?
def run(self):
pygame.init()
pygame.display.set_caption("Platformer v1")
block_speed = 3
sprite_list = pygame.sprite.Group()
wall_list = pygame.sprite.Group()
left_wall = Wall(0,0,10,resolution[1])
wall_list.add(left_wall)
sprite_list.add(left_wall)
top_wall = Wall(10,0,resolution[0]-10,10)
wall_list.add(top_wall)
sprite_list.add(top_wall)
test_wall = Wall(10,150,200,10)
wall_list.add(test_wall)
sprite_list.add(test_wall)
player = Player(50,50)
player.walls = wall_list
sprite_list.add(player)
while True:
self.screen.fill(black)
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if keys[pygame.K_LSHIFT]:
block_speed = 5
else:
block_speed = 3
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
player.change_x += block_speed
elif event.key == pygame.K_a:
player.change_x += -block_speed
elif event.key == pygame.K_w:
player.change_y += -block_speed
elif event.key == pygame.K_s:
player.change_y += block_speed
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d or event.key == pygame.K_a:
player.change_x = 0
elif event.key == pygame.K_w or event.key == pygame.K_s:
player.change_y = 0
sprite_list.update()
sprite_list.draw(self.screen)
pygame.display.update()
self.clock.tick(FPS)
Your issue is that when you add block speed to player.change_x/change_y, it performs that calculation at that time. Changing the variable afterwards won't make a difference.
A simple solution for your case is to simply make the change to block_speed happen before you use it. If you do this, block_speed has the value you want when it comes to changing the other variables, giving you the result you want.
Edit: I realise there is another issue - that is, you only change the movement speed if the key is newly pressed (the event is fired), so changing block speed still won't change the speed unless a direction key is pressed. The solution is to do your calculation every time, regardless.
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if keys[pygame.K_LSHIFT]:
block_speed = 5
else:
block_speed = 3
if keys[pygame.K_d]:
player.change_x += block_speed
if keys[pygame.K_a]:
player.change_x += -block_speed
if keys[pygame.K_w]:
player.change_y += -block_speed
if keys[pygame.K_s]:
player.change_y += block_speed
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d or event.key == pygame.K_a:
player.change_x = 0
elif event.key == pygame.K_w or event.key == pygame.K_s:
player.change_y = 0
An alternative would be to store the direction when a key is pressed, then multiply this up by the speed at the time you do the movement each frame:
keys = pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if keys[pygame.K_LSHIFT]:
player.block_speed = 5
else:
player.block_speed = 3
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
player.change_x += 1
elif event.key == pygame.K_a:
player.change_x -= 1
elif event.key == pygame.K_w:
player.change_y -= 1
elif event.key == pygame.K_s:
player.change_y += 1
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d or event.key == pygame.K_a:
player.change_x = 0
elif event.key == pygame.K_w or event.key == pygame.K_s:
player.change_y = 0
And then in your position code, do self.rect.x += self.change_x * self.block_speed instead. This is probably a preferable solution.
I've had the same issue and tried using the code from the suggested answer but found it did not work for me. My sprite still moved at the base speed until a key was lifted.
Looking at this thread, I tried moving the get_pressed() key detection outside of the event loop, which fixed things.
keys = pygame.key.get_pressed()
if keys[pygame.K_LSHIFT]:
player.block_speed = 5
else:
player.block_speed = 3
for event in pygame.event.get():
if event.type == pygame.QUIT:
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
player.change_x += 1
#etc.
elif event.type == pygame.KEYUP:
if event.key == pygame.K_d or event.key == pygame.K_a:
player.change_x = 0
#etc.
As in the above answer, in your position code have self.rect.x += self.change_x * self.block_speed.
This allowed me to get a speed boost effect when a certain key was held down and revert back to the base speed when it was not.
import pygame
running = True
while running:
for event in pygame.event.get():
#K_UP mean releasing the key
if event.type == pygame.K_UP:
if event.key == pygame.K_LSHIFT:
block_speed = 3
Here is some pygame code it works fine except to move the sprite i have to repeatedly tap the arrow keys, is there a way to make the sprite move by holding down the arrow keys? Below is my code:
while True: #main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYUP:
if event.key == K_RIGHT:
LionCubX+= 10
elif event.key == K_LEFT:
LionCubX-= 10
elif event.key == K_UP:
LionCubY-= 10
elif event.key == K_DOWN:
LionCubY+= 10
DISPLAYSURF.fill(GREEN)
DISPLAYSURF.blit(LionCubImg,(LionCubX,LionCubY))
pygame.display.update()
The problem that I can see here is that you check for events of type KEYUP. This means that your Code only gets executed when you release the key. So change
elif event.type == KEYUP:
to
elif event.type == KEYDOWN:
Another possibility would be that you didn't set key repeat:
pygame.key.set_repeat(1, 30)
Put this before your main game loop to activate key repeat. Also see the docs.
The problem is you're moving your sprite only if a key has been depressed and released KEYUP. You need to move the sprite in the key state KEYDOWN.
Change this:
elif event.type == KEYUP:
To:
elif event.type == KEYDOWN: