Python's list object do not allow index value change - python
I'm creating my first game using Python and Pygame. It consists on objects falling to the ground and an object controlled by the player catching them.
However, It gives me an Exception when the falling object hits the ground:
Traceback (most recent call last):
File "/home/me/Chest/game.py", line 79, in <module>
resetShirtPosition()
File "/home/me/Chest/game.py", line 35, in resetShirtPosition
shirtPosition[0] = random.randint(0, DISPLAY_WIDTH - shirt_size[0])
TypeError: 'tuple' object does not support item assignment
Seems like it doesn't allow the vector to change by index. Which I find odd because I'm not assigning shirtPosition with a tuple but with a list. Besides that I'm changing the chestPosition the same way and it moves without crashing.
Here is my code:
import pygame, random, os
pygame.init()
DISPLAY_WIDTH, DISPLAY_HEIGHT = 1600, 900
clock = pygame.time.Clock()
gamedisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
chest_imag = pygame.image.load(os.path.join("catcher.png"))
shirt_red = pygame.image.load(os.path.join("shirt_red.png"))
background = pygame.image.load(os.path.join("background.png"))
shirt_blue = pygame.image.load(os.path.join("shirt_blue.png"))
shirt_green = pygame.image.load(os.path.join("shirt_green.png"))
shirt = shirt_blue
chest_size = chest_imag.get_size()
chestPosition = [DISPLAY_WIDTH / 2, DISPLAY_HEIGHT - chest_size[1]]
shirt_blue_size = shirt_blue.get_size()
shirt_size = shirt_blue_size
shirtPosition = [random.randint(0, DISPLAY_WIDTH - shirt_size[0]), 0]
dX, dY = 0, 20
score = 0
fallWidth = fallHeight = 100
COLLISION_LEVEL_LINE = DISPLAY_HEIGHT - chest_size[1]
onGame = True
collide = False
# **************** Exception happens here *******************
def resetShirtPosition():
shirtPosition[0] = random.randint(0, DISPLAY_WIDTH - shirt_size[0])
shirtPosition[1] = 0
def hitCollisionLevelLine():
return (shirtPosition[1] + shirt_size[1]) >= COLLISION_LEVEL_LINE
def hitGround():
return (shirtPosition[1] + shirt_size[1]) >= DISPLAY_HEIGHT
def hitHorizontalEdge():
willTouchLeftEdge = (chest_size[0] + dX) < 0
willTouchRightEdge = (chest_size[0] + dX) > (DISPLAY_WIDTH - chest_size[0])
return willTouchLeftEdge or willTouchRightEdge
def collides():
touchFromLeft = shirtPosition[0] > (chestPosition[0] - shirt_size[0])
touchFromRight = shirtPosition[0] < (chestPosition[0] + chest_size[0])
return touchFromLeft and touchFromRight
while onGame:
clock.tick(60)
# action
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
dX = -20
elif event.key == pygame.K_d:
dX = 20
elif event.type == pygame.KEYUP:
dX = 0
elif event.type == pygame.QUIT:
onGame = false
# logic
if hitCollisionLevelLine():
hasCollided = collides()
if hasCollided:
collide = False
score = score + 1
print score
resetShirtPosition()
if hitGround():
resetShirtPosition()
if hitHorizontalEdge():
dX = 0
# update positions and draw
chestPosition = (chestPosition[0] + dX, chestPosition[1])
shirtPosition = (shirtPosition[0], shirtPosition[1] + dY)
gamedisplay.blit(background , (0, 0))
gamedisplay.blit(shirt_blue, shirtPosition)
gamedisplay.blit(chest_imag, chestPosition)
pygame.display.flip()
I've posted all my code because I'd also like if you could hand me some tips to improve it, from code writting to improve-performance tricks. For example, I'm thinking about putting my images in a Dictionary and get them by its key (name). Thank you.
On the following line :
shirtPosition = (shirtPosition[0], shirtPosition[1] + dY)
you have reassigned shirtPosition as a tuple, this is causing your problem.
Do convert this into a list object instead and your issue will be resolved.
Related
Pygame beginner, player animation not working despite doing it by the tutorial
First time ever working with Pygame for a school assignment and I'm following a tutorial for it with my project members (tutorial link https://youtu.be/AY9MnQ4x3zk). Problem is that despite following the tutorial to the dot at the "animating the player", my character (named "Marko" in the game and code) doesn't have his animation playing. When I start the game the character is stuck on it's first frame of animation. I've created a 3-frame animation and have the frames as separate png-files. The game so far itself works (it's on very beginner level, just a couple spawning enemies, collision and intro screens done so far), but the animation has had me and my project group scratching our heads for days. So far haven't found a solution by Googling nor searching here. Also at the "# Marko's animations" -part "marko" is darkened and when hovering mouse on it, it says ""(variable) marko: Surface - "marko" is not accessed Pylance"" Here's the entire code: import sys from pygame.locals import * from random import randint from pygame import mixer pygame.init() width = 1920 height = 1080 screen = pygame.display.set_mode((width,height)) pygame.display.set_caption("Putkimies Marko") start_time = 0 score = 0 nopeus = [3,3] clock = pygame.time.Clock() game_active = False marko_gravity = 0 # Score def display_score(): current_time = int(pygame.time.get_ticks() / 1000) - start_time score_surf = test_font.render(f'Score: {current_time}',False,(black)) score_rect = score_surf.get_rect(center = (900,50)) screen.blit(score_surf,score_rect) return current_time def obstacle_movement(obstacle_list): if obstacle_list: for obstacle_rect in obstacle_list: obstacle_rect.x -= 5 if obstacle_rect.bottom == 955: screen.blit(rat,obstacle_rect) else: screen.blit(fly,obstacle_rect) return obstacle_list else: return[] def collisions(marko,obstacles): if obstacles: for obstacle_rect in obstacles: if marko.colliderect(obstacle_rect): return False return True # Surfaces background = pygame.image.load("marko_background.png").convert_alpha() sewer = pygame.image.load("background_sewer.png").convert_alpha() ground = pygame.image.load("ground.png").convert_alpha() rat = pygame.image.load("rat.png").convert_alpha() game_over = pygame.image.load("game_over.png").convert_alpha() fly = pygame.image.load("fly.png").convert_alpha() # Marko Surfaces marko_run_1 = pygame.image.load("marko_run_1.png").convert_alpha() marko_run_2 = pygame.image.load("marko_run_2.png").convert_alpha() marko_run_3 = pygame.image.load("marko_run_3.png").convert_alpha() marko_run = [marko_run_1,marko_run_2,marko_run_3] marko_index = 0 marko_jump = pygame.image.load("marko_jump.png").convert_alpha() marko = marko_run[marko_index] # Fonts test_font = pygame.font.Font("supermario.ttf", 50) # Colors black = (0,0,0) red = (255,0,0) green = (0,255,0) blue = (0,0,255) light_blue = (94,129,162) purple = (36,5,83) # Rects game_overSurface = game_over.get_rect(midtop = (970,-200)) platform = pygame.Surface((300,50)) groundSurface = ground.get_rect(midtop = (960,480)) markoSurface = marko.get_rect() text_surface = test_font.render('Putkimies Marko', False, red) markoSurface.left = 50 markoSurface.bottom = 714 # Obstacles obstacle_rect_list = [] # Intro screen player_stand = pygame.image.load("putkimies_marko_idle.png") player_stand = pygame.transform.rotozoom(player_stand,0,2) player_stand_rect = player_stand.get_rect(center = (950,500)) game_name = test_font.render("PUTKIMIES MARKO", False,"Black") game_name_rect = game_name.get_rect(center = (950,350)) game_message = test_font.render('PRESS SPACE TO PLAY',False,"Black") game_message_rect = game_message.get_rect(center = (950,650)) game_message_start_again = test_font.render('PRESS SPACE TO PLAY AGAIN',False,"Black") game_message_start_again_rect = game_message.get_rect(center = (850,720)) # Marko's animations def marko_animation(): global markoSurface, marko_index if markoSurface.bottom < 955: marko = marko_jump else: marko_index += 0.1 if marko_index >= len(marko_run):marko_index = 0 marko = marko_run[int(marko_index)] # Timer obstacle_timer = pygame.USEREVENT + 1 pygame.time.set_timer(obstacle_timer,1500) # Background music mixer.music.load('smb_stage_clear.wav') mixer.music.play(0) # -1 Makes the music loop while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == KEYDOWN: if event.key == K_ESCAPE: pygame.quit() sys.exit() if game_active: if event.type == KEYDOWN: if event.key == K_SPACE and markoSurface.bottom >= 955: marko_gravity = -18 else: if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: game_active = True start_time = int(pygame.time.get_ticks() / 1000) if event.type == obstacle_timer and game_active: if randint (0,2): obstacle_rect_list.append(rat.get_rect(midbottom = (randint(2000,2200),955))) else: obstacle_rect_list.append(fly.get_rect(midbottom = (randint(2000,2200),855))) if game_active: # Draw screen.blit(sewer, (0,0)) screen.blit(ground, (0,955)) marko_animation() screen.blit(marko,markoSurface) score = display_score() # Key uses key_use = pygame.key.get_pressed() if key_use[K_LEFT]: markoSurface.move_ip((-7,0)) if key_use[K_RIGHT]: markoSurface.move_ip((7,0)) # Marko marko_gravity += 1 markoSurface.y += marko_gravity if markoSurface.bottom >= 955: markoSurface.bottom = 955 if markoSurface.left <= 0: markoSurface.left = 0 if markoSurface.right >= 1920: markoSurface.right = 1920 # Obstacle movement obstacle_rect_list = obstacle_movement(obstacle_rect_list) # Collision game_active = collisions(markoSurface,obstacle_rect_list) else: # Intro screen screen.fill ("Light blue") screen.blit(player_stand,player_stand_rect) obstacle_rect_list.clear() markoSurface.left = 80 # returns marko to 80 # Draws score message if score > 0 score_message = test_font.render(f'Your score: {score}',False,(red)) score_message_rect = score_message.get_rect(center = (950,650)) screen.blit(game_name,game_name_rect) if score == 0: screen.blit(game_message,game_message_rect) else: screen.blit(score_message,score_message_rect) screen.blit(game_over,game_overSurface) screen.blit(game_message_start_again,game_message_start_again_rect) pygame.display.update() clock.tick(60)```
marko is a variable in global namespace. You must use the global statement to change a variable in the global namespace within a function: def marko_animation(): global marko # <--- global marko_index if markoSurface.bottom < 955: marko = marko_jump else: marko_index += 0.1 if marko_index >= len(marko_run): marko_index = 0 marko = marko_run[int(marko_index)]
Why does my pygame collision detections not work? [duplicate]
This question already has answers here: How do I detect collision in pygame? (5 answers) Closed 1 year ago. Im relatively new to Python and Pygame. I'm making a game where a circle appears at a random location on the window and you have to touch it to get a point. I've programmed it to teleport to another random location when you touch the circle. The problem is when I try to detect collision between the circle and the player it basically teleport the circle non-stop. I also made a print function which prints hi when it detects collision and it also prints non-stop. I usually try to figure out the problem, but I really don't see what Im doing wrong, I'd appreciate all help given. enter code here import pygame import random vel = 2 pygame.init() pygame.font.init() fps = 60 win = pygame.display.set_mode((900, 500), pygame.RESIZABLE) pygame.display.set_caption("Test") #icon = pygame.image.load('icon.png') #pygame.display.set_icon(icon) background = pygame.image.load('Background.png') ghost = pygame.image.load("ghost.png") ghostrect = ghost.get_rect() circle = pygame.image.load("circle.png") circlerect = circle.get_rect() def main(): a = random.randint(0, 900) b = random.randint(0, 500) clock = pygame.time.Clock() run = True while run: keys_pressed = pygame.key.get_pressed() if keys_pressed[pygame.K_d] and ghostrect.x + 55 <= 900: ghostrect.x += vel if keys_pressed[pygame.K_a] and ghostrect.x + 5 >= 0: ghostrect.x -= vel if keys_pressed[pygame.K_s] and ghostrect.y + 63 <= 500: ghostrect.y += vel if keys_pressed[pygame.K_w] and ghostrect.y >= 0: ghostrect.y -= vel if circlerect.colliderect(ghostrect): a = random.randint(0, 900) b = random.randint(0, 500) win.blit(background, (0, 0)) win.blit(circle, (a, b)) win.blit(ghost, (ghostrect.x + 500, ghostrect.y + 210)) pygame.display.update() clock.tick(fps) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if __name__ == "__main__": main()
You haven't set ghostrect's value. By default, pygame.Rect objects position values are 0. You also have not set circlerect's value, so its position is also at (0, 0). Therefore, right now if circlerect.colliderect(ghostrect): will always return true. All you need to do is to give them position values to fix the problem. Give ghostrect some position. I have chosen (100, 100), that's completely up yo you. ghostrect = ghost.get_rect() #give the rect some position value ghostrect.x = 100 ghostrect.y = 100 Give circlerect the random position instead of assigning it to a and b. def main(): #remove them #a = random.randint(0, 900) #this #b = random.randint(0, 500) #and this circlerect.x = random.randint(0, 900)#add this circlerect.y = random.randint(0, 500)#and add this #... while run: #... if circlerect.colliderect(ghostrect): #remove this #a = random.randint(0, 900) #this #b = random.randint(0, 500) #and this circlerect.x = random.randint(0, 900)#add this circlerect.y = random.randint(0, 500)#and add this Then draw the circle at this position instead of a and b. win.blit(circle, (circlerect.x, circlerect.y))
When I start this code, i found a problem with error Traceback (most recent call last) in my code with pygame module
I have problem with function. I starting learn pygame with video course, and this is my first pygame code. My .py code: import pygame pygame.init() win = pygame.display.set_mode((1280, 720)) pygame.display.set_caption("text.") walkaniml = pygame.image.load('left1.png') walkanimr = pygame.image.load('right1.png') stickmanStand = pygame.image.load('stickman.png') clock = pygame.time.Clock() x = 250 y = 400 widht = 271 height = 293 speed = 5 jump = False jumplov = 10 left = False right = False animcount = 0 def drawcube(): global animcount win.fill((255, 218, 185)) if animcount + 1 >= 24: animcount = 0 if left: win.blit(walkaniml(animcount // 1, (x, y))) elif right: win.blit(walkanimr(animcount // 1, (x, y))) else: win.blit(stickmanStand, (x, y)) pygame.display.update() run = True while run: clock.tick(24) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False keys = pygame.key.get_pressed() if keys[pygame.K_LEFT] and x > 1: x -= speed left = True right = False elif keys[pygame.K_RIGHT] and x < 1280 - widht - 1: x += speed left = False right = True else: left = False right = False animcount = 0 if not(jump): if keys[pygame.K_DOWN] and y < 720 - height - 1: y += speed if keys[pygame.K_SPACE]: jump = True else: if jumplov >= -10: if jumplov < 0: y += (jumplov ** 2) / 3 else: y -= (jumplov ** 2) / 3 jumplov -= 1 else: jump = False jumplov = 10 enter image description here drawcube() I wanna do a mini-game with stickman, and i found a very big problem, when I start game in cmd and I'm going to web to found decision, but.. I don't find him. Please guys, I realy need help((
walkaniml and walkanimr are pygame.Surface objects. You can't call an object: win.blit(walkaniml(animcount // 1, (x, y))) win.blit(walkaniml, (x, y)) If walkaniml and walkanimr are a list of Surfaces, you can get an element from the lists by it's index with subscription (even if the list contains only 1 element): walkaniml = [ pygame.image.load('left1.png') ] walkanimr = [ pygame.image.load('right1.png') ] if left: if animcount >= len(walkaniml): animcount = 0 win.blit(walkaniml[animcount], (x, y)) elif right: if animcount >= len(walkanimr): animcount = 0 win.blit(walkanimr[animcount], (x, y))
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
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.