pygame: Stopping movement behind line - python
I am attempting to create a game that lets a block move "jump" and land on a platform above it. Then, jump again to the next platform.
Unfortunately, my code currently just stops when the block touches the bottom of the platform and moves no further. I am unsure why as i believe it should only stop when the bottom of the block hits the line
Specifically am looking at this bit of code, but full code below for context:
#the floor landing code
def hasJumperLanded(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
if isFloorTouching(a.bottom, b):
return True
def isFloorTouching(y, rect):
if (y > rect.top) and (y < rect.bottom):
return True
else:
return False
snip
#stop when land on floor
for n in range(len(floors)):
if (hasJumperLanded(j['rect'], floors[n]['line'])):
j['jump'] = STILL
Full code context:
import pygame, sys, time
from pygame.locals import *
#the deadzone collision code
def doRectsOverlap(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
if ((isPointInsideRect(a.left, a.top, b)) or
(isPointInsideRect(a.left, a.bottom, b)) or
(isPointInsideRect(a.right, a.top, b)) or
(isPointInsideRect(a.right, a.bottom, b))):
return True
return False
def isPointInsideRect(x, y, rect):
if (x > rect.left) and (x < rect.right) and (y > rect.top) and (y < rect.bottom):
return True
else:
return False
#the floor landing code
def hasJumperLanded(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
if isFloorTouching(a.bottom, b):
return True
def isFloorTouching(y, rect):
if (y > rect.top) and (y < rect.bottom):
return True
else:
return False
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
WINDOWWIDTH = 480
WINDOWHEIGHT = 800
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Jumper')
#Directions
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2
STILL = 5
#blocks location for jumping
#BLOCKLOCY = 700
#Binary for stopping movement
#STOPPER = 0
MOVESPEED = 1
# set up the colors
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
j = {'rect':pygame.Rect(240, 700, 20, 20), 'color':GREEN, 'dir':LEFT, 'jump':STILL}
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
# run the game loop
while True:
# check for the QUIT event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# draw the black background onto the surface
windowSurface.fill(BLACK)
# This way or that way. Speed Code
if j['dir'] == LEFT:
j['rect'].left -= MOVESPEED
if j['dir'] == RIGHT:
j['rect'].left += MOVESPEED
#JUST JUMP ALREADY!
if j['jump'] == UP:
j['rect'].bottom -= MOVESPEED
#BLOCKLOCY -= MOVESPEED
#Bouce when side hitting
if j['rect'].left < 0:
j['dir'] = RIGHT
if j['rect'].left > WINDOWWIDTH-j['rect'].width:
j['dir'] = LEFT
#Press to Jump
if event.type == KEYDOWN:
if event.key == K_SPACE:
j['jump'] = UP
#stop when land on floor
for n in range(len(floors)):
if (hasJumperLanded(j['rect'], floors[n]['line'])):
j['jump'] = STILL
#Floor controll code for moving level - not working currently
for f in floors:
#if f['dir'] == DOWN:
# f['line'].y += MOVESPEED
# if event.type == KEYDOWN:
# if event.key == K_SPACE:
# f['dir'] = DOWN
# if f['line'].top == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
#if f['line'].bottom == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
# draw the block onto the surface
pygame.draw.rect(windowSurface, j['color'], j['rect'])
pygame.draw.rect(windowSurface, f['color'], f['line'])
# draw the window onto the screen
pygame.display.update()
mainClock.tick(1000)
#the floor landing code
def hasJumperLanded(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]: ## **
if isFloorTouching(a.bottom, b):
return True
Take a look at the line I marked in this snippet.
Here You are checking the rects to collide both ways.
So you loose the meaning of which one is the floor and which one is moving.
If you just check (rect1, rect2) you will see the difference.
--
EDIT:
Check this out
def hasJumperLanded(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
if isFloorTouching(rect1, rect2):
return True
def isFloorTouching(y, rect):
if (y.bottom > rect.top) and (y.bottom < rect.bottom):
return True
else:
return False
It is more logical to handle the meaning of the floor inside the isFloorTouching() function.
Related
How to delete a single pygame drawing from the screen?
When the big circle touches the little circles I want the little circle that it touched to disappear from the screen. However, I can't figure out how exactly you delete an individual drawing in pygame. How do I fix this issue? does pygame have this feature built-in? from pygame import * import random as rd import math as m init() screen = display.set_mode((800, 600)) p_1_x = 200 p_1_y = 200 p_1_change_x = 0 p_1_change_y = 0 def p_1(x, y): player_1 = draw.circle(screen, (0, 0, 0), (x, y), 15) def pick_up(x, y, xx, yy): distance = m.sqrt(m.pow(xx - x, 2) + m.pow(yy - y, 2)) if distance < 19: # I think the code to delete should go here pass dots = [] locations = [] for i in range(5): x = rd.randint(100, 700) y = rd.randint(100, 500) locations.append((x, y)) while True: screen.fill((255, 255, 255)) for events in event.get(): if events.type == QUIT: quit() if events.type == KEYDOWN: if events.key == K_RIGHT: p_1_change_x = 1 if events.key == K_LEFT: p_1_change_x = -1 if events.key == K_UP: p_1_change_y += 1 if events.key == K_DOWN: p_1_change_y -= 1 if events.type == KEYUP: if events.key == K_RIGHT or K_LEFT or K_UP or K_DOWN: p_1_change_x = 0 p_1_change_y = 0 p_1_x += p_1_change_x p_1_y -= p_1_change_y for i, locate in enumerate(locations): dot = draw.circle(screen, (0, 0, 0), locate, 5) dots.append(dot) for l in enumerate(locate): pick_up(p_1_x, p_1_y, locate[0], locate[1]) p_1(p_1_x, p_1_y) display.update()
Your code was so messy and hard to maintain, first I made 2 classes for Balls & Dots. I detect collision by pygame.Rect.colliderect, first I make 2 rectangle then I check the collision like this: def pick_up(ball, dot): ball_rect = Rect( ball.x - ball.SIZE , ball.y - ball.SIZE , ball.SIZE*2, ball.SIZE*2) dot_rect = Rect( dot.x - dot.SIZE , dot.y - dot.SIZE , dot.SIZE*2, dot.SIZE*2) if ball_rect.colliderect(dot_rect): return True return False If collision detects I remove it from dots array in the while loop: for dot in dots: if pick_up(ball, dot): # if dot in range ball dots.remove(dot) dot.draw() Here is the whole source: from pygame import * import random as rd SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 NUMBER_OF_DOTS = 5 class Ball(): SIZE = 15 def __init__(self, x, y): self.x = x self.y = y def draw(self): draw.circle(screen, (0, 0, 0), (self.x, self.y), Ball.SIZE) def move(self, vx, vy): self.x += vx self.y += vy class Dot(): SIZE = 5 def __init__(self, x, y): self.x = x self.y = y def draw(self): draw.circle(screen, (0, 0, 0), (self.x, self.y), Dot.SIZE) def pick_up(ball, dot): ball_rect = Rect( ball.x - ball.SIZE , ball.y - ball.SIZE , ball.SIZE*2, ball.SIZE*2) dot_rect = Rect( dot.x - dot.SIZE , dot.y - dot.SIZE , dot.SIZE*2, dot.SIZE*2) if ball_rect.colliderect(dot_rect): return True return False init() screen = display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) dots = [] ball = Ball(200,200) # generate dots for i in range(NUMBER_OF_DOTS): x = rd.randint(100, 700) y = rd.randint(100, 500) dots.append(Dot(x,y)) # the main game loop while True: screen.fill((255, 255, 255)) keys=key.get_pressed() for events in event.get(): keys=key.get_pressed() if events.type == QUIT: quit() if keys[K_RIGHT]: ball.move(+1,0) if keys[K_LEFT]: ball.move(-1,0) if keys[K_UP]: ball.move(0,-1) if keys[K_DOWN]: ball.move(0,+1) for dot in dots: dot.draw() if pick_up(ball, dot): dots.remove(dot) ball.draw() display.update() time.delay(1) # Speed down Update1: PyGame Rectangle Collision http://www.pygame.org/docs/ref/rect.html#pygame.Rect.colliderect Update2: I make a repo in the github and did some changes, Dots are colorful, new dot gets random color and the ball gets bigger whenever eats a dot. https://github.com/peymanmajidi/Ball-And-Dots-Game__Pygame
The code should delete it from the locations list so that it's not re-drawn in the future. You clear the screen each frame, so clearing + not-redrawing is "deleting". Say you modified pick_up() to simply return True or False: def pick_up(x, y, xx, yy): result = False distance = m.sqrt(m.pow(xx - x, 2) + m.pow(yy - y, 2)) if distance < 19: result = True # It was picked return result Then as you iterate through the locations list drawing & checking for being picked, save the index of the picked circles, then remove them from the locations in a second step. Using the 2-step form means you don't have to worry about accidentally skipping items if you delete from the list as you iterate over it. p_1_x += p_1_change_x p_1_y -= p_1_change_y picked_up = [] # empty list to hold "picked" items for i, locate in enumerate(locations): dot = draw.circle(screen, (0, 0, 0), locate, 5) dots.append(dot) for l in enumerate(locate): if ( pick_up(p_1_x, p_1_y, locate[0], locate[1]) ): picked_up.append( i ) # save the index of anything "picked" # remove any picked-up circles from the list for index in sorted( picked_up, reverse=True ): # start with the highest index first print( "Removing circle from location[%d]" % ( index ) ) # DEBUG del( locations[ index ] )
Bouncing Ball doesn't come back pygame
import pygame pygame.init() width = 400 hight = 600 screen = pygame.display.set_mode((width, hight)) pygame.display.set_caption("Engine") dot = pygame.image.load("KreisSchwarz.png") clock = pygame.time.Clock() running = True WHITE = (255, 255, 255) # Set (x, y) for Dot def updateDot(x, y): screen.blit(dot, (x, y)) # Display Dot at (x, y) def update(fps=30): screen.fill(WHITE) updateDot(x, y) pygame.display.flip() return clock.tick(fps) # Quit if User closes the window def evHandler(): for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() running = False yKoords = [] (x, y) = (300, 200) t = 1 # time variable a = 2 # acceleration constant tol = 40 # tolerance i = 0 # just some iterator # MAIN LOOP while running: evHandler() update() y += a * (t ^ 2) t += 1 yKoords.append(int(y)) i += 1 if (y < (hight + tol)) and (y > (hight - tol)): y = 580 yKoords.reverse() update() for q in range(i): evHandler() y = yKoords[q] update() if q == i - 1: # Because i didn't write the Part for the Dot coming back down running = False This is my Code for a Ball accelerating down and then jumping back up. My Problem is, that the code works fine until the if statement. There the Programm just displays the Ball at the last position in yKoords and waits until the for loop finishes. If i remove the for loop the Ball gets displayed at y=580 and stops but thats fine. Please help i have no idea whats wrong about this.
Don't do a separate process loop in the main loop. It is sufficient to invert the direction, when the ball bounce on the ground (abs(y - hight)) or the ball reaches the top (t == 0). direction = 1 while running: evHandler() update() y += (a * (t ^ 2)) * direction t += direction if abs(y - hight) < tol: y = 580 t -= 1 direction *= -1 elif t == 0: direction *= -1
Pygame: colliding rectangles with other rectangles in the same list
I have a list of 10 drawn rectangles (referenced as cubes in my script) that are affected by gravity. I made a simple collision system for them to stop when they hit the ground. How can I make it so when 2 cubes collide they stop falling like they do with the ground? import pygame import time import random pygame.init() clock = pygame.time.Clock() wnx = 800 wny = 600 black = (0,0,0) grey = (75,75,75) white = (255,255,255) orange = (255,100,30) wn = pygame.display.set_mode((wnx, wny)) wn.fill(white) def cube(cx,cy,cw,ch): pygame.draw.rect(wn, orange, [cx, cy, cw, ch]) def floor(fx,fy,fw,fh): pygame.draw.rect(wn, grey, [fx, fy, fw, fh]) def main(): floory = 550 number = 30 cubex = [0] * number cubey = [0] * number cubew = 10 cubeh = 10 for i in range(len(cubex)): cubex[i] = (random.randrange(0, 80)*10) cubey[i] = (random.randrange(2, 5)*10) gravity = -10 exit = False while not exit: for event in pygame.event.get(): if event.type == pygame.QUIT: exit = True for i in range(len(cubex)): #i want to check here if it collides with an other cube if not (cubey[i] + 10) >= floory: cubey[i] -= gravity wn.fill(white) floor(0,floory,800,50) for i in range(len(cubex)): cube(cubex[i], cubey[i], cubew, cubeh) pygame.display.update() clock.tick(5) main() pygame.quit() quit()
Use pygame.Rect.colliderect to check if to rectangles are intersecting. Create an rectangle (pygame.Rect) which defines the next position (area) of the cube: cubeR = pygame.Rect(cubex[i], cubey[i] + 10, cubew, cubeh) Find all intersecting rectangles cl = [j for j in range(len(cubey)) if j != i and cubeR.colliderect(pygame.Rect(cubex[j], cubey[j], cubew, cubeh))] And don't move (let further "fall") the cube if there is any() collision: if not any(cl): # [...] The check may look like this: for i in range(len(cubex)): cubeR = pygame.Rect(cubex[i], cubey[i] + 10, cubew, cubeh) cisect = [j for j in range(len(cubey)) if j != i and cubeR.colliderect(pygame.Rect(cubex[j], cubey[j], cubew, cubeh))] if not any(cisect) and not (cubey[i] + 10) >= floory: cubey[i] -= gravity Note, since all the cubes are aligned to an 10*10 raster, it is sufficient to check if the origins of the cubes are equal: for i in range(len(cubex)): cisect = [j for j in range(len(cubey)) if j != i and cubex[i] == cubex[j] and cubey[i]+10 == cubey[j]] if not any(cisect) and not (cubey[i] + 10) >= floory: cubey[i] -= gravity
Python Pygame randomly draw non overlapping circles
Im very new to python and seem to be missing something. I want to randomly draw circles on a pygame display but only if the circles don't overlap each other. I believe I must find the distance between all circle centers and only draw it if the distance is bigger than circle radius * 2. I've tried many different things but all without success, I always get the same result - circles drawn overlapping. #!/usr/bin/env python import pygame, random, math red = (255, 0, 0) width = 800 height = 600 circle_num = 10 tick = 2 speed = 5 pygame.init() screen = pygame.display.set_mode((width, height)) class circle(): def __init__(self): self.x = random.randint(0,width) self.y = random.randint(0,height) self.r = 100 def new(self): pygame.draw.circle(screen, red, (self.x,self.y), self.r, tick) c = [] for i in range(circle_num): c.append('c'+str(i)) c[i] = circle() for j in range(len(c)): dist = int(math.hypot(c[i].x - c[j].x, c[i].y - c[j].y)) if dist > int(c[i].r*2 + c[j].r*2): c[j].new() pygame.display.update() else: continue while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit()
You did not check against all other circles. I added a variable shouldprint which gets set to false if any other circle is too close. import pygame, random, math red = (255, 0, 0) width = 800 height = 600 circle_num = 20 tick = 2 speed = 5 pygame.init() screen = pygame.display.set_mode((width, height)) class circle(): def __init__(self): self.x = random.randint(0,width) self.y = random.randint(0,height) self.r = 100 def new(self): pygame.draw.circle(screen, red, (self.x,self.y), self.r, tick) c = [] for i in range(circle_num): c.append('c'+str(i)) c[i] = circle() shouldprint = True for j in range(len(c)): if i != j: dist = int(math.hypot(c[i].x - c[j].x, c[i].y - c[j].y)) if dist < int(c[i].r*2): shouldprint = False if shouldprint: c[i].new() pygame.display.update() while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() quit()
The for loop has been changed to a while loop. It will keep trying to generate circles until the target number is reached. A circle is first generated. Then, it checks if it intersects with any existing circle using the formula from this answer. It iterates through every existing circle (store in the list circles) and performs the check using the formula. any() returns True if the formula evaluates to True for any iteration. If it's True, it means it found an intersection. Thus, it continues to the next iteration to try again with a new circle. circles = [] while len(circles) < circle_num: new = circle() if any(pow(c.r - new.r, 2) <= pow(c.x - new.x, 2) + pow(c.y - new.y, 2) <= pow(c.r + new.r, 2) for c in circles): continue circles.append(new) new.new() pygame.display.update()
Scrolling camera
I've been tinkering with a scrolling camera that follows the player around and have got it to follow the player. The problem is that it moves slower than the player and because of this the player wont stay in the middle of the screen. I believe the problem is in the offset (cameraX) and have tried a few different values but haven't found any that work. Code: import pygame, sys, time, random, math from 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 to shut down the software pygame.quit() sys.exit() def add_level(lvl, bSize): # Creates the level based on a map (lvl) and the size of blocks bList = [] # List of every block bListDisp = [] # List of every block to display bTypeList = [] # List with corresponding type of block(wall, air, etc.) for y in range(len(lvl)): for x in range(len(lvl[0])): if lvl[y][x] == 0: # If the block type on lvl[y][x] is '0', write "air" down in the type list bTypeList.append("air") elif lvl[y][x] == 1: # If the block type on lvl[y][x] is '1', write "wall" down in the type list bTypeList.append("solid") bList.append(pygame.Rect((bSize * x), (bSize * y), bSize, bSize)) #Append every block that is registered bListDisp.append(pygame.Rect((bSize * x), (bSize * y), bSize, bSize)) #Append every block to display that is 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] # A list containing all lvls(only one for now) maxLevel = len(allLevels) # Checks which level is the last currLevel = allLevels[0] # Current level(start with the first lvl) blockList, blockListDisp, blockTypeList = add_level(currLevel, BLOCKSIZE) # A list with every block and another list with the blocks types thrusters = True jumping = False falling = True while True: """COLLISION""" collision = False for i in range(len(blockTypeList)): if blockTypeList[i] == "solid": if player.colliderect(blockList[i]): collision = True if vx > 0 and not falling: player.right = blockListDisp[i].left vx = 0 print('Collide Right') if vx < 0 and 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 which keys are being pressed timeDiff = pygame.time.get_ticks() - lastTime # Calculates time difference lastTime += timeDiff # Last time checked reset to current time # Shut-down if the ESC-key is pressed or the window is "crossed down" for event in pygame.event.get(): if event.type == QUIT or event.type == KEYDOWN and 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')] and not pressedKeys[ord('a')]: vx = 0 """Y-axis control""" # Controls for jumping if pressedKeys[ord('w')] and thrusters == True: vy -= YACCEL * timeDiff; # Accelerate along the y-xis when "jumping", but not above/below max speed if vy <= -4: vy = -4 isGrounded = False # You are airborne jumping = True # You are jumping if event.type == KEYUP: # If you let go of the "jump"-button, stop jumping if event.key == ord('w') and vy < 0 and 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) for i in range(len(blockTypeList)): if blockTypeList[i] == "solid": screen.blit(wallblock, (blockListDisp[i].x-cameraX, blockListDisp[i].y)) #blit the wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player) pygame.display.update() mainClock.tick(FPS)
You don't apply the camera-offset to the player itself, only to the 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 three lists (blockList, blockListDisp, blockTypeList) to keep track of your level is way to complex, use a single list :-) Change your add_level to: # use a dict to keep track of possible level blocks, so adding new ones becomes simple types = {0: "air", 1: "solid"} def add_level(lvl, bSize): # Creates the level based on a map (lvl) and the size of blocks for y in range(len(lvl)): for 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)) # a single list which holds the type and rect for each block of the level Then your collision detection can look like this: while True: """COLLISION""" collision = False for type, rect in blocks: # list contains a tuple of type, rect if type == "solid": if player.colliderect(rect): collision = True if vx > 0 and not falling: player.right = rect.left # now you can always use the rect directly instead of accesing other lists vx = 0 print('Collide Right') ... Also, the drawing code becomes simpler: for type, rect in blocks: if type == "solid": screen.blit(wallblock, rect.move(-cameraX, 0)) #blit the wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player.move(-cameraX, 0)) In the long run, you may want to use a class instead of a tuple, but that's another topic.