Trying to move image around screen, but "animation" is choppy - python

If I hit a key it won't show the new position until I let off it. It almost teleports to the new spot instead of seeing it move to it. I previously made a square to move around with no issue. Tried looking at that code and doing the something but I'm missing something.
import pygame
import sys
pygame.init()
window = 900, 700
screen = pygame.display.set_mode(window)
title = pygame.display.set_caption("ASTEROOOIDDD")
clock = pygame.time.Clock()
x = 340
y = 280
step = 1
background_surface = pygame.image.load('asteroid/images/background.jpg')
spaceship_surface = pygame.image.load('asteroid/images/ship.png')
spaceship_surface = pygame.transform.scale(spaceship_surface, (80,80))
while True:
for eve in pygame.event.get():
if eve.type==pygame.QUIT:
pygame.quit()
sys.exit()
screen.blit(background_surface,(0,0))
screen.blit(spaceship_surface,(x,y))
key_input = pygame.key.get_pressed()
if key_input[pygame.K_LEFT]:
x -= step
if key_input[pygame.K_UP]:
y -= step
if key_input[pygame.K_RIGHT]:
x += step
if key_input[pygame.K_DOWN]:
y += step
spaceship_surface.blit(spaceship_surface, (x,y))
pygame.display.update()
clock.tick(30)

It is a matter of Indentation. The display needs to be updated in every frame. (At least in every frame where something changes). The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
import pygame
import sys
pygame.init()
window = 900, 700
screen = pygame.display.set_mode(window)
title = pygame.display.set_caption("ASTEROOOIDDD")
clock = pygame.time.Clock()
x = 340
y = 280
step = 1
background_surface = pygame.image.load('asteroid/images/background.jpg')
spaceship_surface = pygame.image.load('asteroid/images/ship.png')
spaceship_surface = pygame.transform.scale(spaceship_surface, (80,80))
while True:
for eve in pygame.event.get():
if eve.type==pygame.QUIT:
pygame.quit()
sys.exit()
# INDENTATION
#<--|
screen.blit(background_surface,(0,0))
screen.blit(spaceship_surface,(x,y))
key_input = pygame.key.get_pressed()
if key_input[pygame.K_LEFT]:
x -= step
if key_input[pygame.K_UP]:
y -= step
if key_input[pygame.K_RIGHT]:
x += step
if key_input[pygame.K_DOWN]:
y += step
spaceship_surface.blit(spaceship_surface, (x,y))
pygame.display.update()
clock.tick(30)

You just need to bring your screen.blit outside the event handler loop.
while True:
for eve in pygame.event.get():
if eve.type == pygame.QUIT:
pygame.quit()
sys.exit()
screen.blit(background_surface, (0, 0))
screen.blit(spaceship_surface, (x, y))
key_input = pygame.key.get_pressed()
if key_input[pygame.K_LEFT]:
x -= step
if key_input[pygame.K_UP]:
y -= step
if key_input[pygame.K_RIGHT]:
x += step
if key_input[pygame.K_DOWN]:
y += step
spaceship_surface.blit(spaceship_surface, (x, y))
pygame.display.update()
clock.tick(30)

Related

Pygame player movement is being weird

I was making a pygame project and i made a square move and It would summon a square every frame and there would just be a line of squares.
I tried to update the screen every frame (Because i hadn't yet), but that did not work. Here is my code:
#Import Pygame
import pygame
#screen object(width, height)
screen_x = 750
screen_y = 600
screen = pygame.display.set_mode((screen_x, screen_y))
#Set the caption of the screen
pygame.display.set_caption('Game')
#Define a velocity, x, and y variable
velocity = 2.5x = 0.0y = 0.0
#Variable to keep our game loop running
running = True
#Game loop
while running:
# Initialing Color
color = (255,0,0)
if pygame.key.get_pressed()[pygame.K_w]:
y += 2.5
if pygame.key.get_pressed()[pygame.K_s]:
y -= 2.5
if pygame.key.get_pressed()[pygame.K_a]:
x -= 2.5
if pygame.key.get_pressed()[pygame.K_d]:
x += 2.5
# Drawing Rectangle
pygame.draw.rect(screen, color, pygame.Rect(x, y, 50, 50))
pygame.display.flip()
pygame.display.update()
# for loop through the event queue
for event in pygame.event.get():
# Check for QUIT event
if event.type == pygame.QUIT:
running = False
The entire scene is redrawn in every frame, therefore you have to clear the display in every frame:
import pygame
#screen object(width, height)
screen_x = 750
screen_y = 600
screen = pygame.display.set_mode((screen_x, screen_y))
#Set the caption of the screen
pygame.display.set_caption('Game')
#Define a velocity, x, and y variable
velocity = 2.5
x, y = 0, 0
color = (255,0,0)
clock = pygame.time.Clock()
running = True
while running:
clock.tick(100)
# for loop through the event queue
for event in pygame.event.get():
# Check for QUIT event
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
x += (keys[pygame.K_d] - keys[pygame.K_a]) * velocity
y += (keys[pygame.K_s] - keys[pygame.K_w]) * velocity
# clear display
screen.fill((0, 0, 0))
# Drawing Rectangle
pygame.draw.rect(screen, color, pygame.Rect(x, y, 50, 50))
# update display
pygame.display.flip()
pygame.quit()
exit()
The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
The solution is very simple. You forgot to fill the screen with a color. Because your code just draw's a square to the screen surface every frame, and that's why it's drawing a line of squares. You have to fill the screen before drawing the things, because otherwise you will see an empty screen with that color, that you filled the surface with. Hope it helped.

pygame movement speed is not constant [duplicate]

This question already has answers here:
Pygame clock and event loops
(1 answer)
Framerate affect the speed of the game
(1 answer)
Closed last year.
I recently started with pygame and im trying to create movement but when I move my rectangle the speed changes at various times. it becomes slower and faster at various times
import pygame
pygame.init() # inisializing pygame
WIN = pygame.display.set_mode((500, 500)) # the width and hieght of the window
pygame.display.set_caption('pygame tutorial') # give the window a title
x = 50
y = 50 # character x and y positions
width = 40
height = 60 # rectangle width and height
vel = 5 # velocity (speed)
run = True # boolean variable
while run: # forever loop
for event in pygame.event.get(): # specifing the event
if event.type == pygame.QUIT: # pygame.QUIT makes the red x work so you can close the window
run = False # run = false so the while loop stops
key = pygame.key.get_pressed()
if key [pygame.K_a]:
x -= vel
if key[pygame.K_d]:
x += vel
if key[pygame.K_w]:
y -= vel
if key[pygame.K_s]:
y += vel
WIN.fill((0,0,0))
pygame.draw.rect(WIN, (255, 0, 0), (x, y, width, height))
'''
create a rectangle with 3 arguements, the window, the rgb colour, and the x,y positions width and height
'''
pygame.display.update()
pygame.quit()
You have wrong indentations so some code is executed inside many times in for-loop but it should be executed only once after for-loop
After changing indentations code work too fast and I needed to add clock.tick(60) to reduce speed to max 60 frames per second. This way it should run with the same speed on computers with older and newer CPU.
WIN = pygame.display.set_mode((500, 500)) # the width and hieght of the window
pygame.display.set_caption('pygame tutorial') # give the window a title
x = 50
y = 50 # character x and y positions
width = 40
height = 60 # rectangle width and height
vel = 5 # velocity (speed)
run = True # boolean variable
clock = pygame.time.Clock()
while run: # forever loop
for event in pygame.event.get(): # specifying the event
if event.type == pygame.QUIT: # pygame.QUIT makes the red x work so you can close the window
run = False # run = false so the while loop stops
# --- after loop --
key = pygame.key.get_pressed()
if key [pygame.K_a]:
x -= vel
if key[pygame.K_d]:
x += vel
if key[pygame.K_w]:
y -= vel
if key[pygame.K_s]:
y += vel
WIN.fill((0,0,0))
pygame.draw.rect(WIN, (255, 0, 0), (x, y, width, height))
'''
create a rectangle with 3 arguments, the window, the rgb colour, and the x,y positions width and height
'''
pygame.display.update()
clock.tick(60) # reduce speed to max 60 frames per seconds
pygame.quit()

how to make object keep moving up

I'm making a game with Python. I have a spaceship in this game. The spaceship can move to the left and to the right and it is supposed to shoot bullets from its x-position and it is supposed to fire the bullets up. I am able to move the spaceship and I am able to put it on the screen. The problem is that I am not able to fire the bullet from the spaceship's x-position and I am not able to make the bullet move up. Can somebody help me with this? Please post simple code too if possible.
Here's the code:
import pygame
import sys
pygame.init()
screen_length = 512
screen_width = 288
clock = pygame.time.Clock()
screen = pygame.display.set_mode((screen_width, screen_length))
bg = pygame.image.load(r'C:\Users\Anonymous\Downloads\space game folder\space background3.png').convert()
bg = pygame.transform.scale2x(bg)
spaceship = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\spaceship.png').convert()
missile = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\bullet2.png').convert()
x = 130
y = 480
z = 460
velocity = 30
spaceship_rect = spaceship.get_rect(center=(x, y))
spaceship_x_pos = spaceship_rect.left + 170
bullet_speed = 10
missile_rect = missile.get_rect(center=(round(spaceship_x_pos // 2), z))
spaceship_direction = 10
while True:
for event in pygame.event.get():
if event == pygame.QUIT:
pygame.display.quit()
sys.exit(0)
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] and x < 288:
x += velocity
if keys[pygame.K_LEFT] and x > 0:
x -= velocity
if keys[pygame.K_SPACE]:
bg.blit(missile, missile_rect)
screen.fill(0)
screen.blit(bg, (0, 0))
screen.blit(spaceship, (x, y))
pygame.display.update()
clock.tick(120)
The problem with your code is that your indentation is not right.
while True:
for event in pygame.event.get():
if event == pygame.QUIT:
pygame.display.quit()
sys.exit(0)
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] and x < 288:
x += velocity
if keys[pygame.K_LEFT] and x > 0:
x -= velocity
if keys[pygame.K_SPACE]:
bg.blit(missile, missile_rect)
screen.fill(0) # THIS
screen.blit(bg, (0, 0)) #THIS
screen.blit(spaceship, (x, y)) #THIS
pygame.display.update() #THIS
clock.tick(120) #THIS
The lines where i commented this have to be indented like this:
while True:
for event in pygame.event.get():
if event == pygame.QUIT:
pygame.display.quit()
sys.exit(0)
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] and x < 288:
x += velocity
if keys[pygame.K_LEFT] and x > 0:
x -= velocity
if keys[pygame.K_SPACE]:
bg.blit(missile, missile_rect)
screen.fill(0)
screen.blit(bg, (0, 0))
screen.blit(spaceship, (x, y))
pygame.display.update()
clock.tick(120)
That's because you want to do those things every single frame while the game is running. One more thing, you are filling the screen with black in line screen.fill(0), which is not necessary since you are already rendering a background image, so you basically cannot see it. With that being said, i recommend taking an object oriented approach as well because you wont get very far without it. Also, set velocity to like 0.5 or something. Its currently 30, which means 30 pixels every frame and that's not what you want.
Now to fire bullets. What you are doing right now wont work because you are only "blitting" a missile if space is pressed. Below i wrote a separate code for you that only fires missiles, so hopefully its clear and you can implement in your own code.
import pygame
import sys
pygame.init()
d = pygame.display.set_mode((1200, 600))
# WE WILL USE FIRING BOOLEAN TO KEEP TRACK OF IF WE ARE FIRING MISSILES
firing = False
missile = pygame.Surface((10, 50))
while True:
d.fill((255, 255, 255))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
# Assign initial positions only if it isnt firing
if not firing:
missilex = 600 # This is the initial position of the missile. This will be
missiley = 500 # your player position in your game
if pygame.key.get_pressed()[pygame.K_SPACE]: # if space pressed set firing to true
firing = True
# if firing is true, we want to display the missile and move it.
if firing:
d.blit(missile, (missilex, missiley))
missiley -= 1
# if missile is off the screen, set firing to false so it resets to initial position (600, 500).
if missiley < -20:
firing = False
pygame.display.update()
The way you are approaching it doesn't seem right to me, unless ofc that isn't your whole code. But you are using the same variable to represent the x and y coordinate of your bullet and the spaceship. You want to bullet to move independently from the space ship. So if you change the variable y in your code, that will move space ship up too, and same with the x variable.
What you need to do is to create 2 separate classes. One for you bullet, and the other for the space ship. Here is a simple example of its implementation, which you can improve upon by adding whatever features you want later.
class Spaceship:
image = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\spaceship.png').convert()
def __init__(self, x, y, vel):
self.x = x
self.y = y
self.vel = vel
def draw(self, screen):
screen.blit(Spaceship.image, (self.x, self.y))
class Bullet:
image = pygame.image.load(r'C:\Users\Soorya\Anonymous\space game folder\bullet2.png').convert()
bullet_list = [] # holds the list of bullets in the screen
def __init__(self, x, y, vel):
self.x = x
self.y = y
self.vel = vel
Bullet.bullet_list.append(self)
def move(self):
self.y -= self.vel
if self.y < 0: # remove bullet if it goes beyond screen
Bullet.bullet_list.remove(self)
def draw(self, screen):
screen.blit(Bullet.image, (self.x, self.y))
spaceship = Spaceship(130, 480, 30)
# set up screen and bg as before
while True:
for event in pygame.event.get():
if event == pygame.QUIT:
pygame.display.quit()
sys.exit(0)
keys = pygame.key.get_pressed()
if keys[pygame.K_RIGHT] and x < 288:
spaceship.x += spaceship.vel
if keys[pygame.K_LEFT] and x > 0:
spaceship.x -= spaceship.vel
if keys[pygame.K_SPACE]: # create a bullet if space is pressed
Bullet(spaceship.x, spaceship.y, 10)
screen.blit(bg, (0, 0))
spaceship.draw()
for bullet in Bullet.bullet_list():
bullet.move() # actually moves the bullet on each iteration of the loop
bullet.draw()
pygame.display.update()
clock.tick(120)
Important note for future if you want to create games, make everything object oriented lol. Trust me, it will make your life a whole lot easier. Let me know if you have any problems.

Trouble with blitting images pygame

I am practicing my pygame skills by making a small project. In it, it will blit a background image to the screen. Afterwards, it will use a list called soldiers, and if the item it takes in the list is 1, it will print a soldier, if it is 0, it will skip a space. When I run the code however, it blits the background, then the sprites, then the sprites disappear. I want my sprites to stay on the screen after the for loop has finished. Here is the for loop section:
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.blit(background_img, (0,0))
for i in soldiers:
if i == 1:
screen.blit(sprite_img,(x,y))
x = x + 50
time.sleep(0.5)
pygame.display.update()
elif i == 0:
x = x + 50
time.sleep(0.5)
pygame.display.update()
pygame.display.update()
Here is all my code:
import sys, pygame, time
from pygame.locals import *
pygame.init()
soldiers = [0,1,1,1,1,0,0,1,1,0]
x = 0
y = 50
background_img = pygame.image.load("/home/myname/Desktop/Army Project/images/background.png")
sprite_img = pygame.image.load("/home/myname/Desktop/Army Project/images/sprite.png")
size = background_img.get_size()
rect = background_img.get_rect()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Army Men")
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.blit(background_img, (0,0))
for i in soldiers:
if i == 1:
screen.blit(sprite_img,(x,y))
x = x + 50
time.sleep(0.5)
pygame.display.update()
elif i == 0:
x = x + 50
time.sleep(0.5)
pygame.display.update()
pygame.display.update()
Thank you for your time.
There are few issues with your code.
First, the pygame.display.update() is redundant in the for loop. You only need to call it once per frame, in your case it will be twice.
Second, do not use time.sleep() in pygame. This essentially freezes your game. So you cannot do anything in it. If you want some sort of a delay, use a timer.
Third, this line appears twice in your if else construct x = x + 50. You could move it outside of the if else.
Lastly, I think your problem is caused by not reseting the variable x. So they still get blit, but outside of the screen.
The code after fixing:
import sys, pygame, time
from pygame.locals import *
pygame.init()
soldiers = [0,1,1,1,1,0,0,1,1,0]
x = 0
y = 50
background_img = pygame.image.load("/home/myname/Desktop/Army Project/images/background.png")
sprite_img = pygame.image.load("/home/myname/Desktop/Army Project/images/sprite.png")
size = background_img.get_size()
rect = background_img.get_rect()
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Army Men")
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
screen.blit(background_img, (0,0))
x = 0
for i in soldiers:
if i == 1:
screen.blit(sprite_img,(x,y))
x = x + 50
pygame.display.update()

pygame key.set_repeat not working

I am new to pygame and I am trying to make pong in order to learn it. I am trying to make smooth controls so that holding down an arrow will work, but it is not working right now.
import sys, pygame
pygame.init()
size = (500, 350)
screen = pygame.display.set_mode(size)
x = 1
xwid = 75
yhei = 5
pygame.key.set_repeat(0, 500)
while True:
vector = 0
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
vector = 4
elif event.key == pygame.K_LEFT:
vector = -4
pygame.draw.rect(screen,(255,255,255),(x,size[1] - yhei,xwid,yhei),0)
pygame.display.update()
screen.fill((0,0,0))
x += vector
if x <= 0:
x = 0
elif x >= size[0] - xwid:
x = size[0] - xwid
why does this not work for holding down the left or right arrows?
pygame.key.set_repeat(0, 500)
If you set the delay parameter to 0, key repeat will be disabled. The documentation isn't quite clear about that:
pygame.key.set_repeat()
control how held keys are repeated
set_repeat() -> None
set_repeat(delay, interval) -> None
When the keyboard repeat is enabled, keys that are held down will generate
multiple pygame.KEYDOWN events. The delay is the number of
milliseconds before the first repeated pygame.KEYDOWN will be sent.
After that another pygame.KEYDOWN will be sent every interval
milliseconds. If no arguments are passed the key repeat is disabled.
When pygame is initialized the key repeat is disabled.
Emphasis mine.
You could set the delay to 1, and it would work as expected:
pygame.key.set_repeat(1, 10) # use 10 as interval to speed things up.
But note that you should not use set_repeat and the pygame.KEYDOWN event to implement movement. If you do, you won't be able to observe real single key strokes, since if the player presses a key, a whole bunch of pygame.KEYDOWN events would be created.
Better use pygame.key.get_pressed(). Have a look at his minimal example:
import pygame
pygame.init()
screen = pygame.display.set_mode((680, 460))
clock = pygame.time.Clock()
# use a rect since it will greatly
# simplify movement and drawing
paddle = pygame.Rect((0, 0, 20, 80))
while True:
if pygame.event.get(pygame.QUIT): break
pygame.event.pump()
# move up/down by checking for pressed keys
# and moving the paddle rect in-place
keys = pygame.key.get_pressed()
if keys[pygame.K_UP]: paddle.move_ip(0, -7)
if keys[pygame.K_DOWN]: paddle.move_ip(0, 7)
# ensure the paddle rect does not go out of screen
paddle.clamp_ip(screen.get_rect())
screen.fill((0,0,0))
pygame.draw.rect(screen, (255,255,255), paddle)
pygame.display.flip()
clock.tick(60)
try it !
pygame.key.set_repeat(1,500)
I know what do you mean. Try this:
import sys, pygame
from pygame.locals import *
pygame.init()
size = (500, 350)
screen = pygame.display.set_mode(size)
x = 1
xwid = 75
yhei = 5
clock = pygame.time.Clock()
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
key_pressed = pygame.key.get_pressed()
if key_pressed[K_LEFT]:
x -= 4
if x <= 0:
x = 0
if key_pressed[K_RIGHT]:
x += 4
if x >= size[0] - xwid:
x = size[0] - xwid
pygame.draw.rect(screen,(255,255,255),(x,size[1] - yhei,xwid,yhei),0)
pygame.display.update()
screen.fill((0,0,0))

Categories

Resources