I want to create the "illusion" so to speak that my character is walking, using multiple images from a sheet of multiple sprite positions. I only know how to move the single image using WASD. Here is my code so far:
room_bg = 'woodf.jpg'#wood floor background
screen = pygame.display.set_mode((640,360),0,32)
background = pygame.image.load(room_bg).convert()#background here
x,y = 290,150
movex, movey = 0,0
while 1:#blitting background to middle of screen, start of main game loop
screen.blit(background, (170,100))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_a:
movex = -1
pygame.image.load('s_left1.png')
pygame.Surface.blit(mc_left1)
elif event.key == K_d:
movex = +1
elif event.key == K_w:
movey = -1
elif event.key == K_s:
movey = +1
if event.type == KEYUP:
if event.key == K_a:
movex = 0
elif event.key == K_d:
movex = 0
elif event.key == K_w:
movey = 0
elif event.key == K_s:
movey = 0
x+= movex
y+= movey
mc = pygame.image.load('ss.png').convert()
mc.set_colorkey((0,0,0))
screen.blit(mc,(x,y))
pygame.display.update()
You first want to extract individual sprites from the sprite sheet, then you want to use, for example, an iterator for serving them to the drawing method in each call.
Here you have a tutorial on how to get individual images from the sprite sheet and how to use them for animation.
I doubt this is the most efficient way of animating a sprite, but it's been working for me so far.
First I load all the sprite frames into a list called spritesheet. Then each time a move event is triggered, I iterate through each frame, updating the display between each iteration. I also introduced a small time delay to make it look more fluid. Again, probably not the best way to do it, but it's a way.
for spriteframe in spritesheet:
x_add = x/len(spritesheet)
y_add = y/len(spritesheet)
player.setPosition( player.getX() + x_add, player.getY() + y_add )
updateBackground(current_map)
pygame.time.delay(40)
updateCharacter(player,spriteframe, image)
pygame.display.update()
Related
This question already has an answer here:
How to get if a key is pressed pygame [duplicate]
(1 answer)
Closed 1 year ago.
click here to see the image
PROGRAMING LANGUAGE THAT I USE IS PYTHON
As on the photo,i have a character(square) and i want when i press the left, right, up, down keys, it has to keep moving in that direction until it hits the wall then stops.But when i press those keys, it only moves once and not continuously like i thought.how to make it move continuously
import pygame
pygame.init()
clock = pygame.time.Clock()
#display
window = pygame.display.set_mode((600,600))
caption = pygame.display.set_caption('SwipeIt')
#player
square = pygame.image.load('asset/square.png').convert_alpha()
square_rect = square.get_rect(center = (100,150))
#wall
wall1 = pygame.image.load('asset/wall1.png').convert()
wall2 = pygame.image.load('asset/wall2.png').convert()
screw = pygame.image.load('asset/screw.png').convert()
white = (255,252,252)
gravity = 0.25
swipe = 0
loop = True
while loop:
print(window)
window.fill(white)
#wall
window.blit(wall1,(0,0))
window.blit(wall2,(0,0))
window.blit(wall2,(565,0))
window.blit(wall1,(0,566))
window.blit(screw,(0,0))
window.blit(screw,(0,566))
window.blit(screw,(565,0))
window.blit(screw,(565,566))
#player
window.blit(square,(square_rect))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
swipe += gravity
square_rect.centery += swipe
if event.key == pygame.K_UP:
swipe -= gravity
square_rect.centery -= swipe
if event.key == pygame.K_RIGHT:
swipe += gravity
square_rect.centerx += swipe
if event.key == pygame.K_LEFT:
swipe -= gravity
square_rect.centerx -= swipe
if event.type == pygame.QUIT:
loop = False
pygame.display.flip()
pygame.display.update()
clock.tick(120)
If you need, here is the link to download the files I have used .
''https://www.mediafire.com/file/ilogoklz3t9abpa/asset.rar/file''
I've made a snake game before and how I did it is by using a variable called direction.
Here is a little snippet from it.
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
direction = "up"
if event.key == pygame.K_DOWN:
direction = "down"
if event.key == pygame.K_RIGHT:
direction = "right"
if event.key == pygame.K_LEFT:
direction = "left"
Then I would check the current direction and change the position depending on the direction.
For example:
one would be
if direction == "up":
player_y += 5
I have started making something on pygame but I have encountered an issue when moving left or right. if I quickly change from pressing the right arrow key to pressing the left one and also let go of the right one the block just stops moving. this is my code
bg = "sky.jpg"
ms = "ms.png"
import pygame, sys
from pygame.locals import *
x,y = 0,0
movex,movey=0,0
pygame.init()
screen=pygame.display.set_mode((664,385),0,32)
background=pygame.image.load(bg).convert()
mouse_c=pygame.image.load(ms).convert_alpha()
m = 0
pygame.event.pump()
while 1:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type==KEYDOWN:
if event.key==K_LEFT:
movex =-0.5
m = m + 1
if event.key==K_RIGHT:
movex=+0.5
m = m + 1
elif event.type == KEYUP:
if event.key==K_LEFT and not event.key==K_RIGHT:
movex = 0
if event.key==K_RIGHT and not event.key==K_LEFT:
movex =0
x+=movex
y=200
screen.blit(background, (0,0))
screen.blit(mouse_c,(x,y))
pygame.display.update()
is there a way I can change this so if the right arrow key is pressed and the left arrow key is released that it will go right instead of stopping?
P.S
I am still learning pygame and am very new to the module. I'm sorry if this seems like a stupid question but i couldn't find any answers to it.
Your problem is that when you test the KEYDOWN events with
if event.key==K_LEFT and not event.key==K_RIGHT:
you always get True, because when event.key==K_LEFT is True,
it also always is not event.key==K_RIGHT (because the key of the event is K_LEFT after all).
My approach to this kind of problem is to separate
the intent from the action. So, for the key
events, I would simply keep track of what action
is supposed to happen, like this:
moveLeft = False
moveRight = False
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_LEFT: moveLeft = True
if event.key == K_RIGHT: moveRight = True
elif event.type == KEYUP:
if event.key == K_LEFT: moveLeft = False
if event.key == K_RIGHT: moveRight = False
Then, in the "main" part of the loop, you can
take action based on the input, such as:
while True:
for event in pygame.event.get():
...
if moveLeft : x -= 0.5
if moveRight : x += 0.5
the problem is that you have overlapping key features; If you hold down first right and then left xmove is first set to 1 and then changes to -1. But then you release one of the keys and it resets xmove to 0 even though you are still holding the other key. What you want to do is create booleans for each key. Here is an example:
demo.py:
import pygame
window = pygame.display.set_mode((800, 600))
rightPressed = False
leftPressed = False
white = 255, 255, 255
black = 0, 0, 0
x = 250
xmove = 0
while True:
window.fill(white)
pygame.draw.rect(window, black, (x, 300, 100, 100))
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
rightPressed = True
if event.key == pygame.K_LEFT:
leftPressed = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
rightPressed = False
if event.key == pygame.K_LEFT:
leftPressed = False
xmove = 0
if rightPressed:
xmove = 1
if leftPressed:
xmove = -1
x += xmove
pygame.display.flip()
One way could be to create a queue that keeps track of the button that was pressed last. If we press the right arrow key we'll put the velocity first in the list, and if we then press the left arrow key we put the new velocity first in the list. So the button that was pressed last will always be first in the list. Then we just remove the button from the list when we release it.
import pygame
pygame.init()
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
FPS = 30
rect = pygame.Rect((350, 220), (32, 32)) # Often used to track the position of an object in pygame.
image = pygame.Surface((32, 32)) # Images are Surfaces, so here I create an 'image' from scratch since I don't have your image.
image.fill(pygame.Color('white')) # I fill the image with a white color.
velocity = [0, 0] # This is the current velocity.
speed = 200 # This is the speed the player will move in (pixels per second).
dx = [] # This will be our queue. It'll keep track of the horizontal movement.
while True:
dt = clock.tick(FPS) / 1000.0 # This will give me the time in seconds between each loop.
for event in pygame.event.get():
if event.type == pygame.QUIT:
raise SystemExit
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
dx.insert(0, -speed)
elif event.key == pygame.K_RIGHT:
dx.insert(0, speed)
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
dx.remove(-speed)
elif event.key == pygame.K_RIGHT:
dx.remove(speed)
if dx: # If there are elements in the list.
rect.x += dx[0] * dt
screen.fill((0, 0, 0))
screen.blit(image, rect)
pygame.display.update()
# print dx # Uncomment to see what's happening.
You should of course put everything in neat functions and maybe create a Player class.
I know my answer is pretty late but im new to Pygame to and for beginner like me doing code like some previous answer is easy to understand but i have a solution to.I didn`t use the keydown line code, instead i just put the moving event code nested in the main game while loop, im bad at english so i give you guy an example code.
enter code here
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT or event.type == pygame.K_ESCAPE:
run = False
win.blit(bg, (0, 0))
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
x -= 5
if pressed[pygame.K_RIGHT]:
x += 5
if pressed[pygame.K_UP]:
y -= 5
if pressed[pygame.K_DOWN]:
y += 5
win.blit(image,(x,y))
pygame.display.update()
pygame.quit()
This will make the image move rapidly without repeating pushing the key, at long the code just in the main while loop with out inside any other loop.
I'm stuck trying to change the sprite blitted to the screen (when moving upwards) to a back view of the sprite.
Currently the sprite is just blitted to the white background on each key press at the most recent x and y coordinates and not fluidly moving along the screen (i want to move the sprite continuously on set trajectories, based on arrow key press, like in snake).
This is my first stab at programming anything on python so Leyman's terms if possible!
lead_x_change = 0
lead_y_change = 0
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x_change = -5
if event.key == pygame.K_RIGHT:
lead_x_change = 5
#above are two snips of code to show the method i'm using to move the sprite
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT or event.key == pygame.K_DOWN:
gameDisplay.fill(white)
gameDisplay.blit(spriteX,(lead_x,lead_y))
pygame.display.update()
if event.key == pygame.K_UP:
gameDisplay.fill(white)
gameDisplay.blit(spriteY,(lead_x,lead_y))
pygame.display.update()
lead_y += lead_y_change
lead_x += lead_x_change
clock.tick(60)
pygame.quit()
quit()
I think there are two plausible ways you can change your sprite depending on the direction you're moving.
First off, lets fix your current drawing logic, so that you draw the sprite regardless of keypresses:
while not gameExit:
for event in pygame.event.get(): # event loop handles setting player speed
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x_change = -5
if event.key == pygame.K_RIGHT:
lead_x_change = 5
lead_y += lead_y_change # update logic moves the position
lead_x += lead_x_change
gameDisplay.fill(white) # draw logic draws the background and the sprite
gameDisplay.blit(spriteX,(lead_x,lead_y))
pygame.display.update()
clock.tick(60)
The approach to the sprite is to change it at the same place you change your speed (in the event code), then use the changed sprite later when you actually draw the scene.
player_sprite = spriteX
while not gameExit:
for event in pygame.event.get(): # event loop handles setting speed and the sprite
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x_change = -5
player_sprite = spriteX
if event.key == pygame.K_UP:
lead_y_change = -5
player_sprite = spriteY
lead_y += lead_y_change # update logic moves the position
lead_x += lead_x_change
gameDisplay.fill(white) # draw logic draws the background and the sprite
gameDisplay.blit(player_sprite,(lead_x,lead_y))
pygame.display.update()
clock.tick(60)
The second approach is to limit the event code to just setting the speed, and then later examining the speed that has been set to pick a sprite to draw.
player_sprite = spriteX
while not gameExit:
for event in pygame.event.get(): # event loop handles setting speed only
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
lead_x_change = -5
if event.key == pygame.K_UP:
lead_y_change = -5
lead_y += lead_y_change # update logic moves the position
lead_x += lead_x_change
if lead_y_change < 0: # set sprite based on speed
player_sprite = spriteY
else:
player_sprite = spriteX
gameDisplay.fill(white) # draw logic draws the background and the sprite
gameDisplay.blit(player_sprite,(lead_x,lead_y))
pygame.display.update()
clock.tick(60)
For very simple logic with only a few different sprites, the event driven sprite changes may be easiest. If you want animations or other more complicated sprite changing behavior, the second approach may be better, since you will be able to handle all the sprite logic in one place.
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
My while loops only maintains the movement for the sprite while the cursor is moving inside of the screen. I've tried reorganizing some of the screen.blits and display.update() and display.flip(). I can't seem to figure out why the character stops after a change in one pixel instead of continuing like it I intended.
background_image = 'Terrain_Grass_First.png'
import pygame, sys
from pygame.locals import *
pygame.init()
pygame.display.set_caption('Hans')
screen_width = 600
screen_height = 400
screen = pygame.display.set_mode((screen_width, screen_height),0,32)
pygame.mouse.set_visible(False)
sprite = pygame.image.load('Hans_front_still.png').convert_alpha()
x,y = (0,0)
movex, movey = (0,0)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_w:
y = -1
elif event.key == K_a:
x = -1
elif event.key == K_s:
y = +1
elif event.key == K_d:
x = +1
elif event.type == KEYUP:
if event.key == K_w:
y = 0
elif event.key == K_a:
x = 0
elif event.key == K_s:
y = 0
elif event.key == K_d:
x = 0
movex += x
movey += y
screen.fill((0,0,0))
screen.blit(sprite,(movex,movey))
pygame.display.flip()
Your loop blocks on pygame.event.get.
You don't schedule any events of your own.
So, you do nothing until the OS has an event (mouse move, redraw, etc.) to give you.
And, even if you fixed that, you're calling movex += x once per event. So, when the OS is throwing a lot of events at you, your sprite will go zipping madly across the screen, but when the events are coming more slowly, it will crawl along. That's almost never what you want.
An easy fix for both problems is to just schedule your own events. For example, with pygame.time.set_timer(), you can make sure you get an event every, say, 250 milliseconds, and you can only move the sprite on those events. For example:
timer_event = pygame.USEREVENT + 1
pygame.time.set_timer(timer_event, 250)
while True:
for event in pygame.event.get():
# ...
elif event.type == timer_event:
movex += x
movey += y
Another alternative is to design your game with a fixed framerate.
A trivial example looks like this:
FRAME_TIME = 50 # 50ms = 20fps
next_frame_time = pygame.time.get_ticks() + FRAMES
while True:
while True:
event = pygame.event.poll()
if event.type == pygame.NOEVENT:
break
elif # ...
pygame.display.flip()
now = pygame.time.get_ticks()
if now < next_frame_time:
pygame.time.wait(next_frame_time - now)
next_frame_time += FRAMES
Now you can just move every 5th frame.
A realistic example has to deal with missed frames, too many events in the queue, choose between wait and delay appropriately, etc.
But I'd go with the event-driven version with a timer instead of a fixed-framerate version in most cases, especially if you're already going down that line.
The only problem is your Indentation!
The fifth and sixth lines from the bottom have wrong indentation, and you need to delete them.
These two lines:
movex += x
movey += y
should be:
movex += x
movey += y
And it works