Pygame: Colliding Rectangle on multiple other rectangles - python
I am attempting to create a game in which a block moves back and forth until the player presses space. Upon which, the block jumps to the next line up and stops.
Currently i am having problems with the collision code.
The error being thrown up by the shell is:
if doRectsOverlap(j['rect'], floors['line']):
TypeError: list indices must be integers, not str
I am stuck with understanding where my code has gone wrong. My knowledge of how python works is very limited.
There is also code i have commented out to do with the floor moving dowards when the player jumps. it has been commented out until i can get the collisions working, but still included
Code Below:
import pygame, sys, time
from pygame.locals import *
def doRectsOverlap(rect1, rect2):
for a, b in [(rect1, rect2), (rect2, rect1)]:
# Check if a's corners are inside b
if ((isPointInsideRect(a.left, a.top, b)) or
(isPointInsideRect(a.left, a.bottom, b)) or
(isPointInsideRect(a.right, a.top, b)) or
(isPointInsideRect(a.right, a.bottom, b))):
return True
return False
def isPointInsideRect(x, y, rect):
if (x > rect.left) and (x < rect.right) and (y > rect.top) and (y < rect.bottom):
return True
else:
return False
# set up pygame
pygame.init()
mainClock = pygame.time.Clock()
# set up the window
WINDOWWIDTH = 480
WINDOWHEIGHT = 800
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
pygame.display.set_caption('Jumper')
#Directions
LEFT = 4
RIGHT = 6
UP = 8
DOWN = 2
STILL = 5
#blocks location for jumping
#BLOCKLOCY = 700
#Binary for stopping movement
#STOPPER = 0
MOVESPEED = 1
# set up the colors
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
j = {'rect':pygame.Rect(240, 700, 20, 20), 'color':GREEN, 'dir':LEFT, 'jump':STILL}
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
# run the game loop
while True:
# check for the QUIT event
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# draw the black background onto the surface
windowSurface.fill(BLACK)
# move the block data structure
if j['dir'] == LEFT:
j['rect'].left -= MOVESPEED
if j['dir'] == RIGHT:
j['rect'].left += MOVESPEED
if j['jump'] == UP:
j['rect'].bottom -= MOVESPEED
#BLOCKLOCY -= MOVESPEED
if j['rect'].left < 0:
j['dir'] = RIGHT
if j['rect'].left > WINDOWWIDTH-j['rect'].width:
j['dir'] = LEFT
if event.type == KEYDOWN:
if event.key == K_SPACE:
j['jump'] = UP
if doRectsOverlap(j['rect'], floors['line']):
j['jump'] = STILL
#Floor controll code for moving level - not working currently
# for f in floors:
#if f['dir'] == DOWN:
# f['line'].y += MOVESPEED
# if event.type == KEYDOWN:
# if event.key == K_SPACE:
# f['dir'] = DOWN
# if f['line'].top == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
#if f['line'].bottom == BLOCKLOCY:
# f['dir'] = STILL
# STOPPER = 1
# draw the block onto the surface
pygame.draw.rect(windowSurface, j['color'], j['rect'])
pygame.draw.rect(windowSurface, f['color'], f['line'])
# draw the window onto the screen
pygame.display.update()
mainClock.tick(40)
You are creating floors as a list:
f1 = {'line':pygame.Rect(0,720,480,2), 'color':GREEN, 'dir':STILL}
f2 = {'line':pygame.Rect(0,650,480,2), 'color':GREEN, 'dir':STILL}
floors = [f1,f2]
So when you call:
if doRectsOverlap(j['rect'], floors['line']):
j['jump'] = STILL
You're message is telling you that you need an index as an int:
for n in range(len(floors)):
if doRectsOverlap(j['rect'], floors[n]['line']):
j['jump'] = STILL
Related
issues with checking if my images collided in pygame [duplicate]
This question already has an answer here: Why is my collision test always returning 'true' and why is the position of the rectangle of the image always wrong (0, 0)? (1 answer) Closed 1 year ago. So I'm trying to check im my bird images are touching my could images and if they are to print print('Collided1!'). My Issue is that print('Collided1!') goes off no matter what and is not checking whether the images are touching. colliderect was the solution I found online but I don't seem to know how it works because this is not working. Do You Know how to fix this? and check whether my images are touching or not? from random import randint import pygame, sys import random import time pygame.init() pygame.display.set_caption('Lokaverkefni') DISPLAYSURF = pygame.display.set_mode((1224, 724)) fpsClock = pygame.time.Clock() FPS = 60 a = 1 b = 1 c = 15 x = 100 y = 480 start = 0 score = 0 landX = 1205 totalScore = 0 level = 'low' directionForBird = 'none' WHITE = (255, 255, 255) BLACK = (0, 0, 0) BASICFONT = pygame.font.Font('freesansbold.ttf', 30) background_resized = pygame.image.load('sky.jpg') background = pygame.transform.scale(background_resized, (1224, 724)) bird1 = pygame.image.load('bird1.png') bird1_resized = pygame.transform.scale(bird1, (170, 150)) bird1Surface = bird1_resized.get_rect() bird2 = pygame.image.load('bird2.png') bird2_resized = pygame.transform.scale(bird2, (170, 150)) bird2Surface = bird2_resized.get_rect() cloudsList = ['cloud1.png', 'cloud2.png', 'cloud3.png', 'cloud4.png'] clouds = random.choice(cloudsList) cloud = pygame.image.load(clouds) cloud_resized = pygame.transform.scale(cloud, (352, 352)) cloudSurface = cloud_resized.get_rect() while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() elif event.type == KEYDOWN: if level == 'low': if (event.key == K_SPACE ): directionForBird = 'up' level = 'high' FPS += 2 c += 1 if directionForBird == 'up': y -= 10 if y == 10: directionForBird = 'down' if directionForBird == 'down': y += 10 if y == 480: directionForBird = 'none' if a == 1: DISPLAYSURF.blit(background, (0, 0)) DISPLAYSURF.blit(bird1_resized, (x, y)) DISPLAYSURF.blit(cloud_resized, (landX, 300)) b += 1 if b == c: a += 1 if a == 2: DISPLAYSURF.blit(background, (0, 0)) DISPLAYSURF.blit(bird2_resized, (x, y)) DISPLAYSURF.blit(cloud_resized, (landX, 300)) b -= 1 if b == 1: a -= 1 start += 1 if start == 100: start -= 1 directionForLand = 'left' if directionForLand == 'left': landX -= 15 if landX == -550: landX = 1205 level = 'low' clouds = random.choice(cloudsList) cloud = pygame.image.load(clouds) cloud_resized = pygame.transform.scale(cloud, (352, 352)) score += 1 if score == 30: score = 0 totalScore += 1 scoreText = BASICFONT.render('Stig : %s' % (totalScore), True, (BLACK)) scoreRect = scoreText.get_rect() scoreRect.topleft = (1070, 10) DISPLAYSURF.blit(scoreText, scoreRect) # This is Supossed to Be what checks if the bird images # colide with the cloud images if bird1Surface.colliderect(cloudSurface): print('Collided1!') if bird2Surface.colliderect(cloudSurface): print('Collided1!') pygame.display.update() fpsClock.tick(FPS)
bird1Surface, bird2Surface and cloudSurface always have an upper left of (0,0), so they are always on top of each other.. You don't change the rectangles when you move the birds. You need to track the bird x,y and the cloud x,y, and construct new rectangles with the current x,y and the known width and height before you do the collision check.
Pygame - Fix issue with pause menu? [duplicate]
I've developed a Python code and am looking for improvements and how to add a pause option. I repeat the exact same lines one after another although I don't know an easier way to do it. import math, pygame, random, sys, turtle from itertools import cycle from datetime import datetime from pygame import gfxdraw from pygame.locals import * def print_text(surface, font, text, surf_rect, x = 0, y = 0, center = False, color = (255,215,0)): if not center: textimage = font.render(text, True, color) surface.blit(textimage, (x, y)) else: textimage = font.render(text, True, color) text_rect = textimage.get_rect() x = (surf_rect.width // 2) - (text_rect.width // 2 ) surface.blit(textimage, (x, y)) def game_is_over(surface, font, ticks): timer = ticks surf_rect = surface.get_rect() surf_height = surf_rect.height surf_width = surf_rect.width print_text(screen, font, "Y O U G O T Y E E T E D (Game Over)", surf_rect, y = 260,\ center = True) pygame.display.update() while True: ticks = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() if ticks > timer + 3000: break def next_level(level): level += 1 if level > 6: level = 6 return level #The Level Creator def load_level(level): invaders, colors = [], [] start_intx, end_intx, increment_intx = 85, 725, 40 start_inty, end_inty, increment_inty = 60, 60, 30 end_inty = end_inty + level * 30 # 30 being the number of rows / intruders color_val = 256 / end_inty #For Colour Repetition for x in range(start_intx, end_intx, increment_intx): for y in range(start_inty, end_inty, increment_inty): invaders.append(pygame.Rect(x, y, 30, 15)) colors.append(((x * 0.35) % 256, (y * color_val) % 256)) return invaders, colors, len(invaders) def draw_title_invader(): rect = Rect(285,247,230,115)#INVATOR rect2 = Rect(0,0,230,115) rect3 = Rect(340,120,120,128)#TOP OF HAT rect4 = Rect(300,200,200,48)#BOT OF HAT rect5 = Rect(340,182,120,18)#LINE IN HAT rect_width = 230 a = 175 b = 55 pygame.draw.rect(backbuffer, MGOLD,rect) #The Left Eye in Title Screen pygame.draw.circle(backbuffer,(0,255,255), (rect.x+46,rect.y+30), 23) #The Right Eye in Title Screen pygame.draw.circle(backbuffer,(0,255,255),(rect.x+rect_width-46,rect.y+30)\ ,23) #The Left Side Mouth in Title Screen pygame.draw.line(backbuffer, RED, (rect.x+46, rect.y+92),\ (rect.x + 115, rect.y + 61), 2) #The Right Side Mouth in Title Screen pygame.draw.line(backbuffer, RED, (rect.x+rect_width-46,\ rect.y+92), (rect.x+rect_width-115,\ rect.y+61), 2) #The Right Eye pygame.draw.circle(backbuffer,RED,(rect.x+rect_width-115,rect.y+65)\ ,23) #The Hat pygame.draw.rect(backbuffer, DIMGRAY,(340,120,120,128)) pygame.draw.rect(backbuffer, DIMGRAY,(300,200,200,48)) pygame.draw.rect(backbuffer, WHITE,(340,182,120,18)) def draw_bonus_invader(i, bonus_color, bx, bonus_x): x, y = bonus_invader.x, bonus_invader.y pygame.draw.circle(backbuffer, bonus_color, (x+bx, y+7), 2) if i == 0: pygame.draw.circle(backbuffer, bonus_color, (bonus_invader.x+bx,bonus_invader.y+7),2) if i == 1: pygame.draw.circle(backbuffer, bonus_color, (bonus_invader.x+bx,bonus_invader.y+7),2) if i == 2: pygame.draw.circle(backbuffer, bonus_color, (bonus_invader.x+bx,bonus_invader.y+7),2) if i == 3: pygame.draw.circle(backbuffer, bonus_color, (bonus_invader.x+bx,bonus_invader.y+7),2) if i == 4: pygame.draw.circle(backbuffer, bonus_color, (bonus_invader.x+bx,bonus_invader.y+7),2) if i == 5: bx = next(bonus_x) def draw_invader(backbuffer, rect, a, b, animate_invaders, ticks,\ animation_time): invader_width = 30 #THe Intruder In Game pygame.draw.rect(backbuffer, MGOLD, rect) #CONSOLE GRAY pygame.draw.rect(backbuffer, DIMGRAY,(0,510,800,110)) #Left Eye in game pygame.gfxdraw.filled_circle(backbuffer, rect.x + 6, rect.y + 4, 3, \ RED) #Right EYe in game pygame.gfxdraw.filled_circle(backbuffer, rect.x + invader_width - 7,\ rect.y + 4, 3, RED) #The draw animation (if needed) if animate_invaders: pygame.gfxdraw.filled_trigon(backbuffer, rect.x+6, rect.y + 12,\ rect.x + 14, rect.y + 4, rect.x +\ invader_width - 7, rect.y + 12, RED) else: #The Left Side of the mouth pygame.gfxdraw.line(backbuffer, rect.x + 6, rect.y + 12,\ rect.x + 15, rect.y + 8, RED) #The Right Side of the mouth pygame.gfxdraw.line(backbuffer, rect.x + invader_width - 7,\ rect.y + 12, rect.x + invader_width - 15,\ rect.y + 8, RED) if ticks > animation_time + 200: animate_invaders = False return animate_invaders pygame.init() pygame.mixer.init() # not always called by pygame.init() screen = pygame.display.set_mode((800, 600)) pygame.display.set_caption("Yeet The Intruders") fpsclock = pygame.time.Clock() #get screen metrics the_screen = screen.get_rect() screen_width = the_screen.width screen_height = the_screen.height backbuffer = pygame.Surface((the_screen.width, the_screen.height)) # fonts font1 = pygame.font.SysFont(None, 30) font2 = pygame.font.SysFont("Impact", 54) font3 = pygame.font.SysFont("Impact", 36) # User event frequencies RELOAD_SPEED = 400 MOVE_SIDEWAYS = 1000 MOVE_DOWN = 1000 BONUS_FREQ = 10000 INV_SHOOT_FREQ = 500 # create user events move_invaders_sideways = pygame.USEREVENT + 1 move_invaders_down = pygame.USEREVENT + 2 reload = pygame.USEREVENT + 3 invader_shoot = pygame.USEREVENT + 4 bonus = pygame.USEREVENT + 5 # event timers pygame.time.set_timer(move_invaders_down, 0) pygame.time.set_timer(move_invaders_sideways, MOVE_SIDEWAYS) pygame.time.set_timer(reload, RELOAD_SPEED) pygame.time.set_timer(invader_shoot, INV_SHOOT_FREQ) pygame.time.set_timer(bonus, BONUS_FREQ) #List of Colours used BLACK = (0,0,0) WHITE = (255,255,255) RED = (255,0,0) GREEN = (0,255,0) BLUE = (0,0,255) YELLOW = (255,255,0) DIMGRAY = (105,105,105) MGOLD = (212,175,55) shots, invader_shots, inv_shot_colors, bonus_invaders = [], [], [], [] #MY Space Ship player = Rect(380,578,42,20) player_gun = Rect(player.x + 18,player.y - 4, 6, 4) # make screen rect for purposes of text-centering etc the_screen = screen.get_rect() # invader animation variables animation_time = 0 animate_invaders = False invader_width = 30 invader_height = 15 # flashing text vars the_text = cycle(["Press Enter To Play, Yeet Master...", ""]) insert = next(the_text) flash_timer = 0 # flashing bonus item vars y1,y2,y3,y4,y5,y6 = (255,255,0), (225,225,0), (195,195,0), (165,165,0),\ (135,135,0), (105,105,0) bonus_colors = cycle([y1,y2,y3,y4,y5,y6]) bonus_color = next(bonus_colors) bonus_x = cycle([4,11,18,25,32,39]) # change draw x coord bonus_timer = 0 # used to control frequency of changes # vars for moving invaders down move_right, move_down, reloaded = True, True, True vert_steps = 0 side_steps = 0 moved_down = False invaders_paused = False invaders = 0 # prevents error until list is created initial_invaders = 0 # use to manage freq of inv shots as invaders removed shoot_level = 1 # manage freq of shots # various gameplay variables game_over = True score = 0 lives = 2 level = 0 playing = False # event loop while True: ticks = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() if event.type == KEYUP: if event.key == pygame.K_1 and not game_over: print("Next level") if event.type == invader_shoot and not game_over: i = random.randint(0, len(invaders)-1) shot_from = invaders[i] a, b = colors[i] invader_fired = True invader_shots.append(Rect(shot_from.x, shot_from.y, 5, 7)) inv_shot_colors.append(RED) if event.type == reload and not game_over: reloaded = True pygame.time.set_timer(reload, 0) if event.type == move_invaders_sideways and not game_over: if move_right: for invader in invaders: invader.move_ip(10,0) side_steps += 1 else: for invader in invaders: invader.move_ip(-10,0) side_steps -= 1 if side_steps == 6 or side_steps == -6: if vert_steps <= 31: # and not moved_down pygame.time.set_timer(move_invaders_sideways, 0) pygame.time.set_timer(move_invaders_down, MOVE_DOWN) # keep invaders moving horizontally after 31 down movements else: move_right = not move_right if event.type == move_invaders_down and not game_over: #for i in range(20): print("down event") move_right = not move_right animate_invaders = True animation_time = ticks # reset move_sideways timer pygame.time.set_timer(move_invaders_sideways, MOVE_SIDEWAYS) # cancel move_down timer pygame.time.set_timer(move_invaders_down, 0) for invader in invaders: invader.move_ip(0,10) vert_steps += 1 if event.type == bonus and not game_over: #a = Rect(769,20,45,15) bonus_invaders.append(Rect(797,20,45,15)) # keyboard polling pressed = pygame.key.get_pressed() if pressed[K_ESCAPE]: pygame.quit(), sys.exit() elif pressed[K_RETURN]: if game_over: game_over = False elif pressed[K_d] or pressed[K_RIGHT]:player.move_ip((8, 0)) #player_gun.move_ip((8,0)) elif pressed[K_a] or pressed[K_LEFT]: player.move_ip((-8, 0)) if pressed[K_SPACE]: if reloaded: reloaded = False # create timeout of RELOAD_SPEED pygame.time.set_timer(reload, RELOAD_SPEED) # shrink copy of player rect to imitate a missile missile = player.copy().inflate(-38, -10) # spawn missile higher to ensure appears missile fired from 'gun' # when the ship is moving horizontally missile.y -= 9 shots.append(missile) #missile_sound.play() backbuffer.fill(BLACK) if not game_over: playing = True if level == 0: level = next_level(level) invaders, colors, initial_invaders = load_level(level) move_right, move_down, reloaded = True, True, True vert_steps = 0 side_steps = 0 moved_down = False invaders_paused = False pygame.time.set_timer(invader_shoot, 500) shoot_level = 1 for shot in invader_shots: shot.move_ip((0,random.randint(5,11))) if not backbuffer.get_rect().contains(shot): i = invader_shots.index(shot) del invader_shots[i] del inv_shot_colors[i] if shot.colliderect(player) and shot.y < the_screen.height -10: lives -= 1 if lives < 0: lives = 0 game_over = True i = invader_shots.index(shot) del invader_shots[i] del inv_shot_colors[i] for shot in shots: shot.move_ip((0, -8)) for inv_shot in invader_shots: if inv_shot.colliderect(shot): shots.remove(shot) i = invader_shots.index(inv_shot) del invader_shots[i] del inv_shot_colors[i] for b_invader in bonus_invaders: if b_invader.colliderect(shot): shots.remove(shot) i = bonus_invaders.index(b_invader) del bonus_invaders[i] score += 1 if not backbuffer.get_rect().contains(shot): shots.remove(shot) else: hit = False for invader in invaders: if invader.colliderect(shot): score += 1 hit = True i = invaders.index(invader) del invaders[i] del colors[i] if hit: shots.remove(shot) # move bonus invader for bonus_invader in bonus_invaders: bonus_invader.move_ip((-4,0 )) ## if not screen.get_rect().contains(bonus_invader): ## bonus_invaders.remove(bonus_invader) if bonus_invader.x < -55: bonus_invaders.remove(bonus_invader) # check if all invaders killed, if so, move to next level if len(invaders) == 0: level = next_level(level) invaders, colors, initial_invaders = load_level(level) move_right, move_down, reloaded = True, True, True vert_steps = 0 side_steps = 0 moved_down = False invaders_paused = False pygame.time.set_timer(invader_shoot, 500) shoot_level = 1 # adjust shot freq when invader numbers decrease if len(invaders) < initial_invaders*.75 and shoot_level == 1: pygame.time.set_timer(invader_shoot, 750) shoot_level = 2 elif len(invaders) < initial_invaders*.5 and shoot_level == 2: pygame.time.set_timer(invader_shoot, 1000) shoot_level = 3 elif len(invaders) < initial_invaders*.25 and shoot_level == 3: pygame.time.set_timer(invader_shoot, 1500) shoot_level = 4 # draw invaders for rect, (a, b) in zip(invaders, colors): animate_invaders = draw_invader(backbuffer, rect, a, b,\ animate_invaders, ticks, \ animation_time) # draw bonus invaders if ticks > bonus_timer + 169: bonus_timer = ticks # change colors every 169ms approx for bonus_invader in bonus_invaders: pygame.draw.rect(backbuffer, (0,0,0,0), bonus_invader) pygame.draw.ellipse(backbuffer,MGOLD,bonus_invader) for i in range(6): bonus_color = next(bonus_colors) bx = next(bonus_x) draw_bonus_invader(i, bonus_color, bx, bonus_x) # draw space ship shots for shot in shots: pygame.draw.rect(backbuffer, GREEN, shot) # draw invader shots for shot, color in zip(invader_shots, inv_shot_colors): pygame.draw.rect(backbuffer, color, shot) #update 'gun' position and draw ship/gun #player_gun = Rect(player.x, player.y, 6, 4) player_gun.x = player.x+18 pygame.draw.rect(backbuffer, (204,0,255), player) pygame.draw.rect(backbuffer, (0,204,255), player_gun) player.clamp_ip(backbuffer.get_rect()) print_text(backbuffer, font1, "Intruders Rekt#: {}".format(score),\ the_screen, x=0, y=520) print_text(backbuffer, font1, "Hearts#: {}".format(lives), the_screen,\ x=0, y=550) print_text(backbuffer, font1, "Round#: {}".format(level), the_screen,\ x=0, y=580) if game_over: if playing: game_is_over(backbuffer, font2, ticks) playing = False level = 0 lives = 2 score = 0 shots, invader_shots, inv_shot_colors, bonus_invaders = [], [], [], [] print_text(backbuffer, font2, "_/¯Yeet The Intruders¯\_", the_screen, y=5,\ center=True) draw_title_invader() if ticks > flash_timer + 800: # "press to play" flashing text insert = next(the_text) flash_timer = ticks print_text(backbuffer, font3, insert, the_screen, y =\ the_screen.height-40, center=True) screen.blit(backbuffer, (0,0)) pygame.display.update() fpsclock.tick(30)
Your code is quite large, but to pause the game is very general task: Add a pause state. Toggle the pause state on an certain event, e.g. when the p key is pressed. Skip the game processing if pauseis stated. e,.g. pause = False # pause state while True: ticks = pygame.time.get_ticks() for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() if event.type == KEYUP: if event.key == pygame.K_1 and not game_over: print("Next level") # toggle pause if "p" is pressed if event.key == pygame.K_p: pause = not pause # [...] if pause: # [...] draw pause screen pass elif not game_over: # <--- elif is important playing = True # [...] screen.blit(backbuffer, (0,0)) pygame.display.update() fpsclock.tick(30)
How to rotate pymunk joints at will?
I'm trying to create a walking spider like this: I considered using a SimpleMotor at the pink and red joints and control them using the rate function. But when I tried, I get an error that the function is not callable. self.motorJoint1.rate(0.0) TypeError: 'float' object is not callable I don't see any other functions in the pymunk API that allow controlling the joints at will. Is there really no function or am I missing something? Basically in the run loop I want to specify rotations to the joints at certain points of time, to not just make the spider walk, but to eventually be able to use Neural Networks to allow it to experiment with various configurations of leg positions and figure out which ones can make it walk: angle1 = 30 angle2 = 10 redJoint1.rotate(angle1) pinkJoint2.rotate(angle2) if angle1 < 50: angle1 = angle1 + 1 Is it possible at all to achieve such a level of control over joints using Pymunk? To be able to stop moving the legs (without needing to put the body to sleep), or to rotate the leg joints to whatever angle the spider 'wishes to' at any point in time? Sample code would be a great help.
From the servo example I took a hint and implemented this basic leg: import sys import pygame from pygame.locals import USEREVENT, QUIT, KEYDOWN, KEYUP, K_s, K_r, K_q, K_ESCAPE, K_UP, K_DOWN, K_RIGHT, K_LEFT from pygame.color import THECOLORS import pymunk from pymunk import Vec2d import pymunk.pygame_util class Simulator(object): def __init__(self): self.display_flags = 0 self.display_size = (600, 600) self.space = pymunk.Space() self.space.gravity = (0.0, -1900.0) #self.space.damping = 0.999 # to prevent it from blowing up. # Pymunk physics coordinates start from the lower right-hand corner of the screen. self.ground_y = 100 ground = pymunk.Segment(self.space.static_body, (5, self.ground_y), (595, self.ground_y), 1.0) ground.friction = 1.0 self.space.add(ground) self.screen = None self.draw_options = None def reset_bodies(self): for body in self.space.bodies: if not hasattr(body, 'start_position'): continue body.position = Vec2d(body.start_position) body.force = 0, 0 body.torque = 0 body.velocity = 0, 0 body.angular_velocity = 0 body.angle = body.start_angle def draw(self): self.screen.fill(THECOLORS["white"])### Clear the screen self.space.debug_draw(self.draw_options)### Draw space pygame.display.flip()### All done, lets flip the display def main(self): pygame.init() self.screen = pygame.display.set_mode(self.display_size, self.display_flags) width, height = self.screen.get_size() self.draw_options = pymunk.pygame_util.DrawOptions(self.screen) def to_pygame(p): return int(p.x), int(-p.y+height) #Small hack to convert pymunk to pygame coordinates def from_pygame(p): return to_pygame(p) clock = pygame.time.Clock() running = True font = pygame.font.Font(None, 16) # Create the spider chassisXY = Vec2d(self.display_size[0]/2, self.ground_y+100) chWd = 70; chHt = 50 chassisMass = 10 legWd_a = 50; legHt_a = 5 legWd_b = 100; legHt_b = 5 legMass = 1 relativeAnguVel = 0 #---chassis chassis_b = pymunk.Body(chassisMass, pymunk.moment_for_box(chassisMass, (chWd, chHt))) chassis_b.position = chassisXY chassis_shape = pymunk.Poly.create_box(chassis_b, (chWd, chHt)) chassis_shape.color = 200, 200, 200, 100 print("chassis position");print(chassis_b.position) #---first left leg a leftLeg_1a_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_a, legHt_a))) leftLeg_1a_body.position = chassisXY - ((chWd/2)+(legWd_a/2), 0) leftLeg_1a_shape = pymunk.Poly.create_box(leftLeg_1a_body, (legWd_a, legHt_a)) leftLeg_1a_shape.color = 255, 0, 0, 100 #---first left leg b leftLeg_1b_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_b, legHt_b))) leftLeg_1b_body.position = leftLeg_1a_body.position - ((legWd_a/2)+(legWd_b/2), 0) leftLeg_1b_shape = pymunk.Poly.create_box(leftLeg_1b_body, (legWd_b, legHt_b)) leftLeg_1b_shape.color = 0, 255, 0, 100 #---first right leg a rightLeg_1a_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_a, legHt_a))) rightLeg_1a_body.position = chassisXY + ((chWd/2)+(legWd_a/2), 0) rightLeg_1a_shape = pymunk.Poly.create_box(rightLeg_1a_body, (legWd_a, legHt_a)) rightLeg_1a_shape.color = 255, 0, 0, 100 #---first right leg b rightLeg_1b_body = pymunk.Body(legMass, pymunk.moment_for_box(legMass, (legWd_b, legHt_b))) rightLeg_1b_body.position = rightLeg_1a_body.position + ((legWd_a/2)+(legWd_b/2), 0) rightLeg_1b_shape = pymunk.Poly.create_box(rightLeg_1b_body, (legWd_b, legHt_b)) rightLeg_1b_shape.color = 0, 255, 0, 100 #---link left leg b with left leg a pj_ba1left = pymunk.PinJoint(leftLeg_1b_body, leftLeg_1a_body, (legWd_b/2,0), (-legWd_a/2,0))#anchor point coordinates are wrt the body; not the space motor_ba1Left = pymunk.SimpleMotor(leftLeg_1b_body, leftLeg_1a_body, relativeAnguVel) #---link left leg a with chassis pj_ac1left = pymunk.PinJoint(leftLeg_1a_body, chassis_b, (legWd_a/2,0), (-chWd/2, 0)) motor_ac1Left = pymunk.SimpleMotor(leftLeg_1a_body, chassis_b, relativeAnguVel) #---link right leg b with right leg a pj_ba1Right = pymunk.PinJoint(rightLeg_1b_body, rightLeg_1a_body, (-legWd_b/2,0), (legWd_a/2,0))#anchor point coordinates are wrt the body; not the space motor_ba1Right = pymunk.SimpleMotor(rightLeg_1b_body, rightLeg_1a_body, relativeAnguVel) #---link right leg a with chassis pj_ac1Right = pymunk.PinJoint(rightLeg_1a_body, chassis_b, (-legWd_a/2,0), (chWd/2, 0)) motor_ac1Right = pymunk.SimpleMotor(rightLeg_1a_body, chassis_b, relativeAnguVel) self.space.add(chassis_b, chassis_shape) self.space.add(leftLeg_1a_body, leftLeg_1a_shape, rightLeg_1a_body, rightLeg_1a_shape) self.space.add(leftLeg_1b_body, leftLeg_1b_shape, rightLeg_1b_body, rightLeg_1b_shape) self.space.add(pj_ba1left, motor_ba1Left, pj_ac1left, motor_ac1Left) self.space.add(pj_ba1Right, motor_ba1Right, pj_ac1Right, motor_ac1Right) #---prevent collisions with ShapeFilter shape_filter = pymunk.ShapeFilter(group=1) chassis_shape.filter = shape_filter leftLeg_1a_shape.filter = shape_filter rightLeg_1a_shape.filter = shape_filter leftLeg_1b_shape.filter = shape_filter rightLeg_1b_shape.filter = shape_filter simulate = False rotationRate = 2 while running: for event in pygame.event.get(): if event.type == QUIT or (event.type == KEYDOWN and event.key in (K_q, K_ESCAPE)): #running = False sys.exit(0) elif event.type == KEYDOWN and event.key == K_s: # Start/stop simulation. simulate = not simulate elif event.type == KEYDOWN and event.key == K_r: # Reset. # simulate = False self.reset_bodies() elif event.type == KEYDOWN and event.key == K_UP: motor_ba1Left.rate = rotationRate elif event.type == KEYDOWN and event.key == K_DOWN: motor_ba1Left.rate = -rotationRate elif event.type == KEYDOWN and event.key == K_LEFT: motor_ac1Left.rate = rotationRate elif event.type == KEYDOWN and event.key == K_RIGHT: motor_ac1Left.rate = -rotationRate elif event.type == KEYUP: motor_ba1Left.rate = 0 motor_ac1Left.rate = 0 self.draw() ### Update physics fps = 50 iterations = 25 dt = 1.0/float(fps)/float(iterations) if simulate: for x in range(iterations): # 10 iterations to get a more stable simulation self.space.step(dt) pygame.display.flip() clock.tick(fps) if __name__ == '__main__': sim = Simulator() sim.main() It can be controlled with the up, left, right and down arrow keys after first pressing the s key to start the simulation. I've also made sure the variables are created properly linked with each other and named well. The part about making the joints move to a desired angle is yet to be implemented, but perhaps that could be calculated by taking the x,y positions of the ends of the joints and using a formula to calculate the angle and then move the motor until it reaches a desired angle. If there's a better way, do let me know by posting an answer or editing this one.
How do I find the distance from the goal node named target, when I have the below mentioned start node named seeker?
I am trying to find the distance from the start node named seeker to the goal node named target. I have already done most of the implementation of the algorithm and each of the nodes have a coordinate or box on a grid. My python code is lacking and I cannot find the coordinates and distance. I have tried using the vector in the math class which gave me logical errors. I also tried sending the actual objects hoping I could use those to reference the coordinates as I'd done in the code but got a TypeError: expected sequence object with len >= 0 or a single integer. import numpy as np import pygame as pg import sys from Settings import * from Sprites import * vec = pg.math.Vector2 class Game: # initialise game window, etc def __init__(self): self.playing = True pg.init() self.mover = 'target' self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(Title) self.clock = pg.time.Clock() pg.key.set_repeat(500, 100) self.load_data() # pg.mouse.set_pos(0, 0) self.walls = [] def load_data(self): pass # start a new game def new(self): self.all_sprites = pg.sprite.Group() self.player = Player(self, 10, 10) self.target = Target(self, 5, 5) def load_data(self): pass # game loop def run(self): while self.playing: self.dt = self.clock.tick(FPS) / 10000 self.events() self.update() self.draw() def draw_grid(self): for x in range(0, WIDTH, TILESIZE): pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT)) for y in range(0, HEIGHT, TILESIZE): pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y)) def quit(self): pg.quit() sys.exit() def update(self): # game loop update self.all_sprites.update() def events(self): # game loop events for event in pg.event.get(): if event.type == pg.QUIT: self.quit() if event.type == pg.MOUSEBUTTONDOWN: mpos = vec(pg.mouse.get_pos()) // TILESIZE if event.button == 1: if mpos in g.walls: g.walls.remove(mpos) else: g.walls.append(mpos) if event.type == pg.KEYDOWN: if event.key == pg.K_b: # start breadth first breadthfirst(self.target, self.player, self.walls, self.screen) if event.key == pg.K_d: # start depth first depthfirst(self.target, self.player, self.walls, self.screen) if event.key == pg.K_a: # start A* search astarsearch(self.target, self.player, self.walls, self.screen) if event.key == pg.K_ESCAPE: self.quit() if event.key == pg.K_t: self.mover = 'target' if event.key == pg.K_s: self.mover = 'seeker' if self.mover == 'target': if event.key == pg.K_LEFT: self.target.move(dx=-1) if event.key == pg.K_RIGHT: self.target.move(dx=1) if event.key == pg.K_UP: self.target.move(dy=-1) if event.key == pg.K_DOWN: self.target.move(dy=1) else: if event.key == pg.K_LEFT: self.player.move(dx=-1) if event.key == pg.K_RIGHT: self.player.move(dx=1) if event.key == pg.K_UP: self.player.move(dy=-1) if event.key == pg.K_DOWN: self.player.move(dy=1) def draw(self): # game loop - draw self.screen.fill(BGCOLOR) self.draw_grid() self.all_sprites.draw(self.screen) for wall in self.walls: rect = pg.Rect(wall * TILESIZE, (TILESIZE, TILESIZE)) pg.draw.rect(self.screen, GREEN, rect) # always do the flip after drawing everything pg.display.flip() def show_start_screen(self): # game splash/start screen pass def show_go_screen(self): # game over/continue screen pass def breadthfirst(target, seeker, walls, maingrid): pass def depthfirst(target, seeker, wall, maingrid): pass def astarsearch(target, seeker, wall, maingrid): # array to store path locations direct_graph = {} # target location, returns a tuple target = np.where(target.pos) # problem area # seeker location, returns locations start = np.where(seeker.pos) # problem area # array of cost to travel so far g_cost_array = np.zeros(seeker) # problem area g_cost_array[start] = 0 total_g_cost = 0 # array for heuristic cost h_cost_array = np.zeros(seeker) # problem area # need to use a loop unfortunately... t = 0 # possible steps steps = ((-1, 0), (+1, 0), (0, -1), (0, +1)) for rows in h_cost_array: s = 0 for cols in rows: # check if it's a wall! if not - get the distance to target loc = (t, s) if (maingrid[loc]): pass else: dist = abs(target[0] - s) + abs(target[1] - t) h_cost_array[t, s] = dist s += 1 t += 1 # total cost = h + g f_cost_array = g_cost_array + h_cost_array # closed and open sets open_set = [] open_set.append(start) closed_set = [] # actual path path = [] path.append([tuple(target[0]), tuple(target[1])]) solution_found = False while (open_set): open_f_cost = [] # get the heuristic cost for the candidates in the open set for vals in open_set: open_f_cost.append(f_cost_array[vals]) # the shortest heuristic now # the index of the candidate with the lowest distance/heuristic best_dist_now = open_f_cost.index(min(open_f_cost)) # the current best position best_pos_now = open_set[best_dist_now] # if the destination is reached, finish! if (tuple(best_pos_now) == target): solution_found = True break else: # remove the best guy from the open_set and add it to the closed set closed_set.append(open_set.pop(best_dist_now)) # analyze the steps from the current best for step in steps: cand = (best_pos_now[0] + step[0], best_pos_now[1] + step[1]) # check if there's a wall or beyond the screen if cand[0] < 0 or cand[1] < 0 or cand[0] > 39 or cand[1] > 23: pass # skip this candidate because it's a wall! elif maingrid[cand]: pass # need an else clause here to weed out the off-screen locations else: # check if the candidate is in the closed set already_seen = False for dead in closed_set: if np.all(dead == cand): already_seen = True break # if the cell is in the closed set, skip it if already_seen: pass else: approx_g_score = g_cost_array[best_pos_now] + 1 # check if it's in the open list: new = True for others in open_set: if np.all(others == cand): new = False break # if a new cell or improved if (new or approx_g_score < g_cost_array[cand]): direct_graph[tuple(cand[0]), tuple(cand[1])] = ( tuple(best_pos_now[0]), tuple(best_pos_now[1])) g_cost_array[cand] = approx_g_score f_cost_array[cand] = g_cost_array[cand] + h_cost_array[cand] if new: open_set.append(cand) if not solution_found: return None else: recurrentPath(path, direct_graph, target, start) return path # takes a dictionary as input def recurrentPath(final_path, raw_path, dest, origin): a = raw_path[tuple(dest[0]), tuple(dest[1])] final_path.append(a) if (a != origin): recurrentPath(final_path, raw_path, a, origin) else: return final_path g = Game() g.show_start_screen() while True: g.new() g.run() g.show_go_screen() pg.QUIT the expected results is to return the correct path to the target object from the seeker object after you press the keyboard character a. Note that with a left click, a wall can be constructed to add a hindrance to the seeking of the goal.
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.