python - Scrolling camera -
i've been tinkering scrolling camera follows player around , have got follow player. problem moves slower player , because of player wont stay in middle of screen.
i believe problem in offset (camerax) , have tried few different values haven't found work.
code:
import pygame, sys, time, random, math pygame.locals import * backgroundcolor = (255, 255, 255) windoww = 800 windowh = 600 playerw = 66 playerh = 22 fps = 60 movespeed = 3 yaccel = 0.13 gravity = 2 blocksize = 30 pygame.init() screen = pygame.display.set_mode((windoww, windowh), 0, 32) mainclock = pygame.time.clock() testlevel = [ (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,), (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,)] def createblock(length, height, color): tmpblock = pygame.surface((length, height)) tmpblock.fill(color) tmpblock.convert() return tmpblock def terminate(): # used shut down software pygame.quit() sys.exit() def add_level(lvl, bsize): # creates level based on map (lvl) , size of blocks blist = [] # list of every block blistdisp = [] # list of every block display btypelist = [] # list corresponding type of block(wall, air, etc.) y in range(len(lvl)): x in range(len(lvl[0])): if lvl[y][x] == 0: # if block type on lvl[y][x] '0', write "air" down in type list btypelist.append("air") elif lvl[y][x] == 1: # if block type on lvl[y][x] '1', write "wall" down in type list btypelist.append("solid") blist.append(pygame.rect((bsize * x), (bsize * y), bsize, bsize)) #append every block registered blistdisp.append(pygame.rect((bsize * x), (bsize * y), bsize, bsize)) #append every block display registered return blist, blistdisp, btypelist player = pygame.rect((windoww/2), (windowh - blocksize*3), playerw, playerh) wallblock = createblock(blocksize, blocksize,(20,0,50)) lasttime = pygame.time.get_ticks() isgrounded = false vx = 0 vy = 0 alllevels = [testlevel] # list containing lvls(only 1 now) maxlevel = len(alllevels) # checks level last currlevel = alllevels[0] # current level(start first lvl) blocklist, blocklistdisp, blocktypelist = add_level(currlevel, blocksize) # list every block , list blocks types thrusters = true jumping = false falling = true while true: """collision""" collision = false in range(len(blocktypelist)): if blocktypelist[i] == "solid": if player.colliderect(blocklist[i]): collision = true if vx > 0 , not falling: player.right = blocklistdisp[i].left vx = 0 print('collide right') if vx < 0 , not falling: player.left = blocklistdisp[i].right vx = 0 print('collide left') if vy > 0: player.bottom = blocklistdisp[i].top isgrounded = true falling = false vy = 0 print('collide bottom') if vy < 0: player.top = blocklistdisp[i].bottom vy = 0 print('collide top') else: player.bottom += 1 if player.colliderect(blocklist[i]): collision = true #isgrounded = true #falling = false player.bottom -= 1 if not collision: falling = true isgrounded = false # input pressedkeys = pygame.key.get_pressed() # checks keys being pressed timediff = pygame.time.get_ticks() - lasttime # calculates time difference lasttime += timediff # last time checked reset current time # shut-down if esc-key pressed or window "crossed down" event in pygame.event.get(): if event.type == quit or event.type == keydown , event.key == k_escape: terminate() """x-axis control""" if pressedkeys[ord('a')]: vx = -movespeed if pressedkeys[ord('d')]: vx = movespeed if not pressedkeys[ord('d')] , not pressedkeys[ord('a')]: vx = 0 """y-axis control""" # controls jumping if pressedkeys[ord('w')] , thrusters == true: vy -= yaccel * timediff; # accelerate along y-xis when "jumping", not above/below max speed if vy <= -4: vy = -4 isgrounded = false # airborne jumping = true # jumping if event.type == keyup: # if let go of "jump"-button, stop jumping if event.key == ord('w') , vy < 0 , not isgrounded: jumping = false falling = true player.x += vx player.y += vy camerax = player.x - windoww/2 # gravity if not isgrounded or falling: vy += 0.3 if vy > 80: vy = 80 screen.fill(backgroundcolor) in range(len(blocktypelist)): if blocktypelist[i] == "solid": screen.blit(wallblock, (blocklistdisp[i].x-camerax, blocklistdisp[i].y)) #blit wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player) pygame.display.update() mainclock.tick(fps)
you don't apply camera-offset player itself, wallblocks.
so change
pygame.draw.rect(screen, (0, 0, 0), player)
to
pygame.draw.rect(screen, (0, 0, 0), player.move(-camerax, 0))
some more notes:
using 3 lists (blocklist
, blocklistdisp
, blocktypelist
) keep track of level way complex, use single list :-)
change add_level
to:
# use dict keep track of possible level blocks, adding new ones becomes simple types = {0: "air", 1: "solid"} def add_level(lvl, bsize): # creates level based on map (lvl) , size of blocks y in range(len(lvl)): x in range(len(lvl[0])): # no more if/elif yield types[lvl[y][x]], pygame.rect((bsize * x), (bsize * y), bsize, bsize)
your lists to:
blocks = list(add_level(currlevel, blocksize)) # single list holds type , rect each block of level
then collision detection can this:
while true: """collision""" collision = false type, rect in blocks: # list contains tuple of type, rect if type == "solid": if player.colliderect(rect): collision = true if vx > 0 , not falling: player.right = rect.left # can use rect directly instead of accesing other lists vx = 0 print('collide right') ...
also, drawing code becomes simpler:
for type, rect in blocks: if type == "solid": screen.blit(wallblock, rect.move(-camerax, 0)) #blit wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player.move(-camerax, 0))
in long run, may want use class instead of tuple, that's topic.