How to Scroll the Background Surface in Pygame

How to scroll the background surface in PyGame?

pygame.Surface.scroll() doesn't do what you expect. It doesn't seamless roll the surface. See the documentation:

scroll() Shift the surface image in place

[...] Areas of the surface that are not overwritten retain their original pixel values. [...]

You've to write your own scroll functions, which place the part of the surface, which was shifted out, at the other side of thee surface.

e.g. write 2 functions (scrollX and scrollY), which can roll along an axis:

def scrollX(screenSurf, offsetX):
width, height = screenSurf.get_size()
copySurf = screenSurf.copy()
screenSurf.blit(copySurf, (offsetX, 0))
if offsetX < 0:
screenSurf.blit(copySurf, (width + offsetX, 0), (0, 0, -offsetX, height))
else:
screenSurf.blit(copySurf, (0, 0), (width - offsetX, 0, offsetX, height))
def scrollY(screenSurf, offsetY):
width, height = screenSurf.get_size()
copySurf = screenSurf.copy()
screenSurf.blit(copySurf, (0, offsetY))
if offsetY < 0:
screenSurf.blit(copySurf, (0, height + offsetY), (0, 0, width, -offsetY))
else:
screenSurf.blit(copySurf, (0, 0), (0, height - offsetY, width, offsetY))
if pressed[pygame.K_UP]:
scrollY(screen, 2)
elif pressed[pygame.K_DOWN]:
scrollY(screen, -2)
elif pressed[pygame.K_LEFT]:
scrollX(screen, 2)
elif pressed[pygame.K_RIGHT]:
scrollX(screen, -2)

Sample Image

How to use pygame.surface.scroll()?

EDIT: Your image and screen variables are backwards. That is also causing you some confusion I'm sure..

Your problem may is that you are trying to scroll an all black background. It is probably scrolling, and you just don't know it because the white box you used blit() to draw on the screen is stationary.

Try using something you can see scroll, like an image file. If you wanna move the white box, you can add a counter as a speed variable. Read this, then run it.

import pygame
from pygame.locals import*
screen=pygame.display.set_mode((1250,720))
pygame.init()
clock=pygame.time.Clock()
boxx=200
boxy=200
image = pygame.Surface([20,20]).convert_alpha()
image.fill((255,255,255))
speed = 5 # larger values will move objects faster
while True :
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type==pygame.QUIT :
pygame.quit()
quit()
image.scroll(10,10)
# I did modulus 720, the surface width, so it doesn't go off screen
screen.blit(image,((boxx + speed) % 720, (boxy + speed) % 720))
pygame.display.update()
clock.tick(60)

I can't say for sure the scroll function is working or not, learn to use an image as your background so you can see it moving first.

How do you make a scrolling background in pygame?

The background moves downwards, so the condition has to be:

if BGY > BG.get_height():
BGY = -BG.get_height()
if BGY2 > BG.get_height():
BGY2 = -BG.get_height()

If the back ground has to move upwards, then you have to decrement BGY and BGY2:

BGY -= 2.5
BGY2 -= 2.5

if BGY < BG.get_height() * -1:
BGY = BG.get_height()
if BGY2 < BG.get_height() * -1:
BGY2 = BG.get_height()

How do I make my background scroll as my Sprite moves left and right? Pygame

Here's how I would approach this...

  1. set up a scrolling background as in the tutorial and make sure you can get that working OK by moving the background back & forth instead of the player (just freeze the player's x coordinate in the center and move the background with your left/right keys.

  2. Add some constants into your settings for an edge buffer (the number of x-increments you want the player to avoid the boundaries by

  3. AFTER you get the key input (left or right) set up a conditional statement. For this, you will have to access the player's x-coordinate and compare it to the buffer. Well, either 0+buffer or width-buffer actually and then based on those cases either move the player or the background. See if you can get that working.

  4. Then, you will realize that when you move the background, you are moving the frame of reference for everything else, meaning things like the fireball, so if you are moving the background left or right, you will need to apply those updates to the other objects as well so it looks correct.

If yer stuck, make those updates to code above & message me back in a comment.

How can I make a scrolling background in python with pygame?

Some things first:

  • fix your indentation
  • your ship function is practically useless
  • use the Rect to handle moving
  • your real problem is that your code never reaches pygame.display.update() because of your second while loop

So, to make an endless scrolling background, and easy way is to do the following:

Blit your background image twice, once at position y, and once at y + image_width (replace y with x of you want). Then, every iteration of your mainloop, you can substract from y to create the movement. Once an image moved it's entire height, reset y to the starting value


Here's a complete example, showing a scrolling background (and how to use sprites, groups, vectors and rects):

import pygame
pygame.init()
SCREEN = pygame.display.set_mode((300, 300))

move_map = {pygame.K_w: pygame.math.Vector2( 0, -1),
pygame.K_s: pygame.math.Vector2( 0, 1),
pygame.K_a: pygame.math.Vector2(-1, 0),
pygame.K_d: pygame.math.Vector2( 1, 0)}

class Actor(pygame.sprite.Sprite):
def __init__(self, group, color, pos, size=(30, 30)):
self.image = pygame.Surface(size)
self.image.fill(color)
self.rect = self.image.get_rect(center=pos)
pygame.sprite.Sprite.__init__(self, group)

class Bullet(Actor):
def __init__(self, *args):
Actor.__init__(self, *args)
self.speed = 10

def update(self):
self.rect.move_ip(self.speed, 0)
if not SCREEN.get_rect().colliderect(self.rect):
self.kill()

class Player(Actor):
def __init__(self, *args):
self._layer = 4
Actor.__init__(self, *args)
self.speed = 4
self.timeout = 0

def update(self):
p = pygame.key.get_pressed()
move_vector = pygame.math.Vector2(0, 0)
for v in [move_map[key] for key in move_map if p[key]]:
move_vector += v
if move_vector:
self.rect.move_ip(*move_vector.normalize() * self.speed)
self.rect.clamp_ip(SCREEN.get_rect())

if self.timeout :
self.timeout -= 1
if p[pygame.K_SPACE] and not self.timeout:
Bullet(self.groups()[0], (130, 200, 77), self.rect.center, (10, 3))
self.timeout = 5

class Background(pygame.sprite.Sprite):
def __init__(self, number, *args):
self.image = pygame.image.load('back.jpg').convert()
self.rect = self.image.get_rect()
self._layer = -10
pygame.sprite.Sprite.__init__(self, *args)
self.moved = 0
self.number = number
self.rect.x = self.rect.width * self.number

def update(self):
self.rect.move_ip(-1, 0)
self.moved += 1

if self.moved >= self.rect.width:
self.rect.x = self.rect.width * self.number
self.moved = 0

group = pygame.sprite.LayeredUpdates()
Player(group, (255, 255, 255), (100, 100))
Background(0, group)
Background(1, group)

clock = pygame.time.Clock()
run = True
while run:
for e in pygame.event.get():
if e.type ==pygame.QUIT:
run = False
SCREEN.fill((0,0,0))
group.update()
group.draw(SCREEN)
pygame.display.flip()
clock.tick(60)

For testing this, you can use this image (save it as back.jpg):

Sample Image



Related Topics



Leave a reply



Submit