How to i make an sprite rotate smoothly - python

I neew help with making my sprites rotate smoothly.
Right now i have to press the botton multiple times to rotate the sprites.
When I rotate the sprites it also warps the sprites in a weird way.
if you go down to the main loop you can see how i tried to implement the rotation in my code right now.
I am new to programming so i would appreciate if anyone could ELI5.
import pygame as pg
import sys
x, y = 0, 0
class Rocket(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.angle_change = 0
self.angle = 90 + self.angle_change
self.image = pg.transform.rotate(self.image, self.angle)
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_w = False
self.pressed_a = False
self.pressed_s = False
self.pressed_d = False
self.speed = 3
self.gravity = False
def update(self):
if self.pressed_a:
self.rect.x -= self.speed
if self.pressed_d:
self.rect.x += self.speed
if self.pressed_w:
self.rect.y -= self.speed
if self.pressed_s:
self.angle_change += 3
if self.gravity:
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height
class Rocket1(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.rotate = 90
self.image = pg.transform.rotate(self.image, self.rotate)
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_up = False
self.pressed_left = False
self.pressed_down = False
self.pressed_right = False
self.speed = 3
self.gravity = False
def update(self):
if self.pressed_left:
self.rect.x -= self.speed
if self.pressed_right:
self.rect.x += self.speed
if self.pressed_up:
self.rect.y -= self.speed
if self.pressed_down:
self.rect.y += self.speed
if self.gravity:
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height
pg.init()
clock = pg.time.Clock()
width = 1920
height = 1080
screen = pg.display.set_mode((width, height))
background = pg.image.load("bg.jpg")
#rocket
player_rect = Rocket("rocket.png", x, y)
player_rect1 = Rocket1("rocketflames.png", x, y)
rocket_group = pg.sprite.Group()
rocket_group.add(player_rect,player_rect1)
while True:
rocket_rotate = 0
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_rect.pressed_w = True
player_rect.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_s:
rocket_rotate += 1
for rocket in rocket_group:
rocket.image = pg.transform.rotate(rocket.image, rocket_rotate)
if event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player_rect.pressed_d = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
player_rect.pressed_a = True
if event.type == pg.KEYUP:
if event.key == pg.K_w:
player_rect.pressed_w = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_s:
rocket_rotate += 0
for rocket in rocket_group:
rocket.image = pg.transform.rotate(rocket.image, rocket_rotate)
if event.type == pg.KEYUP:
if event.key == pg.K_d:
player_rect.pressed_d = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_a:
player_rect.pressed_a = False
player_rect.gravity = True
###
if event.type == pg.KEYDOWN:
if event.key == pg.K_UP:
player_rect1.pressed_up = True
player_rect1.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_DOWN:
player_rect1.pressed_down = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_RIGHT:
player_rect1.pressed_right = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_LEFT:
player_rect1.pressed_left = True
if event.type == pg.KEYUP:
if event.key == pg.K_UP:
player_rect1.pressed_up = False
player_rect1.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_DOWN:
player_rect1.pressed_down = False
player_rect1.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_RIGHT:
player_rect1.pressed_right = False
player_rect1.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_LEFT:
player_rect1.pressed_left = False
player_rect1.gravity = True
pg.display.flip()
screen.blit(background, (0, 0))
rocket_group.draw(screen)
rocket_group.update()
clock.tick(120)

You have to use the pygame.key.get_pressed() instead of the keybord events.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN event occurs once every time a key is pressed. KEYUP occurs once every time a key is released. Use the keyboard events for a single action or a step-by-step movement.
pygame.key.get_pressed() returns a list with the state of each key. If a key is held down, the state for the key is True, otherwise False. Use pygame.key.get_pressed() to evaluate the current state of a button and get continuous movement.
Additionally I recommend reading How do I rotate an image around its center using PyGame?.

Related

Cant move sprite on screen [duplicate]

This question already has answers here:
How can I make a sprite move when key is held down
(6 answers)
Closed 1 year ago.
The sprite is just stuck in the top left corner. It moves sligthly when pressing "wasd".
I am trying to make a simple clone of Mayhem/xPilot. A 2 player game where there are 2 rockets that can shoot eachother down.
I am fairly new to coding and python, I would be gratefull if you could ELI5.
Has anyone else had this problem?
import pygame as pg
import sys
x, y = 0, 0
class Rocket(pg.sprite.Sprite):
def __init__(self, picture_path, x, y):
super().__init__()
self.image = pg.image.load(picture_path)
self.image = pg.transform.scale(self.image, (120, 100))
self.rect = self.image.get_rect()
self.rect.x = 900
self.rect.y = 400
self.pressed_w = False
self.pressed_a = False
self.pressed_s = False
self.pressed_d = False
self.speed = 3
self.gravity = False
def update(self):
self.rect.x = 0
self.rect.y = 0
if self.pressed_a and self.rect.left > 0:
self.rect.x = self.speed
if self.pressed_d and self.rect.right < width:
self.rect.x = self.speed
if self.pressed_s and self.rect.bottom < height:
self.rect.y = self.speed
if self.pressed_w and self.rect.top > 0:
self.rect.y = -self.speed
if self.gravity and self.rect.bottom < height:
self.rect.y = self.speed
self.rect.x += x
self.rect.y += y
pg.init()
clock = pg.time.Clock()
width = 1920
height = 1080
screen = pg.display.set_mode((width, height))
background = pg.image.load("bg.jpg")
#rocket
player_rect = Rocket("rocket.png", x, y)
rocket_group = pg.sprite.Group()
rocket_group.add(player_rect)
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_w:
player_rect.pressed_w = True
player_rect.gravity = False
if event.type == pg.KEYDOWN:
if event.key == pg.K_s:
player_rect.pressed_s = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_d:
player_rect.pressed_d = True
if event.type == pg.KEYDOWN:
if event.key == pg.K_a:
player_rect.pressed_a = True
if event.type == pg.KEYUP:
if event.key == pg.K_w:
player_rect.pressed_w = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_s:
player_rect.pressed_s = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_d:
player_rect.pressed_d = False
player_rect.gravity = True
if event.type == pg.KEYUP:
if event.key == pg.K_a:
player_rect.pressed_a = False
player_rect.gravity = True
pg.display.flip()
screen.blit(background, (0, 0))
rocket_group.draw(screen)
rocket_group.update()
clock.tick(120)
The problem is in the update method. The method has to change the coordinates of the rect attribute. However, your method continuously sets self.rect.x = 0 and self.rect.y = 0.
Change update:
class Rocket(pg.sprite.Sprite):
# [...]
def update(self):
if self.pressed_a:
self.rect.x -= self.speed
if self.pressed_d
self.rect.x += self.speed
if self.pressed_w
self.rect.y -= self.speed
if self.pressed_s
self.rect.y += self.speed
if self.gravity
self.rect.y += self.speed
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > width: self.rect.right = width
if self.rect.top < 0: self.rect.top = 0
if self.rect.bottom > height: self.rect.bottom = height

How to move the Rocket in my first project on pygame Python

I'll much appreciate it if you help me to resolve the issue with moving Rocket in my project.
I've started to code my first game, based on material that I've learned in the "Python crash course" book.
I need to make Rocket in the game to move all over the window and around its axis.
Everything worked (moving left, right, top, bottom), then I decided to make my Rocket to move around its axis. I spend a lot of time to know how to do it and it already works (left Shift).
But now I faced another problem. My Rocket now doesn't move on the screen, only around its axis. I understand that my question may seem very stupid, and somewhere in my code is obviously a lack of simple logic. But I tried to fix it by myself for several hours and didn't get a result.
Here is my code:
import pygame
import sys
class Settings():
"""A class to store all settings for Rocket."""
def __init__(self):
"""Initialize the game screen settings."""
# Screen settings.
self.screen_width = 900
self.screen_height = 700
self.bg_color = (21, 36, 110)
class Rocket():
"""A class that describes rocket."""
def __init__(self, screen):
"""Initialize rocket and its starting position."""
self.screen = screen
#Load the rocket image and get its rect.
self.image = pygame.image.load('/media/philip/9074-45DF/Python/rocket/images/rocket.png')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#set starting position of a rocket.
self.rect.centerx = self.screen_rect.centerx
self.rect.centery = self.screen_rect.centery
#movement flag.
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.rotate_left = False
self.rocket_angle = 0
def update(self):
"""Update the rocket position based on the movement flag."""
if self.moving_right and self.rect.right < self.screen_rect.right:
self.rect.centerx += 2
if self.moving_left and self.rect.left > 0:
self.rect.centerx -= 2
if self.moving_up and self.rect.top > 0:
self.rect.centery -= 2
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.rect.centery += 2
def rotated_center(self, image, rocket_angle):
"""Rotating rocket around its axis."""
self.center = self.image.get_rect().center
self.rotated_image = pygame.transform.rotate(self.image, self.rocket_angle)
self.new_rect = self.rotated_image.get_rect(center = self.center)
return self.rotated_image, self.new_rect
def blit_rocket(self, rect, rocket_angle):
"""Draw the rocket at its current location."""
if self.rotate_left:
self.rocket_angle = (self.rocket_angle + 1) % 360
self.screen.blit(self.rotated_image, self.new_rect)
else:
self.rocket_angle = (self.rocket_angle + 0) % 360
self.screen.blit(self.rotated_image, self.new_rect)
def check_events(self):
"""Respond to a key events."""
# Responses to the keydown events.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.moving_right = True
if event.key == pygame.K_LEFT:
self.moving_left = True
if event.key == pygame.K_DOWN:
self.moving_down = True
if event.key == pygame.K_UP:
self.moving_up = True
if event.key == pygame.K_LSHIFT:
self.rotate_left = True
# Responses to the keyup events.
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
self.moving_right = False
if event.key == pygame.K_LEFT:
self.moving_left = False
if event.key == pygame.K_DOWN:
self.moving_down = False
if event.key == pygame.K_UP:
self.moving_up = False
if event.key == pygame.K_LSHIFT:
self.rotate_left = False
pygame.init()
rocket_settings = Settings()
icon = pygame.image.load('/media/philip/9074-45DF/Python/rocket/images/rocket_icon.png')
pygame.display.set_icon(icon)
screen = pygame.display.set_mode((rocket_settings.screen_width, rocket_settings.screen_height))
pygame.display.set_caption("Rocket")
rocket = Rocket(screen)
"""The main game loop."""
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.fill((rocket_settings.bg_color))
rocket.update()
rocket.check_events()
rocket.rotated_center(rocket.image, rocket.rocket_angle)
rocket.blit_rocket(rocket.rect,rocket.rocket_angle)
pygame.display.flip()
event has to be an argument of the method Rocket.check_events:
class Rocket():
# [...]
def check_events(self, event): # event argument
"""Respond to a key events."""
# Responses to the keydown events.
# [...]
You have to call rocket.check_events() in the event loop and to pass the event to the method:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
rocket.check_events(event) # <--- ADD
screen.fill((rocket_settings.bg_color))
rocket.update()
# rocket.check_events() <--- DELETE
rocket.rotated_center(rocket.image, rocket.rocket_angle)
rocket.blit_rocket(rocket.rect,rocket.rocket_angle)
pygame.display.flip()
pygame.Surface.get_rect.get_rect() returns a rectangle with the size of the Surface object, but it returns a rectangle that always starts at (0, 0).
You must get the position of the the object from self.rect.center rather than self.image.get_rect().center:
class Rocket():
# [...]
def rotated_center(self, image, rocket_angle):
"""Rotating rocket around its axis."""
self.rotated_image = pygame.transform.rotate(self.image, self.rocket_angle)
self.new_rect = self.rotated_image.get_rect(center = self.rect.center)
return self.rotated_image, self.new_rect
Complete example:
import pygame
import sys
class Settings():
"""A class to store all settings for Rocket."""
def __init__(self):
"""Initialize the game screen settings."""
# Screen settings.
self.screen_width = 900
self.screen_height = 700
self.bg_color = (21, 36, 110)
class Rocket():
"""A class that describes rocket."""
def __init__(self, screen):
"""Initialize rocket and its starting position."""
self.screen = screen
#Load the rocket image and get its rect.
self.image = pygame.image.load('/media/philip/9074-45DF/Python/rocket/images/rocket.png')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
#set starting position of a rocket.
self.rect.centerx = self.screen_rect.centerx
self.rect.centery = self.screen_rect.centery
#movement flag.
self.moving_right = False
self.moving_left = False
self.moving_up = False
self.moving_down = False
self.rotate_left = False
self.rocket_angle = 0
def update(self):
"""Update the rocket position based on the movement flag."""
if self.moving_right and self.rect.right < self.screen_rect.right:
self.rect.centerx += 2
if self.moving_left and self.rect.left > 0:
self.rect.centerx -= 2
if self.moving_up and self.rect.top > 0:
self.rect.centery -= 2
if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
self.rect.centery += 2
def rotated_center(self, image, rocket_angle):
"""Rotating rocket around its axis."""
self.rotated_image = pygame.transform.rotate(self.image, self.rocket_angle)
self.new_rect = self.rotated_image.get_rect(center = self.rect.center)
return self.rotated_image, self.new_rect
def blit_rocket(self, rect, rocket_angle):
"""Draw the rocket at its current location."""
if self.rotate_left:
self.rocket_angle = (self.rocket_angle + 1) % 360
self.screen.blit(self.rotated_image, self.new_rect)
else:
self.rocket_angle = (self.rocket_angle + 0) % 360
self.screen.blit(self.rotated_image, self.new_rect)
def check_events(self, event):
"""Respond to a key events."""
# Responses to the keydown events.
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
self.moving_right = True
if event.key == pygame.K_LEFT:
self.moving_left = True
if event.key == pygame.K_DOWN:
self.moving_down = True
if event.key == pygame.K_UP:
self.moving_up = True
if event.key == pygame.K_LSHIFT:
self.rotate_left = True
# Responses to the keyup events.
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
self.moving_right = False
if event.key == pygame.K_LEFT:
self.moving_left = False
if event.key == pygame.K_DOWN:
self.moving_down = False
if event.key == pygame.K_UP:
self.moving_up = False
if event.key == pygame.K_LSHIFT:
self.rotate_left = False
pygame.init()
rocket_settings = Settings()
icon = pygame.image.load('/media/philip/9074-45DF/Python/rocket/images/rocket_icon.png')
pygame.display.set_icon(icon)
screen = pygame.display.set_mode((rocket_settings.screen_width, rocket_settings.screen_height))
pygame.display.set_caption("Rocket")
rocket = Rocket(screen)
"""The main game loop."""
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
rocket.check_events(event)
screen.fill((rocket_settings.bg_color))
rocket.update()
rocket.rotated_center(rocket.image, rocket.rocket_angle)
rocket.blit_rocket(rocket.rect,rocket.rocket_angle)
pygame.display.flip()

Make Character Keep Moving While Key Held Down

I'm trying to make a quick animation where if a key is held down the character will keep moving, however my code doesn't seem to be doing that. I press the key and moves once but doesn't move any further. Any help to fix this. Any other suggestions are appreciated and keep in mind this isn't near final product form.
import pygame
import os
import sys
from pygame.locals import *
pygame.init()
WIN = pygame.display.set_mode(display)
pygame.display.set_caption('The Game')
width = 500
height = 500
display = (width, height)
WHITE = (255, 255, 255)
left = [
pygame.image.load(os.path.join('assets', 'main', 'left_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'left_walk2.png'))
]
right = [
pygame.image.load(os.path.join('assets', 'main', 'right_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'right_walk2.png'))
]
up = [
pygame.image.load(os.path.join('assets', 'main', 'up_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'up_walk2.png'))
]
down = [
pygame.image.load(os.path.join('assets', 'main', 'down_walk1.png')),
pygame.image.load(os.path.join('assets', 'main', 'down_walk2.png'))
]
standing_left = (os.path.join('assets', 'main', 'down_walk2.png'))
standing_right = (os.path.join('assets', 'main', 'down_walk2.png'))
standing_up = (os.path.join('assets', 'main', 'down_walk2.png'))
standing_down = (os.path.join('assets', 'main', 'down_walk2.png'))
class Player:
def __init__(self, x, y):
self.x = x
self.y = y
self.health = 100
self.inv = []
self.left = False
self.right = False
self.up = False
self.down = False
self.walking_count = 0
self.facing = 'down'
def draw_player(self, win):
if self.walking_count == 3:
self.walking_count = 1
if self.left:
WIN.blit(left[self.walking_count // 2], (self.x, self.y))
elif self.right:
WIN.blit(right[self.walking_count // 2], (self.x, self.y))
player = Player(100, 100)
FPS = 40
fpsClock = pygame.time.Clock()
while True:
fpsClock.tick(FPS)
WIN.fill(WHITE)
player.draw_player(WIN)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_UP and player.y <= 0:
player.up = True
elif event.key == K_DOWN:
player.down = True
elif event.key == K_LEFT:
player.left = True
elif event.key == K_RIGHT:
player.right = True
elif event.type == KEYUP:
if event.key == K_UP:
player.up = False
if event.key == K_DOWN:
player.down = False
if event.key == K_LEFT:
player.left = False
if event.key == K_RIGHT:
player.right = False
if player.left:
player.x -= 5
player.walking_count += 1
if player.right:
player.x += 5
player.walking_count += 1
if player.up:
player.y -= 5
player.walking_count += 1
if player.down:
player.y += 5
player.walking_count += 1
pygame.display.update()
It is a matter of Indentation. You've to apply the movement in the application loop rather than the event loop:
while True:
fpsClock.tick(FPS)
WIN.fill(WHITE)
player.draw_player(WIN)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_UP and player.y <= 0:
player.up = True
elif event.key == K_DOWN:
player.down = True
elif event.key == K_LEFT:
player.left = True
elif event.key == K_RIGHT:
player.right = True
elif event.type == KEYUP:
if event.key == K_UP:
player.up = False
if event.key == K_DOWN:
player.down = False
if event.key == K_LEFT:
player.left = False
if event.key == K_RIGHT:
player.right = False
#<--| INDENTATION
if player.left:
player.x -= 5
if player.right:
player.x += 5
if player.up:
player.y -= 5
if player.down:
player.y += 5
pygame.display.update()
Alternatively you can use pygame.key.get_pressed() rather than the KEYDOWN and KEYUP event:
while True:
fpsClock.tick(FPS)
WIN.fill(WHITE)
player.draw_player(WIN)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
keys = pygame.key.get_pressed()
player.left, player.right, player.up, player.down = False, False, False, False
if keys[K_LEFT]:
player.x -= 5
player.left = True
if keys[K_RIGHT]:
player.x += 5
player.right = True
if keys[K_UP]:
player.y -= 5
player.up = True
if keys[K_DOWN]:
player.y += 5
player.down = True
pygame.display.update()
To control the animation speed, add an attribute self.animation_frames = 10. This attributes controls how many frames each image of the animation is shown. Compute the image index dependent on the attribute.
walking_count has to be incremented in Player.draw_player rather than the application loop.
To ensure that the correct "standing" image is displayed, you have to add an attribute self.standing. Set the attribute dependent on the current direction in draw_player. If the player is not moving, the display the current standing image:
class Player:
def __init__(self, x, y):
# [...]
self.animation_frames = 10
self.standing = standing_left
def draw_player(self, win):
# get image list
if self.left:
image_list = left
self.standing = standing_left
else self.right:
image_list = right
self.standing = standing_right
else:
image_list = [self.standing]
# increment walk count and get image list
image_index = self.walking_count // self.animation_frames
if image_index >= len(image_list):
image_index = 0
self.walking_count = 0
self.walking_count += 1
WIN.blit(image_list[image_index], (self.x, self.y))

Problem with my instance's functions not working (Python3, Pygame), check my code?

Been trying to turn my main character into a class that I can call in my game. This is because I know it will get a lot more complex later in the development due to plans to implement enemies and spawn-able power-ups.
For some reason, my sprite will be drawn but the methods to get make it detect my key and then move (getkey, animandmove) don't seem to work as pressing any of the inputs does not move it. Please help?
import pygame
from pygame.locals import *
import sys
import pyganim # used for animations
pygame.init()
pygame.mixer.init()
WINDOWWIDTH = 1600
WINDOWHEIGHT = 900
# x = 100
# y = 100
# vel = 10
# width = 64
# height = 64
# moveleft = moveright = moveup = movedown = False
# direction = 'left'
background = pygame.image.load('sprites/background1.png')
leftidle = pygame.image.load("sprites/left.png")
rightidle = pygame.image.load("sprites/right.png")
upidle = pygame.image.load("sprites/up.png")
downidle = pygame.image.load("sprites/down.png")
charanim = {"walkleft": pyganim.PygAnimation(
[("sprites/left2.png", 100), ("sprites/left.png", 100), ("sprites/left3.png", 100), ("sprites/left.png", 10)]),
"walkright": pyganim.PygAnimation(
[("sprites/right2.png", 100), ("sprites/right.png", 100), ("sprites/right3.png", 100),
("sprites/right.png", 10)]), "walkup": pyganim.PygAnimation(
[("sprites/up2.png", 100), ("sprites/up.png", 100), ("sprites/up3.png", 100), ("sprites/up.png", 10)]),
"walkdown": pyganim.PygAnimation(
[("sprites/down2.png", 100), ("sprites/down.png", 100), ("sprites/down3.png", 100), ("sprites/down.png", 10)])}
moveConductor = pyganim.PygConductor(charanim)
mainmenuanim = {"splashscreen": pyganim.PygAnimation([("sprites/splash1.png", 500), ("sprites/splash2.png", 500)])}
mainmenuConductor = pyganim.PygConductor(mainmenuanim)
muzzleflashanim = {"fire": pyganim.PygAnimation(
[("sprites/muzzleflash.png", 100), ("sprites/muzzleflash2.png", 100), ("sprites/muzzleflash3.png", 100),
("sprites/muzzleflash4.png", 100)])}
mainwin = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption("2084 Ver 0.1.1.1")
def mainmenu():
global running
menulive = True
pygame.mixer.music.load('track0.ogg')
pygame.mixer.music.play(-1)
while menulive:
mainmenuConductor.play()
mainmenuanim["splashscreen"].blit(mainwin, (0, 0))
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_RETURN:
pygame.mixer.music.stop()
mainloop()
if event.type == pygame.QUIT:
running = False
pygame.quit()
pygame.display.update()
def mainloop():
global running
running = True
char1 = Character()
pygame.mixer.music.load("track1.ogg")
pygame.mixer.music.play(-1)
char1.__init__()
while running:
mainwin.blit(background, (0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
char1.getkey()
char1.animandmove()
pygame.display.update()
class Character:
def __init__(self):
self.x = 100
self.y = 100
self.vel = 10
self.width = 64
self.height = 64
self.moveleft = False
self.moveright = False
self.moveup = False
self.movedown = False
self.direction = 'left'
def animandmove(self):
if self.moveleft or self.moveright or self.moveup or self.movedown:
moveConductor.play()
# draws animations for each of the directions
if self.direction == "left":
charanim["walkleft"].blit(mainwin, (self.x, self.y))
elif self.direction == "right":
charanim["walkright"].blit(mainwin, (self.x, self.y))
elif self.direction == "up":
charanim["walkup"].blit(mainwin, (self.x, self.y))
elif self.direction == "down":
charanim["walkdown"].blit(mainwin, (self.x, self.y))
# moving the physicial character
if self.moveleft and self.x > 0:
self.x -= self.vel
if self.moveright and self.x < (WINDOWWIDTH - 64):
self.x += self.vel
if self.moveup and self.y > 0:
self.y -= self.vel
if self.movedown and self.y < (WINDOWHEIGHT - 64):
self.y += self.vel
else:
moveConductor.stop()
if self.direction == "left":
mainwin.blit(pygame.image.load("sprites/left.png"), (self.x, self.y))
elif self.direction == "right":
mainwin.blit(pygame.image.load("sprites/right.png"), (self.x, self.y))
elif self.direction == "up":
mainwin.blit(pygame.image.load("sprites/up.png"), (self.x, self.y))
elif self.direction == "down":
mainwin.blit(pygame.image.load("sprites/down.png"), (self.x, self.y))
def getkey(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_LEFT or event.key == K_a:
self.moveleft = True
self.moveright = False
if not self.moveup and not self.movedown:
self.direction = "left"
elif event.key == K_RIGHT or event.key == K_d:
self.moveleft = False
self.moveright = True
if not self.moveup and not self.movedown:
self.direction = "right"
elif event.key == K_UP or event.key == K_w:
self.moveup = True
self.movedown = False
if not self.moveleft and not self.moveright:
self.direction = "up"
elif event.key == K_DOWN or event.key == K_s:
self.moveup = False
self.movedown = True
if not self.moveleft and not self.moveright:
self.direction = "down"
elif event.type == KEYUP:
if event.key == K_LEFT or event.key == K_a:
self.moveleft = False
if self.moveup:
self.direction = "up"
if self.movedown:
self.direction = "down"
elif event.key == K_RIGHT or event.key == K_d:
self.moveright = False
if self.moveup:
self.direction = "up"
if self.movedown:
self.direction = "down"
elif event.key == K_UP or event.key == K_w:
self.moveup = False
if self.moveleft:
self.direction = "left"
if self.moveright:
self.direction = "right"
elif event.key == K_DOWN or event.key == K_s:
self.movedown = False
if self.moveleft:
self.direction = "left"
if self.moveright:
self.direction = "right"
pygame.display.update()
mainmenu()
pygame.quit()
The main problem is that you have two event loops.
In your main loop, you call pygame.event.get() to get all events which will clear the event queue.
Later, you call pygame.event.get() again in char1.getkey(). At this point, the event queue is already empty (this may happen vice versa, of course).
The easy way to fix it is to just pass every event from the main loop to char1:
while running:
mainwin.blit(background, (0, 0))
for event in pygame.event.get():
char1.getkey(event)
if event.type == pygame.QUIT:
pygame.quit()
char1.animandmove()
pygame.display.update()
and handle them in getkey:
def getkey(self, event):
if event.type == ...
...
There are several other issues with your code but that's out of scope of this question/answer.

Pygame player movement stops when too many keys are pressed at the same time

When I try to move my character and press any other key at the same time, the movement suddenly stops. For example, the space key in my code is used to shoot a tiny orb out of the spaceship. Every time I press space and I am moving left and right quickly, the orb will shoot out but the player movement will be frozen for a second or two.
I have tried to switch to different ways of handling the way keys are input, but all of them seem to lead to this same problem. pygame.key.get_pressed() also has this problem when in my code.
I am not quite sure if this is a problem with my laptop keyboard or something in the code, so the code for the entire file is below.
import pygame, sys, decimal
# Screen Size
SCREEN_X = 400
SCREEN_Y = 400
# Loading Images
backgroundImg = pygame.image.load('StarBackground.png')
menuBar = pygame.image.load('Menu_Bar.png')
shipImg = pygame.image.load('PowerShip.png')
orb = pygame.image.load('Orb00.png')
class Ship(pygame.sprite.Sprite):
# Movement rate of change
change_x = 0
# Methods
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = shipImg.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = SCREEN_X / 2 - 8
self.rect.y = SCREEN_Y - 40
def move(self, speed):
self.change_x = speed
def stop(self):
self.change_x = 0
def update(self, screen):
self.rect.x += self.change_x
if self.rect.x < 0:
self.rect.x = 0
elif self.rect.right > SCREEN_X:
self.rect.x -= 1
screen.blit(self.image, self.rect)
class MenuBar(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = menuBar.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = 10
self.rect.y = 0
def update(self, screen):
screen.blit(self.image,self.rect)
class Bullet1(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = orb.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.alive = True
def update(self):
if self.alive == True:
self.rect.y -= 1
if self.alive == False:
self.rect.y = -10000
class HealthBar(pygame.sprite.Sprite):
pass
class EnergyBar(pygame.sprite.Sprite):
pass
class PointsBar(pygame.sprite.Sprite):
pass
class Background(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = backgroundImg.convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = 0
self.rect.y = 0
def update(self, screen):
if self.rect.top > 0:
self.rect.y = SCREEN_Y * -1
self.rect.y += 1
screen.blit(self.image, self.rect)
def main():
pygame.init()
size = [SCREEN_X, SCREEN_Y]
screen = pygame.display.set_mode(size, pygame.DOUBLEBUF) # Set the height and width of the screen
pygame.display.set_caption("Space Adventure") # Setting the game name in the title bar
background = Background() # Creating the game objects
menubar = MenuBar()
ship = Ship()
finished = False # Close button exit code
bullet1Enabled = True
bullet1Count = 1
spacePressed = False
clock = pygame.time.Clock() # Manages the frames per second
lastkey = None # Variable that stores the last key pressed
bulletlist = []
# Game loop
while not finished:
for event in pygame.event.get():
print(lastkey)
if event.type == pygame.QUIT:
finished = True
pygame.event.set_blocked(pygame.MOUSEMOTION)
if event.type == pygame.KEYDOWN:
if lastkey != pygame.K_SPACE:
lastkey = event.key
if event.key == pygame.K_SPACE:
spacePressed = True
if bullet1Enabled == True:
bullet1 = Bullet1(ship.rect.x, ship.rect.y)
bulletlist.append(bullet1)
bullet1Count = 1
else:
spacePressed = False
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT and lastkey != pygame.K_LEFT:
lastkey = None
ship.move(0)
if event.key == pygame.K_LEFT and lastkey != pygame.K_RIGHT:
lastkey = None
ship.move(0)
if event.key == pygame.K_RIGHT or lastkey == pygame.K_LEFT:
spacePressed = False
if event.key == pygame.K_LEFT or lastkey == pygame.K_RIGHT:
spacePressed = False
#Bullet Delay
if spacePressed == True:
bullet1Count = True
if spacePressed == False:
bullet1Count = False
if lastkey == pygame.K_RIGHT:
ship.move(1)
if lastkey == pygame.K_LEFT:
ship.move(-1)
clock.tick(240) # Frames per second
background.update(screen) # Background update
# Menu Bar update
ship.update(screen) # Ship update
for b in bulletlist:
if b.rect.bottom <= 0:
b.alive = False
b.update()
screen.blit(b.image, b.rect)
menubar.update(screen)
pygame.display.flip() # Updates the display for everything
pygame.quit() # Clean shutdown on IDLE
if __name__ == "__main__":
main()
The problem occurs because you don't reset lastkey to None after you release the space bar, so you have to press left or right twice.
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
lastkey = None
I don't see why you need the lastkey variable at all. I'd remove these lines from the main loop,
if lastkey == pygame.K_RIGHT:
ship.move(1)
if lastkey == pygame.K_LEFT:
ship.move(-1)
insert them in the event loop and change lastkey to event.key:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.move(1)
if event.key == pygame.K_LEFT:
ship.move(-1)
Now you should be able to remove the lastkey completely.

Categories