Trouble with blitting images pygame - python

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()

Related

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

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)

Pygame screen doesn't seem to refresh

I've been trying to make a Chrome Dino Game, however, I'm struggling with this problem:
On every frame, it should draw a new one at the new position and delete the previous one to make it look as if it's moving. HOWEVER, it remains at its previous position and a new image appears on its next position. I did write the pygame.display.update() code at the end of my maintop.
In the last time I ran into a similar problem, I managed to make it work by drawing a background image, but this time, it doesn't work.
following are my codes:
import pygame
import os
from random import randint
import schedule
pygame.init()
assets = os.path.join(os.path.dirname(__file__), "Assets")
screen_size = (screen_width, screen_height) = (1280, 720)
screen = pygame.display.set_mode(screen_size)
clock = pygame.time.Clock()
fps = 120
bg = pygame.image.load(os.path.join(assets, "IMG_15.png"))
ground = 700
running = True
spacebaridx = 0
gamestart = False
tick_on_start = 0
obs1 = pygame.image.load(os.path.join(assets, "colourmat/light_green.png"))
pygame.transform.scale(obs1, (100, 200))
obs2 = pygame.image.load(os.path.join(assets, "colourmat/light_green.png"))
pygame.transform.scale(obs2, (120, 200))
obs3 = pygame.image.load(os.path.join(assets, "colourmat/light_green.png"))
pygame.transform.scale(obs3, (150, 200))
ls_obs = []
def create_obs():
k = randint(1, 3)
if k == 1:
info = {"type":1, "img":obs1, "x":screen_width, "y":ground - 200, "tox":2}
ls_obs.append(info)
if k == 2:
info = {"type":2, "img":obs2, "x":screen_width, "y":ground - 200, "tox":2}
ls_obs.append(info)
else:
info = {"type":3, "img":obs3, "x":screen_width, "y":ground - 200, "tox":2}
ls_obs.append(info)
schedule.every(3).seconds.do(create_obs)
while running:
dt = clock.tick(fps)
if gamestart == True:
game_ticks = pygame.time.get_ticks() - tick_on_start
schedule.run_pending()
else:
game_ticks = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT: running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if spacebaridx == 0: # Press space to start / to tell whether it's the first press
spacebaridx += 1
gamestart = True
tick_on_start = pygame.time.get_ticks()
else:
pass # Jump
for o in ls_obs:
o["x"] += o["tox"] * -1
screen.blit(bg, (0, 0))
for o in ls_obs:
screen.blit(o["img"], (o["x"], o["y"]))
pygame.display.update()
pygame.quit()
This issue is occurring because you aren't clearing the display within each frame. In pygame, in order to clear the display, we need to use the fill method. So in your code, at the top of your game loop before the event loop, add screen.fill((0, 0, 0)). This will fill your screen in the color black. Don't worry, the black won't be shown if you draw the background on top of it. Now, when you add a new image, the previous images won’t be displayed.
Modified Game Loop
while running:
screen.fill((0, 0, 0))
dt = clock.tick(fps)
if gamestart == True:
game_ticks = pygame.time.get_ticks() - tick_on_start
schedule.run_pending()
else:
game_ticks = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT: running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if spacebaridx == 0: # Press space to start / to tell whether it's the first press
spacebaridx += 1
gamestart = True
tick_on_start = pygame.time.get_ticks()
else:
pass # Jump
for o in ls_obs:
o["x"] += o["tox"] * -1
screen.blit(bg, (0, 0))
for o in ls_obs:
screen.blit(o["img"], (o["x"], o["y"]))
pygame.display.update()
pygame.quit()

Python/Pygame; MOUSEBUTTONDOWN event

Okay I'm pretty new to using Pygame, I'm really just playing around with some of the methods and events. So far i pretty much have an image that moves around the pygame frame and bounces off any of the edges of the frame when it hits it. if the image touches the top of the frame it will increase a count variable by 1 which will be displayed on the screen. I then wanted to add a feature whereby if I clicked the image which was moving it would also add one onto the count variable. When i added this code in however (I think because the function operates on a loop), depending how long you hold the mouse down, count increases by a multiple of 8. I want to make it so that no matter how long i hold the mouse down for, the event stored inside the MOUSEBUTTONDOWN handler will only fire once. what am I doing wrong?
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((400, 300))
pygame.display.set_caption('Hello World!')
screen =pygame.display.set_mode((600,400))
ball = pygame.image.load("homers.png")
ball = pygame.transform.scale(ball,(225,200))
x=200
y=100
left = True
up = True
color = 67,143,218
def text_objects(text,font):
text_surface = font.render(text,True, color)
return text_surface,text_surface.get_rect()
def message_display(text,x,y,z):
largeText = pygame.font.Font('freesansbold.ttf',z)
TextSurf,TextRect = text_objects(text,largeText)
TextRect.center = (x,y)
screen.blit(TextSurf,TextRect)
def hi(x,y,p,z):
message_display(x,y,p,z)
count = 0
message_count = str(count)
while True: # main game loop
screen.fill((180,0,0))
screen.blit(ball,(x,y))
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
hi(message_count,x,y,140)
hi("How Many Times Has Homer Hit His Head?",300,200,20)
if event.type == pygame.MOUSEBUTTONDOWN:
# Set the x, y postions of the mouse click
if ball.get_rect().collidepoint(x, y):
count = count+1
if event.type == pygame.MOUSEBUTTONUP:
0
if left == True:
x=x-10
if x == -100:
left =False
if left == False:
x=x+10
if x == 450:
left = True
if up == True:
y=y-10
if y == -20:
up =False
count = count+1
message_count = str(count)
hi(message_count,x,y,140)
if up == False:
y=y+10
if y== 230:
up =True
pygame.display.update()
You have to fix the indentation of your code:
while True: # main game loop
screen.fill((180,0,0))
screen.blit(ball,(x,y))
hi(message_count,x,y,140)
hi("How Many Times Has Homer Hit His Head?",300,200,20)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# this has to be part of the for loop
if event.type == pygame.MOUSEBUTTONDOWN:
if ball.get_rect().collidepoint(x, y):
count = count+1
...

function calls in python (pygame)

im trying to split my code into functions and i want to input my own values for x and y. so the character can move from the inputed values. When i try to do this from the function call, nothing happens.
Any suggestions?
import pygame, sys
from pygame.locals import *
pygame.init()
width,height=(842,595)
screen = pygame.display.set_mode((width,height),0,32)
pygame.display.set_caption("game")
man = pygame.image.load("man.png")
target = pygame.image.load("star.png")
#setting a background image
bgimage= pygame.image.load("background.jpg")
##image for the jupiter object
another_target = pygame.image.load("jupiter.gif")
x = 100
y = height-300
another_targetx = 400
another_targety = 500
#allows movement whilst holding down key.
clock= pygame.time.Clock()
def move(x,y):
movingX =0
movingY =0
speedX =0
speedY=0
while True:
pygame.display.update()
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
elif event.type==KEYDOWN:
if event.key ==K_LEFT:
x-=5
elif event.key==K_RIGHT:
x+=5
elif event.key==K_UP:
y-=5
elif event.key==K_DOWN:
y+=5
time_Passed=clock.tick(25)
time_elapsed_seconds=time_Passed/1000.0
distanceX = time_elapsed_seconds*speedX
movingX+=distanceX
distanceY=time_elapsed_seconds*speedY
movingY+=distanceY
x+=movingX
y+=movingY
clock.tick(50)
pygame.display.update()
move(x,y)
screen.blit(bgimage,(0,0))
screen.blit(man, (x,y))
screen.blit( another_target,( another_targetx, another_targety))
screen.blit(target,(200,400))
pygame.display.update()
You have an infinite loop within the command move(x, y). The stuff on the outside of this loop which updates the screen is never reached, so nothing ever appears to happen. Try putting everything after the command definition into the while True loop inside the command.

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