Pygame running super slow (~2 fps) - python

My pygame game runs super slowly, about 2 fps. You are supposed to be able to move around with WASD and always be centered in the screen. I know it has something to do with my tilemap and the way I do my math, but I can't pin it down. Also, if there is a better way to keep the player in the center while moving the map behind it, I would love to know how to do that.
import pygame, sys, numpy
#create fps clock
clock = pygame.time.Clock()
#
MAPHEIGHT = 80
MAPWIDTH = 80
TILESIZE = 40
TILESONSCREENW = 13
TILESONSCREENH = 13
#set screen size
SCREENH = TILESONSCREENH*TILESIZE
SCREENW = TILESONSCREENW*TILESIZE
#create character vars
circleRad = 40
circleSpeed = 4
#create circle pos vars
circleX = 250
circleY = 250
#create keyboard button vars
rightP = False
leftP = False
upP = False
downP = False
#
playerOnTileS = pygame.Surface((MAPWIDTH*TILESIZE, MAPHEIGHT*TILESIZE))
#constants for the tilemap
GRASS = pygame.image.load("grass.png")
#tilemap
tilemap = [[GRASS for i in range(MAPHEIGHT)] for j in range(MAPWIDTH)]
#create window
DISPLAYSURF = pygame.display.set_mode((SCREENW, SCREENH))
#set window name
pygame.display.set_caption("Snowball Fight!")
#---------------------------------------------------
class Player:
def __init__(self, playX, playY, size):
self.playerX = playX
self.playerY = playY
self.size = size
self.playerSurface = pygame.Surface((size, size))
pygame.draw.rect(self.playerSurface, (19,135,67), (0,0,size, size))
#------------------------------------------------
def update(self):
playerOnTileS.blit(self.playerSurface, (self.playerX, self.playerY))
DISPLAYSURF.blit(playerOnTileS, (SCREENW/2-self.playerX-self.size ,SCREENH/2-self.playerY-self.size))
#game loop
myPlayer = Player(0,0,circleRad)
while True:
DISPLAYSURF.fill((0,0,0))
for event in pygame.event.get():
#if the user closed the window
if event.type == pygame.QUIT:
#close pygame
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
leftP = True
if event.key == pygame.K_d:
rightP = True
if event.key == pygame.K_w:
upP = True
if event.key == pygame.K_s:
downP = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_a:
leftP = False
if event.key == pygame.K_d:
rightP = False
if event.key == pygame.K_w:
upP = False
if event.key == pygame.K_s:
downP = False
if leftP:
myPlayer.move(-circleSpeed,0,True)
if rightP:
myPlayer.move(circleSpeed,0,True)
if downP:
myPlayer.move(0,circleSpeed,True)
if upP:
myPlayer.move(0,-circleSpeed,True)
for row in range(len(tilemap)):
for column in range(len(tilemap[row])):
playerOnTileS.blit(tilemap[row][column],(column*TILESIZE,row*TILESIZE))
myPlayer.update()
pygame.display.update()
clock.tick(30)

Images/pygame.Surfaces should usually be converted with the pygame.Surface.convert or convert_alpha methods. The performance of unconverted surfaces is abysmal. When I convert the grass image, I get nearly 30 FPS.
The next problem is the nested for loop. Python's function call overhead is rather big, so it would be a good idea to blit all the tiles onto one large background surface before the main loop starts and then blit this background surface onto the DISPLAYSURF once per frame to clear it. With that change I get pygame's apparent maximum FPS, that means clock.get_fps() jumps between 2000 and 1666.666 FPS.
# Ahead of the while loop.
playerOnTileS = pygame.Surface((MAPWIDTH*TILESIZE, MAPHEIGHT*TILESIZE))
for row in range(len(tilemap)):
for column in range(len(tilemap[row])):
playerOnTileS.blit(tilemap[row][column],(column*TILESIZE,row*TILESIZE))
You have to change the update method (by the way, better call it draw) and blit the player surface onto the DISPLAYSURF instead.

Related

Why does my sprite reset to the top left of the screen when I try to rotate it with pygame.transform.rotate? [duplicate]

This question already has answers here:
How do I rotate an image around its center using Pygame?
(6 answers)
Closed 1 year ago.
I'm trying to rotate a sprite 90 degrees whenever the player presses the A and D keys, and I've got that working, but the sprite is always sent to the top left corner of the screen whenever this happens. Can someone shed some light on this? As well as that, I've tried to get a shooting system working with shooting asteroids, by creating an asteroid and appending it to a list, but it seems to become a tuple instead of a pygame rectangle when I try to change the y of it, can someone help with that as well?
import pygame, sys, random
from pygame.locals import *
#Imports pygame, system and random as modules to use later in the code.
#Also imports extra stuff from pygame that contains useful variables.
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
#Initialises pygame, sets up the clock to stop the program running too fast
#And also makes the font (must happen after pygame initialises)
WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite
def terminate():
pygame.quit()
sys.exit()
def pendingKey():
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
return
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOUR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
#Defining functions, to quit pygame and the system.
#And to wait for the escape key to be pressed to start the terminate function.
#And to wait for the quit event (such as at the end of the game).
#And a function to create text on the screen, such as for the title.
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
#Creates the games window, sets the name of the window, and makes the mouse invisible
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
pendingKey()
#Sets the colour of the background and draws the title and some basic instructions
#And updates the display and activates the terminate function
while True:
LEFT = RIGHT = UP = DOWN = SHOOT = LEFTROTATE = RIGHTROTATE = False
#Sets the players start position to half through the screen, and 50 pixels down
#And sets the movement variables to false
while True:
for event in pygame.event.get():
if event.type == QUIT:
terminate()
#Checks for events, first event being the game quitting
if event.type == KEYDOWN:
if event.key == K_LEFT:
RIGHT = False
LEFT = True
if event.key == K_RIGHT:
LEFT = False
RIGHT = True
if event.key == K_UP:
DOWN = False
UP = True
if event.key == K_DOWN:
UP = False
DOWN = True
if event.key == K_SPACE:
SHOOT = True
if event.key == K_a:
RIGHTROTATE = False
LEFTROTATE = True
if event.key == K_d:
LEFTROTATE = False
RIGHTROTATE = True
#Checks for keys being pressed, corresponding to movement.
if event.key == K_ESCAPE:
terminate()
#Checks for escape being pressed, which quits the game.
if event.type == KEYUP:
if event.key == K_ESCAPE:
terminate()
if event.key == K_LEFT:
LEFT = False
if event.key == K_RIGHT:
RIGHT = False
if event.key == K_UP:
UP = False
if event.key == K_DOWN:
DOWN = False
if event.key == K_SPACE:
SHOOT = False
if event.key == K_a:
RIGHTROTATE = False
LEFTROTATE = False
if event.key == K_d:
LEFTROTATE = False
RIGHTROTATE = False
#Checks whether keys have been let go of.
if LEFT and PLAYERRECT.left > 0:
PLAYERRECT.move_ip(-1 * PLAYERSPEED, 0)
if RIGHT and PLAYERRECT.right < WINDOWWIDTH:
PLAYERRECT.move_ip(PLAYERSPEED, 0)
if UP and PLAYERRECT.top > 0:
PLAYERRECT.move_ip(0, -1 * PLAYERSPEED)
if DOWN and PLAYERRECT.bottom < WINDOWHEIGHT:
PLAYERRECT.move_ip(0, PLAYERSPEED)
if SHOOT:
ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
if LEFTROTATE:
PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, 90)
PLAYERRECT = PLAYERIMAGE.get_rect()
if RIGHTROTATE:
PLAYERIMAGE = pygame.transform.rotate(PLAYERIMAGE, -90)
PLAYERRECT = PLAYERIMAGE.get_rect()
for asteroid in ASTEROIDS:
asteroid.y -= 4
for asteroid in ASTEROIDS:
WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
#Moves the player a certain number of pixels in a direction and shoots asteroids
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
WINDOWSURFACE.blit(PLAYERIMAGE, PLAYERRECT)
pygame.display.update()
mainClock.tick(FPS)
#Fills the background, draws the players image on the rectangle
#And updates the screen and selects how many frames per second the game should tick by
Thanks in advance
Note that you should only call pygame.event.get() once in your application.
When you rotate, you set your player rect as such:
PLAYERRECT = PLAYERIMAGE.get_rect()
You have never specified the value of PLAYERIMAGE.get_rect() and it is (0, 0) by default, so if the player is transported to the top left of the screen. To fix that, simply remove it, it serves no purpose.
Also, your movement code can be simplified.
keys = pygame.key.get_pressed()
PLAYERRECT.move_ip
(
(keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED,
(keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED
)
Thats it.
Code to handle rotation can be simplified as well. Make a function that gets the players rotation angle:
def getPlayerRotation(keys):
if keys[K_a]: return 90
elif keys[K_d]: return -90
return 0
Then use that to rotate your image and draw it.
#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
WINDOWSURFACE.blit(rotated_image, new_rect)
Your asteroid isn't drawing because you are trying to draw it before you clear the screen, which draws over the asteroids.
Also you cannot do
ASTEROIDS.append(ASTEROIDIMAGE.get_rect(center=PLAYERRECT.midtop))
because there is only one asteroid.rect object, so what you are appending is a reference to the same object over and over. You need to create a new rect if your want to use a rect, but I got around the problem by using a list.
ASTEROIDS.append(list(PLAYERRECT.center))
and then later:
for asteroid in ASTEROIDS:
asteroid[1] -= 4
Lastly I changed pending key function:
def pendingKey(events):
for event in events:
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
It takes events as argument to avoid calling pygame.event.get() in the function. I also removed the return statement at the end of it since it was causing the function to exit before it got to to through all the events.
Here is the new code:
import pygame, sys, random
from pygame.locals import *
WINDOWWIDTH = 1000
WINDOWHEIGHT = 1000
pygame.init()
mainClock = pygame.time.Clock()
FONT = pygame.font.SysFont(None, 48)
BACKGROUNDCOLOUR = (255, 255, 255)
TEXTCOLOUR = (0, 0, 0)
FPS = 60
PLAYERSPEED = 5
PLAYERIMAGE = pygame.image.load("images/P1.png")
PLAYERRECT = PLAYERIMAGE.get_rect()
ASTEROIDIMAGE = pygame.image.load("images/asteroid.png")
ASTEROIDRECT = ASTEROIDIMAGE.get_rect()
ASTEROIDMINSIZE = 3
ASTEROIDMAXSIZE = 5
ASTEROIDSPEED = 5
ASTEROIDS = []
#Defining Variables and setting up player sprite
def terminate():
pygame.quit()
sys.exit()
def pendingKey(events):
for event in events:
if event.type == QUIT:
terminate()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
terminate()
def drawText(text, font, surface, x, y):
textobj = font.render(text, 1, TEXTCOLOUR)
textrect = textobj.get_rect()
textrect.topleft = (x, y)
surface.blit(textobj, textrect)
WINDOWSURFACE = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
pygame.display.set_caption('Space Penguin Remastered')
pygame.mouse.set_visible(False)
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
drawText('Space Penguin Remastered', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
drawText('Press a key to start!', FONT, WINDOWSURFACE, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
pygame.display.update()
def getPlayerRotation(keys):
if keys[K_a]: return 90
elif keys[K_d]: return -90
return 0
while True:
events = pygame.event.get()
pendingKey(events)
keys = pygame.key.get_pressed()
PLAYERRECT.move_ip((keys[K_RIGHT] - keys[K_LEFT]) * PLAYERSPEED, (keys[K_DOWN] - keys[K_UP]) * PLAYERSPEED)
#https://stackoverflow.com/questions/4183208/how-do-i-rotate-an-image-around-its-center-using-pygame
rotated_image = pygame.transform.rotate(PLAYERIMAGE, getPlayerRotation(keys))
new_rect = rotated_image.get_rect(center = PLAYERIMAGE.get_rect(topleft = PLAYERRECT.topleft).center)
for event in events:
if event.type == KEYDOWN and event.key == K_SPACE:
ASTEROIDS.append(list(PLAYERRECT.center))
for asteroid in ASTEROIDS:
asteroid[1] -= 4
WINDOWSURFACE.fill(BACKGROUNDCOLOUR)
WINDOWSURFACE.blit(rotated_image, new_rect)
for asteroid in ASTEROIDS:
WINDOWSURFACE.blit(ASTEROIDIMAGE, asteroid)
pygame.display.update()
mainClock.tick(FPS)

Python 2D Sprite Animation

I'm trying to animate a sprite using a loop such that each time the loop runs through the position number for an image in an array increases by one. I keep getting "UnboundLocalError: local variable 'Antic' referenced before assignment". There is
Antic = 0
Antic = int(Antic)
# Global constants
StAnmtn = ["Images/PlayerVampireStanding1.png", "
Images/PlayerVampireStanding2.png",
"Images/PlayerVampireStanding3.png","Images/PlayerVampireStanding4.png",
"Images/PlayerVampireStanding5.png", "Images/PlayerVampireStanding6.png",
"Images/PlayerVampireStanding7.png", "Images/PlayerVampireStanding8.png"]
`
at the start and
def main():
""" Main Program """
pygame.init()
clock = pygame.time.Clock() # creates clock to limit frames per
second
FPS = 60 # sets max speed of min loop
SCREENSIZE = SCREENWIDTH, SCREENHEIGHT = 1300, 700 # sets size of
screen/window
screen = pygame.display.set_mode(SCREENSIZE) # creates window and game
screen
pygame.display.set_caption("Count Acheron")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append( Level_01(player) )
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
if Antic > 6:
Antic = 0
else:
Antic += 1
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
if __name__ == "__main__":
main()
as the loop. What it doesn't seem to like is the snippet of code
if Antic > 6:
Antic = 0
else:
Antic += 1
How do I fix this?
Personally I've never used pygame's sprite module.
import pygame
class character:
def __init__(self, x, y):
self.x = x
self.y = y
self.sprites = [pygame.image.load("img1.png"), pygame.image.load("img2.png")]
self.frame = 0
def draw(self, surface):
surface.blit(self.sprites[self.frame], (self.x, self.y))
self.frame += 1
if self.frame > len(self.sprites) - 1: self.frame = 0
pygame.init()
DS = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
c = character(640, 360)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
c.draw(DS)
pygame.display.update()
clock.tick(30)
DS.fill((0, 0, 0))
Needed to globalise the function ("global Antic" in the main loop)

Continuous movement of a box in pygame

I have written the following code that creates a simple game where when you click an arrow on the keyboard a box moves a unit over in the game.
I am trying to make it so that if i push any of the arrow buttons the box will continue to move in that direction until another arrow is pushed. So if i push the right arrow once instead of scooting +50 pixels it will move continuously across the screen untill a different arrow is clicked and then it will go that way
import pygame #importing the pygame library
# some initializations
pygame.init() # this line initializes pygame
window = pygame.display.set_mode( (800,600) ) # Create a window with width=800 and height=600
pygame.display.set_caption( 'Rectangle move' ) # Change the window's name we create to "Rectangle move"
clock = pygame.time.Clock() # Clocks are used to track and control the frame-rate of a game (how fast and how slow the pace of the game)
# This line creates and initializes a clock.
# color definitions, using RBG color model.
black = (0,0,0)
white = (255,255,255)
# initial center position for the square (bob)
x,y = 0,0
lastKey=0
game_loop=True
while game_loop:
for event in pygame.event.get(): # loop through all events
if event.type == pygame.QUIT:
game_loop = False # change the game_loop boolean to False to quit.
if event.type == pygame.KEYDOWN:
lastKey = event.key
#check last entered key
#lastKey equals "LEFT", "RIGHT", "UP", "DOWN" --> do the required stuff!
#set x coordinate minus 50 if left was pressed
if lastKey == pygame.K_LEFT:
x -= 50
if lastKey == pygame.K_RIGHT:
x += 50
if lastKey == pygame.K_UP:
y += 50
if lastKey == pygame.K_DOWN:
y -= 50
if event.key == pygame.K_LEFT:
x -= 50
if event.key == pygame.K_RIGHT:
x += 50
if event.key == pygame.K_UP:
y += 50
if event.key == pygame.K_DOWN:
y -= 50
# draw and update screen
window.fill( black ) # fill the screen with black overwriting even bob.
pygame.draw.rect( window, white, (x, y, 50, 50) ) # draw bob on the screen with new coordinates after its movement.
# the parameters are as follows: window: is the window object you want to draw on. white: the object color used to fill the rectangle
# (x,y,50,50) x is the x position of the left side of the rectangle. y is the y position of the upper side of the rectangle.
# In other words (x,y) is the coordinate of the top left point of the rectangle.
# 50 is the width, and 50 is the height
pygame.display.update() #updates the screen with the new drawing of the rectangle.
#fps stuff:
clock.tick(10) # this controls the speed of the game. low values makes the game slower, and large values makes the game faster.
pygame.quit()
any help would be much appreciated.
Try to save the entered key into a variable and check it after your Event-Loop.
Like this:
#...
lastKey = None
while game_loop:
for event in pygame.event.get(): # loop through all events
if event.type == pygame.QUIT:
game_loop = False # change the game_loop boolean to False to quit.
if event.type == pygame.KEYDOWN:
lastKey = event.key
#check last entered key
#lastKey equals "LEFT", "RIGHT", "UP", "DOWN" --> do the required stuff!
#set x coordinate minus 50 if left was pressed
if lastKey == pygame.K_LEFT
x -= 50
#<add the other statements here>
#(...)
I would recommend to not use that many if-statements. It could get a bit confusing after some time.
Check the following question out to keep your code brief:
Replacements for switch statement in Python?
You want to change the state of your application when you press a key. So you need a variable to keep track of that state (the state is: What direction should the box move?).
Here's a complete, minimal example that does what you're looking for. Note the comments.
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((640, 480))
screen_r = screen.get_rect()
clock = pygame.time.Clock()
rect = pygame.rect.Rect(0, 0, 50, 50)
# let's start at the center of the screen
rect.center = screen_r.center
# a dict to map keys to a direction
movement = {pygame.K_UP: ( 0, -1),
pygame.K_DOWN: ( 0, 1),
pygame.K_LEFT: (-1, 0),
pygame.K_RIGHT: ( 1, 0)}
move = (0, 0)
# a simple helper function to apply some "speed" to your movement
def mul10(x):
return x * 10
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
sys.exit()
# try getting a direction from our dict
# if the key is not found, we don't change 'move'
if e.type == pygame.KEYDOWN:
move = movement.get(e.key, move)
# move the rect by using the 'move_ip' function
# but first, we multiply each value in 'move' with 10
rect.move_ip(map(mul10, move))
# ensure that 'rect' is always inside the screen
rect.clamp_ip(screen_r)
screen.fill(pygame.color.Color('Black'))
pygame.draw.rect(screen, pygame.color.Color('White'), rect)
pygame.display.update()
clock.tick(60)
I use a Rect instead of keeping track of two coordinates x and y, since that allows to make use of the move_ip and clamp_ip functions to easily move the rect inside the screen.
Here are two versions, the first demonstrates how to utilize an event loop to get continuous movement (similar to Sloth's solution, but a bit simpler for beginners who don't know dictionaries yet), the second one shows how to achieve this with pygame.key.get_pressed().
Solution 1: Check which key was pressed in the event loop and change the x and y velocities to the desired values. Then add the velocities to the rect.x and rect.y positions in the while loop.
I'd actually recommend using vectors instead of the velocity_x and velocity_y variables and another one for the actual position of your sprite. pygame.Rects can't have floats as their coordinates and so a vector or separate variables for the position would be more accurate.
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect = pg.Rect(100, 200, 40, 60)
velocity_x = 0
velocity_y = 0
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
elif event.type == pg.KEYDOWN:
if event.key == pg.K_d:
velocity_x = 4
elif event.key == pg.K_a:
velocity_x = -4
elif event.type == pg.KEYUP:
if event.key == pg.K_d and velocity_x > 0:
velocity_x = 0
elif event.key == pg.K_a and velocity_x < 0:
velocity_x = 0
rect.x += velocity_x
rect.y += velocity_y
screen.fill((40, 40, 40))
pg.draw.rect(screen, (150, 200, 20), rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
Solution 2: Call pygame.key.get_pressed to check which key is currently being held down. Check if the left, right, up or down keys are held and then adjust the position of the sprite each frame.
pygame.key.get_pressed has the disadvantage that you can't know the order of the key presses, but the code looks a bit simpler.
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
rect = pg.Rect(100, 200, 40, 60)
velocity = (0, 0)
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
keys = pg.key.get_pressed()
if keys[pg.K_d]:
rect.x += 4
if keys[pg.K_a]:
rect.x -= 4
screen.fill((40, 40, 40))
pg.draw.rect(screen, (150, 200, 20), rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()

Add walk animation. I just want to have the sprite image change when i hold down the key, like shuffle between 3 different walking images.

This is my first post and i have no idea what i am doing hah, but i started learning pygame tonight
and i want to know to add a walk animation. I just want to variable "walk" to change images every .5 or so seconds of holding the
key down
import pygame
import time
pygame.init()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
#imports pygame and initializes the module
pygameDisplay = pygame.display.set_mode((800,600))
#creates a screen
pygame.display.set_caption("Snake(;")
gameExit = False
walk = pygame.image.load("pokemon walk sprite sheet.png")
walkx = 350
walky = 330
walkx_change = 0
clock = pygame.time.Clock()
while not gameExit:
pygameDisplay.blit(walk,(walkx,walky))
pygame.display.update()
clock.tick(30)
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
walkx_change = -10
walk = pygame.image.load("walk sheet left.png")
#right here i want code to make it switch to another image after .5 or so seconds
if event.key == pygame.K_RIGHT:
walkx_change = 10
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
walkx_change = 0
walkx += walkx_change
pygameDisplay.fill(white)
pygame.display.update()
clock.tick(30)
pygame.quit()
quit()
You can't do animation like that. You have to create a class with Sprite module first. And you have to import every image(frame) of your animation.
class Asker(Sprite):
def __init__(self, konum):
Sprite.__init__(self)
self.resimler = [pygame.image.load("01.png"), pygame.image.load("02.png"),pygame.image.load("03.png"),pygame.image.load("04.png"),pygame.image.load("05.png"),
pygame.image.load("06.png"),pygame.image.load("07.png"),pygame.image.load("08.png"),pygame.image.load("09.png"),pygame.image.load("10.png"),
pygame.image.load("11.png"),pygame.image.load("12.png"),pygame.image.load("13.png"),pygame.image.load("14.png"),pygame.image.load("15.png"),
pygame.image.load("16.png")]
self.image = self.resimler[0]
self.rect = self.image.get_rect()
self.rect.x, self.rect.y = konum
self.say = 0
It's an example from my script, see I load 16 pictures, you have to split them first with gimp or photoshop.That pictures I splitted them from an animation. Then you have to rotate them etc etc. You should check some tutorials of Sprite, before it, learn basic Pygame.

image is bad with python in pygame

I have a program in python:
import sys, random, pygame
from pygame.locals import *
pygame.init()
# Preparing Pygame
size = width, height = 718, 502
screen = pygame.display.set_mode(size)
framerate = pygame.time.Clock()
pygame.display.set_caption('Flappy Cube')
#Peparing background
background_x = 0
background_y = 0
background = pygame.image.load("background.jpg")
#Preparing Cube
cube_x = 100
cube_y = 200
cube_unscaled = pygame.image.load("cube.png")
cube = pygame.transform.smoothscale(cube_unscaled, (64, 64))
#Preparing Tubes
tube_x = 750
tube_y= 300
tube_unscaled = pygame.image.load("tube.png")
tube = pygame.transform.smoothscale(tube_unscaled, (125, 500))
# The main game loop
def exit_game():
sys.exit()
while True:
#Background
screen.blit(background, (background_x,background_y))
background_x = background_x+254.5
screen.blit(cube,(cube_x, cube_y))
#Tube
tube_x = tube_x -.075
screen.blit(tube,(tube_x, tube_y))
# If exit
for event in pygame.event.get():
if event.type == pygame.QUIT: exit_game()
# If Space Key is presed
elif event.type == pygame.KEYDOWN and event.key == K_SPACE:
cube_y = cube_y-10
#If Clicked
elif pygame.mouse.get_pressed()[0]:
cube_y = cube_y-10
framerate.tick(60)
pygame.display.flip()
run_game()
I get this result: http://i.stack.imgur.com/MKYRM.png
I have to boost framerate.tick(60) to framerate.tick(700) it looks a glichy. when I program the gravity the multiple images won't look good.
how can i fix the images been drawn multiple times before the screen updates?
Try:
cube_unscaled = pygame.image.load("cube.png").convert_alpha()
You shouldn't need to boost your FPS in such way, 60 is a good value.
Also, I like better this order for your main loop: check events, draw, update, tick.
I don't think it makes a difference to your problem, but I think it easier to understand that way.
while True:
# If exit
for event in pygame.event.get():
if event.type == pygame.QUIT: exit_game()
# If Space Key is presed
elif event.type == pygame.KEYDOWN and event.key == K_SPACE:
cube_y = cube_y-10
#If Clicked
elif pygame.mouse.get_pressed()[0]:
cube_y = cube_y-10
#Background
screen.blit(background, (background_x,background_y))
background_x = background_x+254.5
screen.blit(cube,(cube_x, cube_y))
#Tube
tube_x = tube_x -.075
screen.blit(tube,(tube_x, tube_y))
pygame.display.flip()
framerate.tick(60)
I fixed it! I just needed to fill the screen with black before "bliting" it.

Categories