Pygame Tetris Issue - python
I've been writing a very rudimentary version of Tetris for Pygame in python 3.6. The only features so far are the blocks falling, making them fall faster, moving left and right, and when a block hits the ground, a new one spawns.
However, there is the issue. When the first block hits the ground, blocks spawn indefinitely at the top of the screen. I scoured the code and also showed it to my friend, and we couldn't find the issue. I scrapped the code and rewrote it, and the problem persisted. Does anyone here see it?
Thanks
P.S.
I'm pretty sure that the top 2/3 of the code is not the issue.
import pygame, random
screen = pygame.display.set_mode((400,600))
pygame.display.set_caption("Tetris")
done = False
fast = False
locked = False
fallingblocks = []
setblocks = []
clock = pygame.time.Clock()
fallcooldown = 0
class Block:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
fallingblocks.append(self)
self.rect = pygame.Rect(self.x + 1, self.y, 23, 25) #game only cares if falling block collides on the top or bottom, not side
def fall(self):
self.y += 25
def move(self):
if pressed[pygame.K_a] or pressed[pygame.K_LEFT]: self.x -= 25
if pressed[pygame.K_d] or pressed[pygame.K_RIGHT]: self.x += 25
def drawblock(self): #just to make it look nice
pygame.draw.rect(screen, self.color[0], pygame.Rect(self.x,self.y,25,25))
pygame.draw.polygon(screen, self.color[1], ((self.x,self.y),(self.x+3,self.y+3),(self.x+21,self.y+3),(self.x+24,self.y)))
pygame.draw.polygon(screen, self.color[2], ((self.x,self.y),(self.x+3,self.y+3),(self.x+3,self.y+21),(self.x,self.y+24)))
pygame.draw.polygon(screen, self.color[3], ((self.x,self.y+24),(self.x+3,self.y+21),(self.x+21,self.y+21),(self.x+24,self.y+24)))
pygame.draw.polygon(screen, self.color[4], ((self.x+24,self.y+24),(self.x+21,self.y+21),(self.x+21,self.y+3),(self.x+24,self.y)))
def spawn():
blocknum = random.randint(0,6)
if blocknum == 0:
#I block
colors = [(129,184,231),
(179,223,250),
(146,202,238),
(76,126,189),
(96,157,213)]
Block(175,0,colors)
Block(175,25,colors)
Block(175,50,colors)
Block(175,75,colors)
elif blocknum == 1:
#J block
colors = [(77,110,177),
(149,178,229),
(104,145,203),
(49,63,136),
(63,85,158)]
Block(200,0,colors)
Block(200,25,colors)
Block(200,50,colors)
Block(175,50,colors)
elif blocknum == 2:
#L block
colors = [(219,127,44),
(243,191,122),
(229,158,69),
(166,71,43),
(193,98,44)]
Block(175,0,colors)
Block(175,25,colors)
Block(175,50,colors)
Block(200,50,colors)
elif blocknum == 3:
#O block
colors = [(248,222,49),
(246,243,139),
(245,235,86),
(183,160,54),
(213,190,55)]
Block(175,0,colors)
Block(175,25,colors)
Block(200,0,colors)
Block(200,25,colors)
elif blocknum == 4:
#S block
colors = [(156,195,76),
(204,218,127),
(174,208,79),
(109,157,75),
(140,183,93)]
Block(175,0,colors)
Block(175,25,colors)
Block(200,0,colors)
Block(150,25,colors)
elif blocknum == 5:
#Z block
colors = [(204,42,40),
(226,138,132),
(213,90,69),
(151,34,42),
(181,37,43)]
Block(175,0,colors)
Block(225,25,colors)
Block(200,0,colors)
Block(200,25,colors)
else:
#T block
colors = [(147,68,149),
(187,145,194),
(156,101,167),
(108,45,123),
(128,47,135)]
Block(175,0,colors)
Block(175,25,colors)
Block(200,0,colors)
Block(150,0,colors)
spawn()
#Pretty sure that everything above here is not the issue
while not done: #main loop
screen.fill((0,0,32))
pressed = pygame.key.get_pressed()
for fallingblock in fallingblocks:
fallingblock.drawblock()
fallingblock.move()
for setblock in setblocks:
setblock.drawblock()
if fallcooldown >= 50: #makes all pieces fall at once
for fallingblock in fallingblocks:
fallingblock.fall()
fallcooldown = 0
pygame.display.flip()
if pressed[pygame.K_SPACE]: #if you want the piece to go the ground instantly
fast = True
if fast: fallcooldown = 50 #falling movements
elif pressed[pygame.K_DOWN]: fallcooldown += 8 #goes faster
else: fallcooldown += 1 #default speed
for fallingblock in fallingblocks:
for setblock in setblocks:
if fallingblock.rect.colliderect(setblock.rect): #if fallingblock collides with setblock
locked = True
if fallingblock.y >= 575 and not locked: #if block hits the bottom
locked = True
if locked: #if block is in final state
setblocks += fallingblocks
fallingblocks = []
spawn()
locked = False
clock.tick(50)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
The problem is caused in the fall method of the Block. You only change the y attribute but never move the rect of the block, so it actually stays at the top of the screen the whole time. So remove the x, y attributes and just use self.rect.x and self.rect.y, or alternatively set self.rect.y = self.y.
To debug the code I first printed print(locked, len(fallingblocks), len(setblocks)) above the if locked: line to confirm that locked was always True after the first block touched the ground. Then I tried to comment out the collision detection with the setblocks and the continuous spawning stopped. The next step was to print the rects of the setblocks and fallingblocks and it revealed that the y-pos of the rects was always 0 or 25 and never changed. I looked at the movement code in the fall method and noticed that the rect doesn't get moved.
There are more issues, but I think you should try to continue with the debugging first and ask new questions if you still have trouble.
Related
How do I make my rocket go back to its position when hitting the border?
I am new to programming and started with pygame zero. I am making a little game where you shoot a rocket to an alien. But my rocket keeps stuck to the border when fired, I made a reload function but I want it to go automatically ( when it hits the border or alien to go back to its normal position). Can anyone help me with that? alien = Actor('alien', (100,100)) ship =Actor('ship', (500,400)) rocket_fire = Actor('rocket_fire', (500,400)) WIDTH = 1000 HEIGHT =500 def draw(): screen.clear() screen.blit('space_back', (0,0)) rocket_fire.draw() ship.draw() alien.draw() def move_ship(ship): if keyboard.left: ship.x -= 3 rocket_fire.x -= 3 elif keyboard.right: ship.x += 3 rocket_fire.x += 3 elif keyboard.space: animate(rocket_fire, pos = (ship.x,0)) elif keyboard.r: rocket_fire.pos = (ship.x,ship.y) def move_alien(alien): alien.right +=2 if alien.left > WIDTH: alien.right = 0 collide = rocket_fire.colliderect(alien) if collide == 0: alien.image = 'alien' elif collide == 1: alien.image = 'nuclear_explosion' def update(): rocket_fire.draw() ship.draw() alien.draw() move_ship(ship) move_alien(alien)
You can try to assign the initial values to 'rocket_fire' after 'collide == 1'. elif collide == 1: alien.image = 'nuclear_explosion' // rocket_fire = (500,400) -> this is just a representation to assign position; not accurate as per the code
Blinking rectangle in pygame
I am trying to learn pyGame. And I ran into a problem. I have a rectangle which can be moved with arrow buttons. Then I created another thread which generates smaller rectangles which can be picked up. But when I run my game, the small generated rectangles blink too much. How can I make them be stable? I think I dont understand time concept here well. Could someone explain me etc My code: import pygame import random import threading import thread import sys import time pygame.init() screen = pygame.display.set_mode((400, 300)) done = False is_blue = True entityList = [] x = 30 y = 30 clock = pygame.time.Clock() class Entity(): def __init__(self, x, y): self.x = x self.y = y def getX(self): return self.x def getY(self): return self.y def drawStuff(entityList): # pygame.draw.rect(screen, (255, 100, 0), pygame.Rect(55, 45, 10, 10)) for x in range (0, entityList.__len__()): pygame.draw.rect(screen, (255, 100, 0), pygame.Rect(entityList[x].getX(), entityList[x].getY(), 10, 10)) pygame.display.flip() clock.tick(60) class EntityManager(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): while True: entityList = generateEntities() drawStuff(entityList) def endJob(self): thread.exit() time.sleep(2) def detect_collision(x,y): if x > 340: x -= 1 if y > 240: y -= 1 if y < 0: y += 1 if x < 0: x += 1 return x,y def generateEntities(): itemlist = [] for x in range (0,4): x = random.randint(1,339) y = random.randint(1,239) entity = Entity(x,y) itemlist.append(entity) return itemlist entityList = generateEntities() a = EntityManager() a.setDaemon(True) a.start() while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True pygame.quit() sys.exit() if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: is_blue = not is_blue pressed = pygame.key.get_pressed() if pressed[pygame.K_UP]: y -= 1 x,y = detect_collision(x, y) if pressed[pygame.K_DOWN]: y += 1 x,y = detect_collision(x, y) if pressed[pygame.K_LEFT]: x -= 1 x,y = detect_collision(x, y) if pressed[pygame.K_RIGHT]: x += 1 x,y = detect_collision(x, y) screen.fill((0, 0, 0)) if is_blue: color = (0, 128, 255) else: color = (255, 100, 0) pygame.draw.rect(screen, color, pygame.Rect(x, y, 60, 60)) pygame.display.flip() clock.tick(60)
clock.tick() actually means FPS (frames per second); instead of changing it, change another variable. Watch this tutorial, it might help you understand FPS. Issues about smoothness are sometimes about the size of your object and how many pixels you are moving it when key events are True. Be careful about that; imagine you have a little box and you are trying to move it. If you move it with big steps, it seems 'laggy', but if you move it with little steps then it may look smoother. Hope you understand what I mean. For your second question please check this documentation.
Okay, I figured it out now. OMG, I feel such an idiot after this. But I forgive myself that I am also doing parallell learning of Python. I used to code in Java more. Anyway: problem was that my drawStuff function drew things in function but when it left this function, it did nothing. Changes were made locally. I solved this problem by using global keyword. I made in my code changes that thread computes entity coordinates and then main loop does update. This leads me to another idea that maybe there should be some game info object which gets updated all the time and all rectangles info go to that game info object. Anyway, soon I will edit this post code too to see what i did
Player moves correct speed across the screen, walk cycle is too fast, hoping for suggestions to do it properly
I'm jumping around tutorials trying to successfully complete my first game. I was taking a heavy object oriented approach for managing resources, but I felt that was clouding my understanding a bit, so I restarted. I currently have my character moving smoothly across the screen at a speed I like, my problem is my "walk cycle" of three images goes way to fast, and I get a persistence of vision effect on my little chicken's legs. I need to slow it down, so far I was able to achieve a desired effect by popping in a call to the clock after each decision loop, but I am worried that will slow down the entire game logic, as I am not sure if calling clock more than once is "freezing" my game update in time while the character decides to move. I had considered maybe making some type of equation comparing the time on the clock to the time on the clock before, to slow down the walk cycle key frames. Any help or suggestions, is there an easier method? Thanks a bunch. import pygame, sys from pygame.locals import * pygame.init() #Contstants BLACK = (0, 0, 0) SCREENWIDTH = 300 SCREENHEIGHT = 300 game_running = True clock = pygame.time.Clock() #variables current = 0 class Player(object): def __init__(self): self.avatar_front = pygame.image.load("chicken_front.png") self.avatar_back = pygame.image.load("chicken_back.png") self.avatar_right = pygame.image.load("chicken_right_stand.png") self.avatar_left = pygame.image.load("chicken_left_stand.png") self.avatar_left_walk = pygame.image.load("chicken_left_walk1.png") self.avatar_left_walk2 = pygame.image.load("chicken_left_walk2.png") self.avatar_right = pygame.image.load("chicken_right_stand.png") self.avatar_right_walk = pygame.image.load("chicken_right_walk1.png") self.avatar_right_walk2 = pygame.image.load("chicken_right_walk2.png") self.position = [0, 0] self.current_direction = self.avatar_front #SetUp myScreen = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT)) pygame.display.set_caption("Chicken Rush!") pygame.display.set_icon(pygame.image.load("chicken_front.png")) myPlayer = Player() while game_running: myScreen.fill(BLACK) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() #RIGHT HERE DETERMINES WHICH IMAGE TO DISPLAY FOR WALKING LEFT->This is the part I need to # slow down keys_pressed = pygame.key.get_pressed() if keys_pressed[K_LEFT] and myPlayer.position[0] >= 0: if current == 0: myPlayer.current_direction = myPlayer.avatar_left current += 1 elif current == 1: myPlayer.current_direction = myPlayer.avatar_left_walk current += 1 elif current == 2: myPlayer.current_direction = myPlayer.avatar_left_walk2 current = 0 myPlayer.position[0] -= 3 if keys_pressed[K_RIGHT] and myPlayer.position[0] < SCREENWIDTH - 32: myPlayer.position[0] += 3 if keys_pressed[K_UP] and myPlayer.position[1] >= 0: myPlayer.position[1] -= 3 if keys_pressed[K_DOWN] and myPlayer.position[1] < SCREENHEIGHT - 35: myPlayer.position[1] += 3 myScreen.blit(myPlayer.current_direction, (myPlayer.position[0], myPlayer.position[1])) pygame.display.update() clock.tick(28)
It seems like you could use a longer interval to slow down the image transitions. Keep in mind you'll need to play with the value of imageTransitionSpeed to get it to your liking, but something like this should help slow the transition down: #RIGHT HERE DETERMINES WHICH IMAGE TO DISPLAY FOR WALKING LEFT->This is the part I need to # slow down imageTransitionSpeed = 10 keys_pressed = pygame.key.get_pressed() if keys_pressed[K_LEFT] and myPlayer.position[0] >= 0: if current == 0: myPlayer.current_direction = myPlayer.avatar_left current += 1 elif current == imageTransitionSpeed: myPlayer.current_direction = myPlayer.avatar_left_walk current += 1 elif current == (imageTransitionSpeed * 2): myPlayer.current_direction = myPlayer.avatar_left_walk2 current = 0 else: current += 1 myPlayer.position[0] -= 3 if keys_pressed[K_RIGHT] and myPlayer.position[0] < SCREENWIDTH - 32: myPlayer.position[0] += 3 if keys_pressed[K_UP] and myPlayer.position[1] >= 0: myPlayer.position[1] -= 3 if keys_pressed[K_DOWN] and myPlayer.position[1] < SCREENHEIGHT - 35: myPlayer.position[1] += 3 myScreen.blit(myPlayer.current_direction, (myPlayer.position[0], myPlayer.position[1])) pygame.display.update() clock.tick(28)
Collision detection in pygame not working properly
I have a piece of code that is supposed to place 1000 squares on screen, none overlapping. But when I run it, I just get a bunch of squares where some of them ARE overlapping, any idea where I went wrong? import time, pygame, ctypes, random class Block(pygame.sprite.Sprite): def __init__(self, color, width, height): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface([width, height]) self.image.fill(color) self.rect = self.image.get_rect() white = (255,255,255) black = (0, 0, 0) user32 = ctypes.windll.user32 sw = user32.GetSystemMetrics(0) sh = user32.GetSystemMetrics(1) Bloqs = {} #Bloq atributes: Position (upper left), Size, Color, Genetics pygame.init() all_sprites_list = pygame.sprite.Group() def Collision(bloq): global all_sprites_list hit = pygame.sprite.spritecollide(bloq, all_sprites_list, True) if len(hit) == 0: return False if len(hit) > 0: return True def InitializeSim(): global Bloqs global white global black global sw global sh global all_sprites_list size = sw, sh screen = pygame.display.set_mode(size, pygame.FULLSCREEN ) screen.fill(white) count = 0 while count < 1000: size = 10 pos = random.seed() posx = random.randint(0, sw-size) posy = random.randint(0, sh-size) #pygame.draw.rect(screen, color, (x,y,width,height), thickness) CurrentBloq = "bloq" + str(count) Bloqs[CurrentBloq]={} Bloqs[CurrentBloq]["position"] = (sw, sh) bloq = Block(black, size, size) bloq.rect.x = posx bloq.rect.y = posy Bloqs[CurrentBloq]["sprite"] = bloq all_sprites_list.add(bloq) all_sprites_list.draw(screen) pygame.display.update() while Collision(bloq) == True: all_sprites_list.remove(bloq) posx = random.randint(0, sw-size) posy = random.randint(0, sh-size) bloq.rect.x = posx bloq.rect.y = posy all_sprites_list.add(bloq) all_sprites_list.draw(screen) pygame.display.update() count += 1 InitializeSim() time.sleep(5) pygame.quit()
Your code seems pretty complex for what you are trying to do... approach it as a whole however feels natural for you, but when generating the blocks, I would follow something more along the lines of: for i in range(numberofblocksyouwant): while true: create a block at a random x,y pos if block collides with any existing blocks: remove the block you just created else: break For every block you want, this approach would keep recreating each block until it picks a random x,y that does not end up colliding with any other blocks. However, if your blocks fill up the screen and make doing this impossible, the nested while loop will never end. Hope that helps, let me know if that doesn't make sense.
To build upon Max's answer: You would probably want a system to abort if there are to many iterations without success. I would write it: for i in range(numberofblocksyouwant): while true: numberofattempts = 0 create a block at a random x,y pos if block collides with any existing blocks: remove the block you just created numberofattempts += 1 if numberofattempts > 1000: return "took too many attempts" else: break
Scrolling in 2D game?
I'm trying to add a scrolling "camera" that follows the player when it moves but can't figure out how to do this. I know that you can just move the level in the opposite direction when you press one of the movement keys but I'd rather not do that as I plan on adding enemies later on and don't want have to keep update their coordinates as the player moves. I've added my code with a sample level below. 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 # 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, blockListDisp[i].y)) #blit the wall-block graphics pygame.draw.rect(screen, (0, 0, 0), player) pygame.display.update() mainClock.tick(FPS)
The trick is to keep track of camera coordinates and use these as an offset in your rendering code. It looks like you're doing you're rendering right at the end of the code you've posted, drawing each block with coord x,y to pixel x,y on the screen. As you say, shifting the level around isn't great. Instead, have your key inputs (or other camera moving device) change cameraX and cameraY variables, and then add (or subtract, depending which direction you want to go) these values from the block x and y values to change which pixels map to which blocks. I.e. change your rendering to: screen.blit(wallblock, (blockListDisp[i].x + cameraX, blockListDisp[i].y + cameraY)) This means if your camera moves to (10, 20) then you map your block at (5, 5) to (15, 25) on the screen, shifting your whole level across while your underlying model of the level stays the same. Make sense? You can also take this slightly further; if your camera is only being moved to follow your character you can make swap cameraX and cameraY in the above for some function of the character position, and have the whole thing just managed directly there.