How do i check for tiles around a specific tile? - python
I'm making a game.
The game's world is represented by a tilemap. The tiles correspond to values in a 2D array.
I would like to use a special "corner" wall sprite if any three wall tiles make an L shape. That is,
V
## # >##
# ## #
^
The tiles indicated with arrows should be corner tiles.
I have the code to search for the wall but I don't know how to identify which tiles are the corner tiles.
My code is:
import pygame, sys
import Sprites
import random
from pygame.locals import *
pygame.init()
fpsClock = pygame.time.Clock()
cloudx = -200
cloudy = 0
infoObject = pygame.display.Info()
DIRT = 0
GRASS = 1
WATER = 2
COAL = 3
CLOUD = 4
WALL = 5
CWALL = 6
controls = {
DIRT : 49,
GRASS: 50,
WATER: 51,
COAL : 52,
WALL : 53
}
infoObject = pygame.display.Info()
w = infoObject.current_w
h = infoObject.current_h
TILESIZE = 40
MAPWIDTH = 15
MAPHEIGHT = 15
WHITE = (255,255,255)
BLACK = (0,0,0)
resources = [DIRT, GRASS, WATER, COAL]
textures = {
DIRT : pygame.image.load('Sprites/Dirt.png'),
GRASS : pygame.image.load('Sprites/tile130.png'),
WATER : pygame.image.load('Sprites/Water.png'),
COAL : pygame.image.load('Sprites/Coal.png'),
CLOUD : pygame.image.load('Sprites/Cloud.png'),
WALL : pygame.image.load('Sprites/Swall.png'),
CWALL : pygame.image.load('Sprites/Swall.png')
}
playerPos = [0,0]
inventory = {
DIRT : 0,
GRASS : 0,
WATER : 0,
COAL : 0,
WALL : 10,
}
tilemap = [[DIRT for w in range(MAPWIDTH)] for h in range(MAPHEIGHT)]
DISPLAYSURF = pygame.display.set_mode((MAPWIDTH*TILESIZE,MAPHEIGHT*TILESIZE + 50))
pygame.display.set_caption('M I N E C R A F T -- 2D')
pygame.display.set_icon(pygame.image.load('Sprites/player.png'))
PLAYER = pygame.image.load('Sprites/Player.png').convert_alpha()
for rw in range(MAPHEIGHT):
for cl in range(MAPWIDTH):
randomNumber = random.randint(0,15)
if randomNumber == 0:
tile = COAL
elif randomNumber == 1 or randomNumber == 2:
tile = WATER
elif randomNumber >= 3 and randomNumber <=7:
tile = GRASS
else:
tile = DIRT
tilemap[rw][cl] = tile
INVFONT = pygame.font.Font('freesansbold.ttf', 18)
print(tilemap)
while True:
currentTile = tilemap[playerPos[1]][playerPos[0]]
DISPLAYSURF.fill(BLACK)
for event in pygame.event.get():
# print(event)
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
for key in controls:
if (event.key == controls[key]):
if inventory[key] > 0:
inventory[key] -=1
inventory[currentTile] += 1
tilemap[playerPos[1]][playerPos[0]] = key
if(event.key == K_RIGHT) and playerPos[0] < MAPWIDTH - 1:
playerPos[0]+=1
elif(event.key == K_LEFT) and playerPos[0] > 0:
playerPos[0]-=1
elif(event.key == K_DOWN) and playerPos[1] < MAPHEIGHT - 1:
playerPos[1]+=1
elif(event.key == K_UP) and playerPos[1] > 0:
playerPos[1]-=1
if event.key == K_SPACE:
currentTile = tilemap[playerPos[1]][playerPos[0]]
inventory[currentTile] += 1
tilemap[playerPos[1]][playerPos[0]] = DIRT
for row in range(MAPHEIGHT):
for column in range(MAPWIDTH):
DISPLAYSURF.blit(textures[tilemap[row][column]],(column*TILESIZE, row*TILESIZE, TILESIZE, TILESIZE))
DISPLAYSURF.blit(PLAYER,(playerPos[0]*TILESIZE,playerPos[1]*TILESIZE))
DISPLAYSURF.blit(textures[CLOUD].convert_alpha(),(cloudx,cloudy))
cloudx +=1
if cloudx > MAPWIDTH*TILESIZE:
cloudy = random.randint(0, MAPHEIGHT*TILESIZE)
cloudx = -200
placePosition = 10
for item in resources:
DISPLAYSURF.blit(textures[item],(placePosition, MAPHEIGHT*TILESIZE+10))
placePosition+=50
textObj = INVFONT.render(str(inventory[item]), True, WHITE, BLACK)
DISPLAYSURF.blit(textObj,(placePosition, MAPHEIGHT*TILESIZE+20))
placePosition += 50
pygame.display.update()
fpsClock.tick(24)
for x in range(MAPWIDTH):
for y in range(MAPHEIGHT):
if tilemap[x][y] == WALL:
go_left = x > 1
go_right = x < MAPWIDTH - 1
go_up = y > 1
go_down = y < MAPHEIGHT - 1
if go_left:
tilemap[x - 1][y] = CWALL
if go_up:
pass
if go_right:
tilemap[x + 1][y] = WALL
if go_up:
pass
if go_down:
pass
print('WALL')
pygame.display.update()
And here are the links to the sprites:
https://framadrop.org/r/fmReup_rTK#bMSywSUa7nxb1qL/a4FIbns+VaspgE0c/FU+9f1drHI=
https://framadrop.org/r/pBOfrnKcdT#eNEZQ9QjX5Cl6X4gH4UwdIg3eBPnY/L4WcSGYtUR5PE=
https://framadrop.org/r/ZFfTz_Lq9V#2Nd5ba1iE7miyFg8JpPFvwabAkdnHds/GfVkSAQeJaQ=
https://framadrop.org/r/gN9Y748L9G#Z552pPpgjTcSubt9tn74mZ0tT1COv7UCFdkUq2DorAU=
https://framadrop.org/r/d9k4hyCUni#OTza8UbsR8Am/R1PA9MAWkLDPRDBsT1rAHMgr61jusc=
https://framadrop.org/r/1mv777OR6d#pkqwaQrmVRElUPcdEV5K4UhmALsJSYX7z3WtrZXl4TE=
https://framadrop.org/r/CyF-tk7yUb#IFexcePe418JizElZzCJzDENTJPDfz7i1nr+lGns0rU=
https://framadrop.org/r/VzVfAz6bnL#oLHivyHPtTD8+IxliDD4yc+6LS9kpGyEp1HNFGUsBHo=
https://framadrop.org/r/0V0ShMH0uq#PZHdPSQNbgL7QqH2niwdS4HO34ZRMfIlhpvpRqbWwng=
From the comments, I'm not sure what the problem is... let me just show you what I would do so we can discuss further if needed:
for x in range(MAPWIDTH):
for y in range(MAPHEIGHT):
if tilemap[x][y] == WALL:
# there is a wall at indices x and y
# get neighbouring tiles (check for limits)
go_left = x > 1
go_right = x < MAPWIDTH - 1
go_up = y > 1
go_down = y < MAPHEIGHT - 1
if go_left:
# you can use x-1
tilemap[x-1][y] = WALL # set left tile to WALL
if go_up:
# do something in the diagonal with x-1 y-1?
pass
if go_right:
# you can use x+1
tilemap[x+1][y] = WALL # set right tile to WALL
if go_up:
pass # same story
if go_down:
pass # and again
EDIT here is a simple (hence hopefully easy to understand) way of doing this
In order to make the textures clean, I first had to rotate the wall and corner to get all possible configurations (vertical/horizontal for the wall, and all four possibilities for the corner)
VWALL = 5
HWALL = 6
CORNERLD = 7
CORNERRD = 8
CORNERLU = 9
CORNERRU = 10
controls = {
DIRT : 49,
GRASS : 50,
WATER : 51,
COAL : 52,
VWALL : 53,
HWALL : 54,
CORNERLD: 55,
CORNERRD: 56,
CORNERLU: 57,
CORNERRU: 58,
}
tex_wall = pygame.image.load('Sprites/Swall.png')
tex_corner = pygame.image.load('Sprites/Corner.png')
textures = {
DIRT : pygame.image.load('Sprites/Dirt.png'),
GRASS : pygame.image.load('Sprites/tile130.png'),
WATER : pygame.image.load('Sprites/Water.png'),
COAL : pygame.image.load('Sprites/Coal.png'),
CLOUD : pygame.image.load('Sprites/Cloud.png'),
HWALL : pygame.transform.rotate(tex_wall, 90),
VWALL : tex_wall,
CORNERRD: tex_corner,
CORNERLD: pygame.transform.flip(tex_corner, True, False),
CORNERLU: pygame.transform.flip(tex_corner, True, True),
CORNERRU: pygame.transform.flip(tex_corner, False, True),
}
I created a wall dict to quickly check all 6 possibilities for walls with in walls
walls = {
VWALL : None,
HWALL : None,
CORNERLD: None,
CORNERRD: None,
CORNERLU: None,
CORNERRU: None,
}
And then I check the map
for x in range(MAPWIDTH):
for y in range(MAPHEIGHT):
if tilemap[x][y] in walls:
# there is a wall at indices x and y
# get neighbouring tiles (check for limits)
go_left = x > 1
go_right = x < MAPWIDTH - 1
go_up = y > 1
go_down = y < MAPHEIGHT - 1
l_wall = False
r_wall = False
u_wall = False
d_wall = False
if go_left and tilemap[x-1][y] in walls:
# left tile is WALL
l_wall = True
if go_right and tilemap[x+1][y] in walls:
# right tile is WALL
r_wall = True
if go_up and tilemap[x][y-1] in walls:
u_wall = True
if go_down and tilemap[x][y+1] in walls:
d_wall = True
if l_wall and u_wall:
# upper left corner
tilemap[x][y] = CORNERLU
elif l_wall and d_wall:
# down left corner
tilemap[x][y] = CORNERRU
elif r_wall and u_wall:
# upper left corner
tilemap[x][y] = CORNERLD
elif r_wall and d_wall:
# down left corner
tilemap[x][y] = CORNERRD
elif (l_wall or r_wall) and not (u_wall or d_wall):
# tiles in a vertical wall, use VWALL
tilemap[x][y] = VWALL
elif (u_wall or d_wall) and not (l_wall or r_wall):
# tiles in a horizontal wall, use HWALL
tilemap[x][y] = HWALL
And we get
Note that there are random configurations of wall that will not look good, though (T-shapes...) but these would require additional sprites.
The full code I used can be found here
EDIT2 note that you will have to update a few more things to make everything work smoothly (e.g. wall uptake in the inventory)
Also running this check every loop is costly, so you should declare an env_changed boolean to make the test only when a change was made to the environment.
For the inventory, you will need
if currentTile in walls:
inventory[VWALL] += 1
this makes VWALL the default wall in the inventory and the loop takes care of switching it to a proper one for the display.
For the rest, well... it's your game, so I'll let you figure it out ;)
I'd start by generating a set offsets
// 1
//0 2 Neighbour directions
// 3
// 0 1 2 3 Corresponding offsets
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
Nmax = 4
Now, I can get the n-values of the neighbouring walls, like so:
nwalls = []
for n in range(Nmax): #n is the direction of the neighbour
#Ensure that the neighbour tile, identified as (x+dx[n], y+dy[n])
#is in the map and check to see if it is a wall
if 1<x+dx[n]<WIDTH and 1<y+dy[n]<HEIGHT and tilemap[x+dx[n]][y+dy[n]]==WALL:
nwalls.append(n) #Neighbour was a wall, add its direction to this list
Now, I can convert my list into a tile name:
#nwalls is a list of all the directions pointing to a wall
nwalls.sort() #Sort list, e.g. 3,1,2 -> 1,2,3
nwalls = map(str,nwalls) #Convert from numbers to strings
nwalls = ''.join(nwalls) #Append strings together: ['1','2','3'] -> '123'
if nwalls: #If the string is not empty
nwalls = 'corner_tile_{0}.jpg'.format(nwalls) #Convert string to tile name
Now I just need a bunch of tiles named, e.g.:
corner_tile_01.jpg
corner_tile_013.jpg
Then I can say:
if nwalls: #Only true if this was a corner
Code to display the tile whose name is stored in `nwalls`
Related
Random Brick Color -> TypeError: 'pygame.Color' object is not callable
so this is my first time as a registered user here, so please bear with me if I was searching wrong, but with the tags [python] or [pygame] I could not find an answer to this question of a random color. So my problem is the following: The Game In this game I want the bricks to be random colors. To do so I made a function to generate a random color: def brick_color(): color_var = random.randint(0,3) if color_var == 0: #red brick_color1 = pygame.Color(198,44,58) elif color_var == 1:#blue brick_color1 = pygame.Color(1,128,181) elif color_var == 2:#yellow brick_color1 = pygame.Color(255,211,92) elif color_var == 3:#green brick_color1 = pygame.Color(0,157,103) return brick_color1 and implemented the function into this lines: # brick init brick = pygame.Surface([brick_width, brick_height]),brick_color # surface for a single brick pygame.draw.rect(brick[0], brick[1], [0, 0, brick_width, brick_height]) bricks = [] # list of *coordinates* of the bricks # initialize coordinates of bricks for y in range(num_brick_rows): brickY = (y * brick_row_height) + brick_offset_y for x in range(num_bricks_in_row): brickX = (x * brick_column_width) + brick_offset_x color_of_brick = brick_color() bricks.append((brickX, brickY),color_of_brick) # coordinates are in fact tuples (x,y) But i keep getting this error: File "C:\_____\unbenannt0.py", line 146, in <module> color_of_brick = brick_color() TypeError: 'pygame.Color' object is not callable And this is the full code. #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Thu Jul 2 09:33:50 2020 #author: """ # example from the Sloan Kelly book # very slightly modified # imports (or makes usable) external packages that may be 3rd party (such as pygame) import pygame, sys, random # enable "short-hand" notation for imported stuff from pygame.locals import QUIT, MOUSEBUTTONUP, MOUSEMOTION, KEYDOWN, K_ESCAPE from pygame import display #Functions def draw_bricks(): for b in bricks: windowSurfaceObj.blit(brick[0], b) # makes a copy of brick image acording to coordinates, where stuff is drawn! def draw_bat(): windowSurfaceObj.blit(bat, batRect) def draw_ball(): windowSurfaceObj.blit(ball, ballRect) def brick_color(): color_var = random.randint(0,3) if color_var == 0: #red brick_color = pygame.Color(198,44,58) elif color_var == 1:#blue brick_color = pygame.Color(1,128,181) elif color_var == 2:#yellow brick_color = pygame.Color(255,211,92) elif color_var == 3:#green brick_color = pygame.Color(0,157,103) return brick_color pygame.init() fpsClock = pygame.time.Clock() # new and improved: # create surface object aka. the main window inf = display.Info() screen_width = inf.current_w - 200 # make window sizea little bit smaller than actual screen screen_height = inf.current_h - 200 # windowSurfaceObj = display.set_mode(size=(screen_width, screen_height), flags=pygame.FULLSCREEN) # initialize window windowSurfaceObj = display.set_mode(size=(screen_width, screen_height)) # initialize window display.set_caption('New and improved Bricks'); # set window title # brick layout brick_width = 50 brick_height = 20 num_bricks_in_row = 7 num_brick_rows = 5 brick_row_height = 2 * brick_height brick_offset_y = 100 brick_column_width = 2 * brick_width brick_offset_x = int(screen_width/2 - brick_column_width*num_bricks_in_row/2) # place it in the middle of the screen brick_color = brick_color() # ball related stuff ball_radius = int(screen_height/200) # more game constants! fps = 60 # desired frames per second background_colour = pygame.Color(0, 0, 0) # background is black # used variables for bat dimensions bat_width = 100 bat_height = 10 # ball related stuff ball_start_x = 24 # somehwere near the left of the window ball_start_y = 200 # initial ball position when new ball is released ball_speed = int(fps*0.15) # speed of ball in pixel per frame! use fps var. here to make real ball speed independent of frame rate # bat init # replace bat with crude hand drawn one batcolor = pygame.Color(0, 0, 255) # bat color: blue! bat = pygame.Surface([bat_width, bat_height]) # this Surface is for drawing the bat upon pygame.draw.rect(bat, batcolor, [0, 0, bat_width, bat_height]) # draw bat. It's a simple rectangle. bat = bat.convert_alpha() # deal with transparency # place the bat somewhere near the bottom of the screen/window player_start_x = 0 # initial position is on left player_start_y = screen_height - 6 * bat_height # this is used as Y coordinate for bat, near the bottom of the screen batRect = bat.get_rect() # rectangle around bat, used to move it around later mousex = player_start_x mousey = player_start_y # mousex and mousey later used for moving the bat around, not actual mouse coordinates at this point # ball init ball_color = pygame.Color(255, 255, 255) # white ball = pygame.Surface([ball_radius*2, ball_radius*2]) # Surface for drawing the ball upon pygame.draw.circle(ball, ball_color, (ball_radius, ball_radius), ball_radius) # draw circle on ball surface ballRect = ball.get_rect() # rectangle around ball, use to move it around later ballServed = False bx = ball_start_x # bx is actual ball postion by = ball_start_y # by is actual (current) ball position sx = ball_speed # current ball speed in horizontal direction sy = ball_speed # current ball speed vertical ballRect.topleft = (bx, by) # move ball rectangle to initial position # brick init brick = pygame.Surface([brick_width, brick_height]),brick_color # surface for a single brick pygame.draw.rect(brick[0], brick[1], [0, 0, brick_width, brick_height]) bricks = [] # list of *coordinates* of the bricks # initialize coordinates of bricks for y in range(num_brick_rows): brickY = (y * brick_row_height) + brick_offset_y for x in range(num_bricks_in_row): brickX = (x * brick_column_width) + brick_offset_x color_of_brick = brick_color() bricks.append((brickX, brickY),color_of_brick) # coordinates are in fact tuples (x,y) while True: # main loop, run once per frame (i.e. fps times per second) windowSurfaceObj.fill(background_colour) # clear the screen # brick draw # for b in bricks: # remember: bricks is a list of brick coordinates, not surfaces # windowSurfaceObj.blit(brick, b) # make copy of brick image and place it on screen, b = brick coordinates draw_bricks() # bat and ball draw, rectangles around bat and ball are used for positioning # windowSurfaceObj.blit(bat, batRect) # copy surface with image of bat to screen # windowSurfaceObj.blit(ball, ballRect) # same for ball draw_bat() draw_ball() # main event loop # process user interaction for event in pygame.event.get(): # quit the game if window is closed or escape key is pressed if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): pygame.quit() sys.exit() elif event.type == MOUSEBUTTONUP and not ballServed: ballServed = True # start game, when mouse is clicked elif event.type == MOUSEMOTION: # mouse has moved mousex, mousey = event.pos # set mouse coordinate variables to actual mouse coordinates if mousex < screen_width - bat_width: if mousex < 0: # may occur in full screen / large window mode batRect.topleft = (0, player_start_y) else: batRect.topleft = (mousex, player_start_y) else: batRect.topleft = (screen_width - bat_width, player_start_y) # main game logic if ballServed: # if game is in progress ballRect.topleft = (bx, by) # position the ball using its rectangle bx += sx # sx = speed of the ball in X direction by += sy # sy = speed of the ball in Y direction if (by >= screen_height): # ball below bottom of screen ballServed = False # game not in progess, ball lost! bx, by = (ball_start_x, ball_start_y) # ball is reset to start position ballRect.topleft = (bx, by) # move the rectangle around ball to correct position if by <= 0: # ball hits top by = 0 sy *= -1 # reflect if bx <= 0: # ball hits left side of window bx = 0 sx *= -1 # reflect if bx >= screen_width - ball_radius*2: # ball hits right side of window bx = screen_width - ball_radius*2 sx *= -1 # reflection # collision detection brickForRemoval = None for b in bricks: # remember: bricks is list of coordinates of bricks; iterating all bricks and check each one for collision briX, briY = b # tuple unwrapping: x and y coordinates of top left of brick if bx + ball_radius*2 >= briX and bx <= briX + brick_width: # is x coordinate of ball inside brick (or touching brick) if (by + ball_radius*2 >= briY and by <= briY + brick_height): # same for y coordinate brickForRemoval = b # brick was hit and is scheduled for removal if bx <= briX + ball_radius*2: # ball hit brick from left sx *= -1 # reflect elif bx >= briX + brick_width - ball_radius*2: # ball hit brick from right sx *= -1 # reflect if by <= briY + ball_radius * 2: # ball hit brick from top sy *= -1 # reflect elif by >= briY + brick_height - ball_radius*2: # ball hit brick from below sy *= -1 # reflect break # ball hit a brick and cannot hit another one at the same time if brickForRemoval != None: # if a brick is scheduled for removal… bricks.remove(brickForRemoval) # … remove it! # collision check: does bat hit ball? if (bx >= mousex and bx <= mousex + bat_width): # using bat_width variable if(by >= player_start_y - bat_height and by <= player_start_y): sy *= -1 # reflect pygame.display.update() # show updated screen fpsClock.tick(fps) # limit fps Any help is highly appreciated!
As per #jasonharper's comment, when you assign a value to a variable name that is the same as the function name, that name becomes "re-assigned", in this case - making the function no longer accessible. Using any other variable name inside your function would fix it: def brick_color(): color_var = random.randint(0,3) if color_var == 0: #red new_color = pygame.Color(198,44,58) elif color_var == 1:#blue new_color = pygame.Color(1,128,181) elif color_var == 2:#yellow new_color = pygame.Color(255,211,92) elif color_var == 3:#green new_color = pygame.Color(0,157,103) return new_color Your function could also use a python list to be a bit more flexible and compact: def getRandomColor(): # red blue yellow green color_list = [ (198,44,58), (1,128,181), (255,211,92), (0,157,103) ] random_choice = random.randrange( len( color_list ) ) return color_list[ random_choice ] This form is more flexible because you can easily add more colours by appending them to the list (no more to do).
How can I retrieve coordinates of a pymunk.Circle?
I'm new to python so please forgive me if I'm misnaming pygame objects. I've been tasked to build a virtual Pachinko gaming machine. I'm having trouble getting the coordinates of the ball as it falls through the window. I need the coordinates to keep track of score and reset the loops so the user can drop another ball once it bottoms out. Here's my source code. #Project specific libraries import pygame #https://www.pygame.org/news import pymunk #http://www.pymunk.org/en/latest/ import pymunk.util import pymunk.pygame_util import tkinter #https://docs.python.org/2/library/tkinter.html #Standard libraries import sys import math import random import os import time #Import ALL tools from tkinter & pygame libraies from tkinter import * from pygame import * #Constants for object to object interaction COLLTYPE_FLOOR = 3 COLLTYPE_BOUNCER = 2 COLLTYPE_BALL = 1 #**************************************************************************** def goal_reached(arbiter, space1, data): ball_i, floor_i = arbiter.shapes space_i = space1 space_i.remove(ball_i, ball_i.body) remove_from_ball_list(ball_i) return True #************************************************************* main = Tk() main.resizable(width=False, height=False) main.title("Pachinko") embed = Frame(main, width = 500, height = 500) embed.pack() #packs window to the left os.environ['SDL_WINDOWID'] = str(embed.winfo_id()) screen = pygame.display.set_mode((500,500)) screen.fill(pygame.Color(255,215,255)) clock = pygame.time.Clock() #List of ball "objects" balls = [] #might not need balls_to_remove List balls_to_remove = [] #velocity, gravity space = pymunk.Space() space.gravity = 0, -200 #Floor boundaries floor = pymunk.Segment(space.static_body, (0.0, 10.0), (500.0, 10.0), 1.0) floor.collision_type = COLLTYPE_FLOOR space.add(floor) #Left wall boundaries left_wall = pymunk.Segment(space.static_body, (0.0, 500.0), (0.0, 0.0), 1.0) left_wall.friction = 1.0 left_wall.elasticity = 0.9 left_wall.collision_type = COLLTYPE_BOUNCER space.add(left_wall) #Right wall boundaries right_wall = pymunk.Segment(space.static_body, (500.0, 500.0), (500.0, 0.0), 1.0) right_wall.friction = 1.0 right_wall.elasticity = 0.9 right_wall.collision_type = COLLTYPE_BOUNCER space.add(right_wall) draw_options = pymunk.pygame_util.DrawOptions(screen) space.debug_draw(draw_options) #Generate a fixed field of pins done = 0 x_shift = 45 y_shift = 150 step = 0 tier = 0 while(done == 0): variance = random.randint(1, 15) pin_radius = random.randint(14, 17) newPin = pymunk.Body(body_type=pymunk.Body.KINEMATIC) x = x_shift + variance y = y_shift + variance newPin.position = x, y shape = pymunk.Circle(newPin, pin_radius) shape.collision_type = COLLTYPE_BOUNCER space.add(newPin, shape) x_shift += 85 step += 1 if(step == 5): #Tier one x_shift = 100 y_shift += 60 if(step == 10): #Tier two x_shift = 50 y_shift += 60 if(step == 15): #Tier three x_shift = 100 y_shift += 60 if(step == 20): #Tier four x_shift =50 y_shift += 60 if(step == 25): #Tier five x_shift = 100 y_shift += 60 done = 1 #Generate the five poles (left to right) step = 0 x_shift = 100 while(step < 4): pole0 = pymunk.Segment(space.static_body, (x_shift, 100.0), (x_shift, 10.0), 5.0) pole0.friction = 1.0 pole0.elasticity = 0.9 pole0.collision_type = COLLTYPE_BOUNCER space.add(pole0) step += 1 x_shift += 100 pygame.display.flip() pygame.display.init() pygame.display.update() #https://stackoverflow.com/questions/23410161/pygame-collision-code h = space.add_collision_handler(COLLTYPE_BALL, COLLTYPE_FLOOR) h.begin = goal_reached def remove_from_ball_list(temp1): #print("where in list is it?") for ball in balls: if temp1 == ball: #print("Time to remove from the list") balls.remove(ball) #Primary game loop ticks = 50 play = True while play == True: mouseClick = pygame.event.get() dropHeight = 440 for event in mouseClick: if event.type == pygame.MOUSEBUTTONUP: mouseX, mouseY = pygame.mouse.get_pos() ticks = 0 #keep making new balls & pins if ticks == 0: step = 0 x_shift = 0 y_shift = 0 #Generate the new ball mass = 1 inertia = pymunk.moment_for_circle(mass, 0, 14, (0, 0)) radius = 12 ball = pymunk.Body(mass, inertia) #Keep the ball in bounds when user drops if(mouseX < 25): mouseX = 10 if(mouseX > 480): mouseX = 490 ball.position = mouseX, dropHeight shape = pymunk.Circle(ball, radius) shape.collision_type = COLLTYPE_BALL space.add(ball, shape) balls.append(shape) ticks = 50 pygame.draw.line(screen, (255,0,255), (20,60), (480,60), 2) space.step(1/50.0) space.debug_draw(draw_options) pygame.display.update() pygame.display.flip() screen.fill(pygame.Color(255,215,255)) clock.tick(50) #ticks -= 1 main.update() And here is the specific piece of code I'd like to add the feature: #Primary game loop ticks = 50 play = True while play == True: mouseClick = pygame.event.get() dropHeight = 440 for event in mouseClick: if event.type == pygame.MOUSEBUTTONUP: mouseX, mouseY = pygame.mouse.get_pos() ticks = 0 #keep making new balls & pins if ticks == 0: step = 0 x_shift = 0 y_shift = 0 #Generate the new ball mass = 1 inertia = pymunk.moment_for_circle(mass, 0, 14, (0, 0)) radius = 12 ball = pymunk.Body(mass, inertia) #Keep the ball in bounds when user drops if(mouseX < 25): mouseX = 10 if(mouseX > 480): mouseX = 490 ball.position = mouseX, dropHeight shape = pymunk.Circle(ball, radius) shape.collision_type = COLLTYPE_BALL space.add(ball, shape) balls.append(shape) ticks = 50 pygame.draw.line(screen, (255,0,255), (20,60), (480,60), 2) space.step(1/50.0) space.debug_draw(draw_options) pygame.display.update() pygame.display.flip() screen.fill(pygame.Color(255,215,255)) clock.tick(50) #ticks -= 1 main.update() I would like to print the ball coordinates to the terminal so I can add scoring and restart features. I feel like that I'm missing a very simple solution.
It seems like the balls are collected in a list, balls. So you can just loop through it to get all the info you need. For example, if you put the below code in the while loop it will print the location of each ball each frame. for b in balls: print("ball position", b.body.position) However, maybe you do not need to check this yourself each frame? You already have a goal_reached function, that is called once the ball reached the goal if I understand it correctly. In there you can update the score and toggle something to allow the player to add another ball.
How do i find the coordinates of a resource?
I'm making a game and I started by making some framework just for me to learn and test different things within it the game. In this game, I have a randomly generated tilemap with the resources dirt, grass, water, and coal. In the code, there are some other irrelevant resources but what I'm trying to do is find the coordinates of a specific resource in the game. What I plan on doing with this is say the resource is a wall and there is a wall below it and next to it the texture for the middle wall will turn into a corner piece. My issue is I don't know how to find the coordinates. Can someone please help me, I honestly am not sure what I'm doing but I'm trying to learn. Heres my code: import pygame, sys import Sprites import random from pygame.locals import * pygame.init() fpsClock = pygame.time.Clock() cloudx = -200 cloudy = 0 infoObject = pygame.display.Info() DIRT = 0 GRASS = 1 WATER = 2 COAL = 3 CLOUD = 4 WALL = 5 controls = { DIRT : 49, GRASS: 50, WATER: 51, COAL : 52, WALL : 53 } infoObject = pygame.display.Info() w = infoObject.current_w h = infoObject.current_h TILESIZE = 40 MAPWIDTH = 15 MAPHEIGHT = 15 WHITE = (255,255,255) BLACK = (0,0,0) resources = [DIRT, GRASS, WATER, COAL] textures = { DIRT : pygame.image.load('Sprites/Dirt.png'), GRASS : pygame.image.load('Sprites/tile130.png'), WATER : pygame.image.load('Sprites/Water.png'), COAL : pygame.image.load('Sprites/Coal.png'), CLOUD : pygame.image.load('Sprites/Cloud.png'), WALL : pygame.image.load('Sprites/Swall.png') } playerPos = [0,0] inventory = { DIRT : 0, GRASS : 0, WATER : 0, COAL : 0, WALL : 10, } tilemap = [[DIRT for w in range(MAPWIDTH)] for h in range(MAPHEIGHT)] DISPLAYSURF = pygame.display.set_mode((MAPWIDTH*TILESIZE,MAPHEIGHT*TILESIZE + 50)) pygame.display.set_caption('M I N E C R A F T -- 2D') pygame.display.set_icon(pygame.image.load('Sprites/player.png')) PLAYER = pygame.image.load('Sprites/Player.png').convert_alpha() for rw in range(MAPHEIGHT): for cl in range(MAPWIDTH): randomNumber = random.randint(0,15) if randomNumber == 0: tile = COAL elif randomNumber == 1 or randomNumber == 2: tile = WATER elif randomNumber >= 3 and randomNumber <=7: tile = GRASS else: tile = DIRT tilemap[rw][cl] = tile INVFONT = pygame.font.Font('freesansbold.ttf', 18) print(tilemap) while True: currentTile = tilemap[playerPos[1]][playerPos[0]] DISPLAYSURF.fill(BLACK) for event in pygame.event.get(): # print(event) if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: for key in controls: if (event.key == controls[key]): if inventory[key] > 0: inventory[key] -=1 inventory[currentTile] += 1 tilemap[playerPos[1]][playerPos[0]] = key if(event.key == K_RIGHT) and playerPos[0] < MAPWIDTH - 1: playerPos[0]+=1 elif(event.key == K_LEFT) and playerPos[0] > 0: playerPos[0]-=1 elif(event.key == K_DOWN) and playerPos[1] < MAPHEIGHT - 1: playerPos[1]+=1 elif(event.key == K_UP) and playerPos[1] > 0: playerPos[1]-=1 if event.key == K_SPACE: currentTile = tilemap[playerPos[1]][playerPos[0]] inventory[currentTile] += 1 tilemap[playerPos[1]][playerPos[0]] = DIRT for row in range(MAPHEIGHT): for column in range(MAPWIDTH): DISPLAYSURF.blit(textures[tilemap[row][column]],(column*TILESIZE, row*TILESIZE, TILESIZE, TILESIZE)) DISPLAYSURF.blit(PLAYER,(playerPos[0]*TILESIZE,playerPos[1]*TILESIZE)) DISPLAYSURF.blit(textures[CLOUD].convert_alpha(),(cloudx,cloudy)) cloudx +=1 if cloudx > MAPWIDTH*TILESIZE: cloudy = random.randint(0, MAPHEIGHT*TILESIZE) cloudx = -200 placePosition = 10 for item in resources: DISPLAYSURF.blit(textures[item],(placePosition, MAPHEIGHT*TILESIZE+10)) placePosition+=50 textObj = INVFONT.render(str(inventory[item]), True, WHITE, BLACK) DISPLAYSURF.blit(textObj,(placePosition, MAPHEIGHT*TILESIZE+20)) placePosition += 50 pygame.display.update() fpsClock.tick(24) for x in range(MAPWIDTH): for y in range(MAPHEIGHT): if tilemap[x][y] == WALL: pos = tilemap[x][y] if tilemap[pos[1]][pos[0]-1] == WALL: print('I DID IT') pygame.display.update() Edit: My current code has been updated, the added part is at the very end
If you want to find the coordinates of a specific tile, then it's going to take some work. Namely, your program will have to search through every tile and compare it to see if it's a WALL tile. i.e. for x in range(MAPWIDTH): for y in range(MAPHEIGHT): if tilemap[y][x] == WALL: # Do something here... However, this is extremely inefficient. Though it may not be a problem when your map is only 15 by 15, it will start to eat up your performance if you expand the map. It might be wiser to only check the area that's being shown on the screen. After all, you're only trying to work out how the tile should be displayed - it doesn't matter otherwise. for x in range(30): # Replace with whatever number of tiles is displayed horizontally on the screen, times two for y in range(30): # Do the same here if tilemap[y][x] == WALL: # Do something here Just a quick note, though - if this is only for display, a far better solution for this is to define multiple WALL tiles. You could do this by just making constants like WALL_UPPER_RIGHT, but it would be a much better idea to make it in the form of a list. WALL_TILES = [[5, 6, 7], [8, 9, 10], [11, 12, 13]] # WALL_TILES is a 2D list in the format: # upper left upper middle upper right # middle left middle middle middle right # lower left lower middle lower right Then, you could just address something like WALL_UPPER_RIGHT with WALL_TILES[0][2]. When you have your multiple wall tiles, you can just change the type of tile whenever it or a tile next to it gets changed. ADDED: To check if surrounding tiles are also wall tiles, you could check the tiles whose x-position and y-position are both within 1 of the center tile. For example, you could check tilemap[pos[1]][pos[0]-1].
Pygame 2d tile scrolling edges don't load
Im trying to make a 2d game in pygame that kinda works like pokemon. Ive gotten really stuck on a problem now that I dont know how to solve. When I move my character I scroll the map instead so the player stays centered. I've created an "animation" by offsetting the distance by 2 pixels at a time instead of moving the full tile size so I get smooth movemen. The problem I have is that when I move, the screen doesn't load the new tiles in the edges that i'm moving towards so the edges end up a white space until i've completed the full animation. I'll link my code and hopefully someone can help me :) TILESIZE = 32 MAP_WIDTH = 25 MAP_HEIGHT = 25 class Player(pygame.sprite.Sprite): def __init__(self, color, width, height): # Call the parent class (Sprite) constructor super().__init__() self.name = "Player" self.width = width self.height = height self.image = pygame.Surface([width, height]) self.image.fill(color) self.rect = self.image.get_rect() self.rect.x = int(TILESIZE * (MAP_WIDTH / 2)) - TILESIZE / 2 self.rect.y = int(TILESIZE * (MAP_HEIGHT / 2)) - TILESIZE / 2 class World: def __init__(self): self.shiftX = 0 self.shiftY = 0 self.tile_map = [ [DIRT for w in range(MAP_WIDTH)] for h in range(MAP_HEIGHT)] for row in range(MAP_HEIGHT): for column in range(MAP_WIDTH): try: if real_map[row + self.shiftY][column + self.shiftX] == 0: tile = DIRT elif real_map[row + self.shiftY][column + self.shiftX] == 1: tile = GRASS elif real_map[row + self.shiftY][column + self.shiftX] == 2: tile = WATER else: tile = DIRT self.tile_map[row][column] = tile except: self.tile_map[row][column] = WATER def shiftWorld(self): for row in range(MAP_HEIGHT): for column in range(MAP_WIDTH): try: if real_map[row + self.shiftY][column + self.shiftX] == 0: tile = DIRT elif real_map[row + self.shiftY][column + self.shiftX] == 1: tile = GRASS elif real_map[row + self.shiftY][column + self.shiftX] == 2: tile = WATER else: tile = DIRT self.tile_map[row][column] = tile except: self.tile_map[row][column] = WATER def okToMove(self, key): if key[K_w]: if self.tile_map[int(MAP_WIDTH/2 - 1)][int(MAP_HEIGHT/2)] != 2: return True elif key[K_s]: if self.tile_map[int(MAP_WIDTH/2 + 1)][int(MAP_HEIGHT/2)] != 2: return True elif key[K_a]: if self.tile_map[int(MAP_WIDTH/2)][int(MAP_HEIGHT/2) - 1] != 2: return True elif key[K_d]: if self.tile_map[int(MAP_WIDTH/2)][int(MAP_HEIGHT/2) + 1] != 2: return True def start_game(): pygame.init() clock = pygame.time.Clock() #HÄR KAN VI MÅLA UPP MER #SCREEN = pygame.display.set_mode((MAP_WIDTH*TILESIZE, MAP_HEIGHT*TILESIZE)) world = World() SCREEN = pygame.display.set_mode((TILESIZE * (MAP_WIDTH-2), TILESIZE * (MAP_HEIGHT-4))) running = True player = Player(BLACK, 32, 32) sprites = pygame.sprite.Group() sprites.add(player) movement = 0 offsetY = 0 offsetX = 0 animation_north = False animation_south = False animation_west = False animation_east = False while running: for event in pygame.event.get(): if event.type==QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN: #Get keyinput and do whatever needs to be done key = pygame.key.get_pressed() if key[K_ESCAPE]: pygame.quit() sys.exit() if animation_east or animation_north or animation_south or animation_west: pass else: if key[K_w]: okToMove = world.okToMove(key) if okToMove == True: animation_north = True else: pass elif key[K_a]: okToMove = world.okToMove(key) if okToMove == True: animation_west = True elif key[K_s]: okToMove = world.okToMove(key) if okToMove == True: animation_south = True elif key[K_d]: okToMove = world.okToMove(key) if okToMove == True: animation_east = True if animation_north == True: if movement == 32: movement = 0 world.shiftY -= 1 world.shiftWorld() offsetY = 0 animation_north = False else: offsetY += 4 movement += 4 if animation_south == True: if movement == 32: movement = 0 world.shiftY += 1 world.shiftWorld() offsetY = 0 animation_south = False intY = 0 else: offsetY -= 4 movement += 4 if animation_west == True: if movement == 32: movement = 0 world.shiftX -= 1 world.shiftWorld() offsetX = 0 animation_west = False else: offsetX += 4 movement += 4 if animation_east == True: if movement == 32: world.shiftX += 1 world.shiftWorld() movement = 0 offsetX = 0 animation_east = False else: offsetX -= 4 movement += 4 SCREEN.fill(WHITE) for row in range(MAP_HEIGHT): for column in range(MAP_WIDTH): SCREEN.blit(textures[world.tile_map[row][column]], (column*TILESIZE + offsetX, row*TILESIZE + offsetY)) sprites.draw(SCREEN) pygame.display.update() pygame.display.flip() clock.tick(60) start_game()
I am writing a similar game and I will share my logic with you. my blocks are 32x32 so each block is 32 pixesl. The outer border is the sprites screen and the inner square is the monitor. You always have one sprite extra on all sides of the screen. now if you count the pixel movement on any side of the screen it's easy for you to keep track of when you need to draw the next row or column of sprites but not that they are always DRAWN OFF SCREEN. if my pixel movement is -8 (left movement) I draw a column of sprites on the right side just on the border os the screen but OUTSIDE the visible area. Same goes for the other side. Here is some code from my program. This is the sprite adding code. def add_sprites(self): """sprites are added to the group which appear on screen right. the column number is the value in ColDrawn. We selct columns from the list according to this value. Once the end of the column list is reached we start again from the first one. We cycle thru the list depending on the NumCycle[0] value.""" if self.ColDrawn < self.Columns_in_Dungeon - 1: self.ColDrawn += 1 else: # all the columns drawn so increment the flag self.ColDrawn = 0 self.NumCycle[1] += 1 if self.NumCycle[1] >= self.NumCycle[0]: # if the flag is equal to the number of cycles the screen is scrolled then set numcycle[2] to True self.NumCycle[2] = True else: # screen can be scrolled spritecol = self.all_wall_sprite_columns_list[self.ColDrawn] self.wallspritegroup.add(spritecol) # add column of sprites to the sprite group return and here is the sprite removing code. def remove_sprites(self): """sprites are removed from the group as they exit from screen left.""" for sprt in self.wallspritegroup: # remove_basic sprites that move_basic off screen on left if sprt.rect.x <= -48: sprt.rect.x = self.screenw # reset the x position and sprt.kill() #spritegrp.remove_basic(sprt) # remove_basic the sprite from the sprite group return The code is quite easy to follow as I have commented them. Hope this helps.
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.