Python PyGame append object on the screen multiple times with different movement - python

I am trying to make an object with very random movement which is fine, that works. But if I want the same object to append to the screen 10 times then it does not work or i dont know how to do that. The object is called ant. I am sorry if its a bad, unreadable code im still a beginner in pygame. So the ant object(which is a small red square), need to be visible on the screen 10 times, each ant need to move randomly. I appreciate all your answers thanks.
import pygame as pg
import random as rd
import math
import sys
from pygame.time import Clock
pg.init()
screen = pg.display.set_mode((500,500))
title = pg.display.set_caption("TEST")
#REDRAWING SCREEN
def redraw():
screen.fill((0,0,0))
pg.display.update()
#FOOD
def food():
food_x = 200
food_y = 200
FOOD_COLOR = (255,255,255,0)
FWIDTH = 15
fooddraw = pg.draw.circle(screen, FOOD_COLOR, (food_x, food_y), FWIDTH)
#ANT VARIABLES
ant_x = 200
ant_y = 200
COLOR = (220,20,60,0)
ANT_WIDTH = 5
#RANDOM MOVES USING VECTOR
def move():
global ant_x,ant_y
x_boundary = 1000
y_boundary = 1000
pos = pg.math.Vector2(ant_x, ant_y)
ant_x = rd.randrange(0, x_boundary)
ant_y = rd.randrange(0, y_boundary)
speed = 1
maxdist = 1
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 2).rotate(rd.randrange(360))
pos += direction * speed
dist -= speed
ant_x, ant_y = round(pos.x), round(pos.y)
if dist <= 0:
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 0).rotate(rd.randrange(360))
else:
pass
if ant_x >= screen.get_width(): #IF ANTS X IS OFF THE SCREEN WIDTH THEN RESET THE X POSITION
ant_x = 200
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 0).rotate(rd.randrange(360))
else:
pass
if ant_y >= screen.get_height(): #RESET POSITION IF ANTS Y IS OFF THE SCREEN HEIGHT
ant_x = 200
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 0).rotate(rd.randrange(360))
else:
pass
#TRIED TO DUPLICATE ANT 10 TIMES WITH DIFFERENT MOVES BUT DOESNT WORK, I STILL SEE ONLY 1 ANT ON THE SCREEN
ant_spawn = []
for i in range(10):
for j in range(2):
ant_x = 250
ant_y = 250
ant_spawn.append(j)
while True:
FPS = pg.time.Clock()
redraw()
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
#APPEND TO SCREEN
for ants in ant_spawn:
antdraw = pg.draw.rect(screen, COLOR, (ant_x, ant_y,3,3))
#MOVE FUNCTION ACTIVATE
move()
pg.display.update()
FPS.tick(60)

You have to create a list of coordinates instead a list of indices:
ant_spawn = []
for i in range(10):
ant_x = 250
ant_y = 250
ant_spawn.append([ant_x, ant_y])
Move and draw the ants in loops:
for ants in ant_spawn:
move(ants)
for ants in ant_spawn:
pg.draw.rect(screen, COLOR, (*ants, 3, 3))
The move function changes the coordinates of an ant:
def move(ants):
ant_x, ant_y = ants
# change ant_x and ant_y
# [...]
ants[0] = ant_x
ants[1] = ant_y
Complete example (start with space bar)
import pygame as pg
import random as rd
pg.init()
screen = pg.display.set_mode((500,500))
title = pg.display.set_caption("TEST")
ant_x = 200
ant_y = 200
COLOR = (220,20,60,0)
ANT_WIDTH = 5
def move(ants):
ant_x, ant_y = ants
x_boundary = 1000
y_boundary = 1000
pos = pg.math.Vector2(ant_x, ant_y)
c = rd.randrange(0, x_boundary)
ant_y = rd.randrange(0, y_boundary)
speed = 1
maxdist = 1
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 2).rotate(rd.randrange(360))
pos += direction * speed
dist -= speed
ant_x, ant_y = round(pos.x), round(pos.y)
if dist <= 0:
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 0).rotate(rd.randrange(360))
else:
pass
if ant_x >= screen.get_width(): #IF ANTS X IS OFF THE SCREEN WIDTH THEN RESET THE X POSITION
ant_x = 200
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 0).rotate(rd.randrange(360))
else:
pass
if ant_y >= screen.get_height(): #RESET POSITION IF ANTS Y IS OFF THE SCREEN HEIGHT
ant_x = 200
dist = rd.randrange(maxdist)
direction = pg.math.Vector2(1, 0).rotate(rd.randrange(360))
else:
pass
ants[0] = ant_x
ants[1] = ant_y
ant_spawn = []
for i in range(10):
ant_x = 250
ant_y = 250
ant_spawn.append([ant_x, ant_y])
move_ants = False
run = True
while run:
FPS = pg.time.Clock()
for event in pg.event.get():
if event.type == pg.QUIT:
run = False
if event.type == pg.KEYDOWN and event.key == pg.K_SPACE:
move_ants = not move_ants
if move_ants:
for ants in ant_spawn:
ants = move(ants)
screen.fill((0,0,0))
for ants in ant_spawn:
#pg.draw.rect(screen, COLOR, (*ants, 3, 3))
pg.draw.circle(screen, COLOR, ants, 5)
pg.display.update()
FPS.tick(60)
pg.quit()

Related

Python Pygame changing two positions based on a angle [duplicate]

This question already has answers here:
How to set the pivot point (center of rotation) for pygame.transform.rotate()?
(5 answers)
How can you rotate an image around an off center pivot in Pygame
(1 answer)
Closed 4 months ago.
Basically im trying to make a line point out out of the muzzle of this gun.
Picture of player, gun and make shift cross hair for reference (not part of the game)
How i made the gun was by get_rect() the gun surface, and setting the rectangles pos values to the players right side. I also made it so the gun will rotate to always point towards the mouse, but when the cross hair goes past the players right side (the angle goes past 90 or -90) the gun will flip to the players left side. Sorry for very messy code, im still quite new.
gunxposmdl = Player.player_rect.right
gunyposmdl = Player.player_rect.top
gunyposmdl += 20
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - gunxposmdl, mouse_y - gunyposmdl
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
if angle > 90 or angle < -90:
if angle > 0:
angle =-abs(angle)
else:
angle = abs(angle)
rshotgunmdl = pygame.transform.rotate(Weapons.shotgun, int(angle))
rshotgunrect = rshotgunmdl.get_rect(midleft=(gunxposmdl,gunyposmdl))
player_surf_cpy = Player.player_surf.copy()
player_fliped = pygame.transform.flip(player_surf_cpy, False, True)
flipgunxposmdl = Player.player_rect.left
rshotgunmdlcpy = rshotgunmdl.copy()
rshotgunmdlfliped = pygame.transform.flip(rshotgunmdlcpy, False, True )
rshotgunrectfliped = rshotgunmdlfliped.get_rect(midright=(flipgunxposmdl, gunyposmdl))
screen.blit(player_fliped, Player.player_rect)
screen.blit(rshotgunmdlfliped, rshotgunrectfliped)
sg_muzzle_x, sg_muzzle_y = rshotgunrectfliped.midleft[0], rshotgunrectfliped.midleft[1]
else:
rshotgunmdl = pygame.transform.rotate(Weapons.shotgun, int(angle))
rshotgunrect = rshotgunmdl.get_rect(midleft=(gunxposmdl,gunyposmdl))
screen.blit(Player.player_surf, Player.player_rect)
screen.blit(rshotgunmdl, rshotgunrect)
sg_muzzle_x, sg_muzzle_y = rshotgunrect.midright[0], rshotgunrect.midright[1]
#Cast rays
pygame.draw.line(screen, ("Green"), (sg_muzzle_x, sg_muzzle_y), (sg_muzzle_x, sg_muzzle_y), 3)
The problem with this is that when the guns surface is rotated, the rectangle doesnt rotate with it. So when i rotate the gun with the mouse, the line still gets drawn where the rectangles right side is and not where the muzzle is. I need the line to stick out of the muzzle as a visual on where the gun is pointing. Im going to be using this to implement hit casting.
E.g.
Image example (actual in game cross hair this time)
Could somebody please help me make it so the line is coming out of the muzzle in both examples please?
full code:
#!/bin/env python3
import pygame
from sys import exit
import time
import math
pygame.init()
video_infos = pygame.display.Info()
width, height = video_infos.current_w, video_infos.current_h
screen = pygame.display.set_mode((width, height), pygame.FULLSCREEN,
pygame.RESIZABLE)
pygame.display.set_caption('2D Quake')
clock = pygame.time.Clock()
keys = pygame.key.get_pressed()
mousec = pygame.image.load("textures/UI/crossh.png").convert_alpha()
pygame.mouse.set_visible(False)
backround = pygame.Surface((width, height)).convert_alpha()
backround.fill('White')
sbar = pygame.image.load("textures/UI/HUD/SBAR.png").convert_alpha()
class Player:
player_surf = pygame.Surface((50,100))
player_surf.fill('Black')
player_rect = player_surf.get_rect(midbottom = (300, height))
player_gravity = 0
player = {"Inv": [1,1,0], "Hand": 1, "Health": 100}
class Weapons:
shotgun = pygame.image.load("textures/weapons/SHOTGUN.png").convert_alpha()
class Enemies:
esoldier_surf = pygame.Surface((50,100))
esoldier_surf.fill('Black')
esoldier_rect = esoldier_surf.get_rect(midbottom = (800, height))
esoldier = {"Health": 100}
print(width, height)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_h:
Player.player["Health"] -= 1
#Backround
screen.blit(backround,(0,0))
#Enemies
screen.blit(Enemies.esoldier_surf, Enemies.esoldier_rect)
#Player
healthnum = Player.player["Health"]
healthnums = [int(x) for x in str(healthnum)]
Player.player_gravity += 1
Player.player_rect.y += Player.player_gravity
if Player.player_rect.bottom >= height: Player.player_rect.bottom = height
keys = pygame.key.get_pressed()
if keys[pygame.K_d] == 1:
if keys[pygame.K_LCTRL] == 1:
Player.player_rect.x += 9
else:
Player.player_rect.x += 5
if keys[pygame.K_a] == 1:
if keys[pygame.K_LCTRL] == 1:
Player.player_rect.x -= 9
else:
Player.player_rect.x -= 5
if keys[pygame.K_SPACE] == 1 and Player.player_rect.bottom >= height:
Player.player_gravity = -20
gunxposmdl = Player.player_rect.right
gunyposmdl = Player.player_rect.top
gunyposmdl += 20
mouse_x, mouse_y = pygame.mouse.get_pos()
rel_x, rel_y = mouse_x - gunxposmdl, mouse_y - gunyposmdl
angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)
if angle > 90 or angle < -90:
if angle > 0:
angle =-abs(angle)
else:
angle = abs(angle)
rshotgunmdl = pygame.transform.rotate(Weapons.shotgun, int(angle))
rshotgunrect = rshotgunmdl.get_rect(midleft=(gunxposmdl,gunyposmdl))
player_surf_cpy = Player.player_surf.copy()
player_fliped = pygame.transform.flip(player_surf_cpy, False, True)
flipgunxposmdl = Player.player_rect.left
rshotgunmdlcpy = rshotgunmdl.copy()
rshotgunmdlfliped = pygame.transform.flip(rshotgunmdlcpy, False, True )
rshotgunrectfliped = rshotgunmdlfliped.get_rect(midright=(flipgunxposmdl,
gunyposmdl))
screen.blit(player_fliped, Player.player_rect)
screen.blit(rshotgunmdlfliped, rshotgunrectfliped)
sg_muzzle_x, sg_muzzle_y = rshotgunrectfliped.midleft[0],
rshotgunrectfliped.midleft[1]
else:
rshotgunmdl = pygame.transform.rotate(Weapons.shotgun, int(angle))
rshotgunrect = rshotgunmdl.get_rect(midleft=(gunxposmdl,gunyposmdl))
screen.blit(Player.player_surf, Player.player_rect)
screen.blit(rshotgunmdl, rshotgunrect)
sg_muzzle_x, sg_muzzle_y = rshotgunrect.midright[0], rshotgunrect.midright[1]
#Cast rays
pygame.draw.line(screen, ("Green"), (sg_muzzle_x, sg_muzzle_y), (sg_muzzle_x,
sg_muzzle_y), 3)
#UI
mpos = pygame.mouse.get_pos()
sbarxpos = width - 600
sbarxpos = sbarxpos / 2
sbarypos = height - 46
screen.blit(sbar,(sbarxpos,sbarypos))
if len(healthnums) == 3:
hnum1 = pygame.image.load("textures/UI/HUD/NUM_1.png").convert_alpha()
hnum2 = pygame.image.load("textures/UI/HUD/NUM_0.png").convert_alpha()
hnum3 = pygame.image.load("textures/UI/HUD/NUM_0.png").convert_alpha()
if width == 1366:
screen.blit(hnum1,(645,727))
screen.blit(hnum2,(685,727))
screen.blit(hnum3,(727,727))
elif width == 1920:
numypos = height - 44
#screen.blit(hnum1,(, numypos))
#screen.blit(hnum2,(, numypos))
#screen.blit(hnum3,(, numypos))
if len(healthnums) == 2:
numa = healthnums[0]
numb = healthnums[1]
hnum2 = pygame.image.load(f"textures/UI/HUD/NUM_{numa}.png").convert_alpha()
hnum3 = pygame.image.load(f"textures/UI/HUD/NUM_{numb}.png").convert_alpha()
if width == 1366:
screen.blit(hnum2,(685,727))
screen.blit(hnum3,(727,727))
elif width == 1920:
numypos = height - 44
if len(healthnums) == 1:
numb = healthnums[0]
hnum3 = pygame.image.load(f"textures/UI/HUD/NUM_{numb}.png").convert_alpha()
screen.blit(hnum3,(727,727))
screen.blit(mousec, (mpos))
pygame.display.update()
clock.tick(60)
Link to Source files: https://www.dropbox.com/s/4tuk7v675go1urv/2DQuake.zip?dl=0

Python treating all instances of an object as the same

I'm making a game with pygame and pymunk as a physics engine. I'm trying to kill a bullet whenever it hits a player or goes past its lifetime.
When I tried to space.remove(self.shape) and the second bullet hits the player, it gives me an "AssertionError: shape not in space, already removed. I simply changed it to teleport the bullets away, and then learned of the real error.
When I have more than one bullet in the space and a bullet hits the enemy player, all the current bullets teleport away, which means that when I tried to remove one bullet, it called the remove on all the bullets and thats why I had the initial error.
However the problem still remains that one bullet is being treated as every bullet.
Why is something that should be a non-static variable being called as a static variable?
I even tried to use deepcopy to see if that fixed it, but to no avail
This is my chunk of code, apologies since I don't know what is needed to understand it.
The key parts are most likely the Bullet class, the shoot() function in the Player class, and the drawBulletCollision() function
# PyGame template.
# Import modules.
import sys, random, math, time, copy
from typing import List
import pygame
from pygame.locals import *
from pygame import mixer
import pymunk
import pymunk.pygame_util
from pymunk.shapes import Segment
from pymunk.vec2d import Vec2d
pygame.mixer.pre_init(44110, -16, 2, 512)
mixer.init()
# Set up the window.
width, height = 1440, 640
screen = pygame.display.set_mode((width, height))
bg = pygame.image.load("space.png")
def draw_bg():
screen.blit(bg, (0, 0))
#load sounds
#death_fx = pygame.mixer.Sound("")
#death_fx.set_volume(0.25)
shoot_fx = mixer.Sound("shot.wav")
shoot_fx.set_volume(0.25)
#mixer.music.load("video.mp3")
#mixer.music.play()
#time.sleep(2)
#mixer.music.stop()
#gun_mode_fx = pygame.mixer.Sound("")
#gun_mode_fx.set_volume(0.25)
#thrust_mode_fx = pygame.mixer.Sound("")
#thrust_mode_fx.set_volume(0.25)
collision_fx = mixer.Sound("thump.wav")
collision_fx.set_volume(0.25)
ship_group = pygame.sprite.Group()
space = pymunk.Space()
space.gravity = 0, 0
space.damping = 0.6
draw_options = pymunk.pygame_util.DrawOptions(screen)
bulletList = []
playerList = []
environmentList = []
arbiterList = []
b0 = space.static_body
segmentBot = pymunk.Segment(b0, (0,height), (width, height), 4)
segmentTop = pymunk.Segment(b0, (0,0), (width, 0), 4)
segmentLef = pymunk.Segment(b0, (width,0), (width, height), 4)
segmentRit = pymunk.Segment(b0, (0,0), (0, height), 4)
walls = [segmentBot,segmentLef,segmentRit,segmentTop]
for i in walls:
i.elasticity = 1
i.friction = 0.5
i.color = (255,255,255,255)
environmentList.append(i)
class Player(object):
radius = 30
def __init__(self, position, space, color):
self.body = pymunk.Body(mass=5,moment=10)
self.mode = 0 # 0 is gun, 1 is thrust, ? 2 is shield
self.body.position = position
self.shape = pymunk.Circle(self.body, radius = self.radius)
#self.image
#self.shape.friction = 0.9
self.shape.elasticity= 0.2
space.add(self.body,self.shape)
self.angleGun = 0
self.angleThrust = 0
self.health = 100
self.speed = 500
self.gearAngle = 0
self.turningSpeed = 5
self.shape.body.damping = 1000
self.cooldown = 0
self.fireRate = 30
self.shape.collision_type = 1
self.shape.color = color
playerList.append(self)
def force(self,force):
self.shape.body.apply_force_at_local_point(force,(0,0))
def rocketForce(self):
radians = self.angleThrust * math.pi/180
self.shape.body.apply_force_at_local_point((-self.speed * math.cos(radians),-self.speed * math.sin(radians)),(0,0))
def draw(self):
gear = pygame.image.load("gear.png")
gearBox = gear.get_rect(center=self.shape.body.position)
gearRotated = pygame.transform.rotate(gear, self.gearAngle)
#gearRotated.rect.center=self.shape.body.position
x,y = self.shape.body.position
radianGun = self.angleGun * math.pi/180
radianThrust = self.angleThrust * math.pi/180
radiyus = 30 *(100-self.health)/100
screen.blit(gearRotated,gearBox)
self.gearAngle += 1
if radiyus == 30:
radiyus = 32
pygame.draw.circle(screen,self.shape.color,self.shape.body.position,radiyus,0)
pygame.draw.circle(screen,(0,0,0),self.shape.body.position,radiyus,0)
pygame.draw.line(
screen,(0,255,0),
(self.radius * math.cos(radianGun) * 1.5 + x,self.radius * math.sin(radianGun) * 1.5 + y),
(x,y), 5
)
pygame.draw.line(
screen,(200,200,0),
(self.radius * math.cos(radianThrust) * 1.5 + x,self.radius * math.sin(radianThrust) * 1.5 + y),
(x,y), 5
)
#more
def targetAngleGun(self,tAngle):
tempTAngle = tAngle - self.angleGun
tempTAngle = tempTAngle % 360
if(tempTAngle < 180 and not tempTAngle == 0):
self.angleGun -= self.turningSpeed
elif(tempTAngle >= 180 and not tempTAngle == 0):
self.angleGun += self.turningSpeed
self.angleGun = self.angleGun % 360
#print(tAngle, "target Angle")
#print(self.angleGun, "selfangleGun")
#print(tempTAngle, "tempTAngle")
def targetAngleThrust(self,tAngle):
tempTAngle = tAngle - self.angleThrust
tempTAngle = tempTAngle % 360
if(tempTAngle < 180 and not tempTAngle == 0):
self.angleThrust -= self.turningSpeed
elif(tempTAngle >= 180 and not tempTAngle == 0):
self.angleThrust += self.turningSpeed
self.angleThrust = self.angleThrust % 360
#print(tAngle, "target Angle")
#print(self.angleThrust, "selfangleGun")
#print(tempTAngle, "tempTAngle")
def targetAngle(self,tAngle):
if(self.mode == 0):
self.targetAngleGun(tAngle)
elif(self.mode == 1):
self.targetAngleThrust(tAngle)
def shoot(self):
if(self.cooldown == self.fireRate):
x,y = self.shape.body.position
radianGun = self.angleGun * math.pi/180
spawnSpot = (self.radius * math.cos(radianGun) * 1.5 + x,self.radius * math.sin(radianGun)*1.5+y)
self.shape.body.apply_impulse_at_local_point((-20 * math.cos(radianGun),-20 * math.sin(radianGun)),(0,0))
print(spawnSpot)
bT = Bullet(spawnSpot, 5, 50,self.shape.color)
b = copy.deepcopy(bT)
bulletList.append(b)
space.add(b.shape,b.shape.body)
b.getShot(self.angleGun)
self.cooldown = 0
print('pew')
shoot_fx.play()
# HEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEREEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE
def tick(self):
self.draw()
if(self.cooldown < self.fireRate):
self.cooldown += 1
#for o in playerList:
# c = self.shape.shapes_collide(o.shape)
# if(len(c.points)>0):
# self.damage(c.points[0].distance/10)
for o in bulletList:
c = self.shape.shapes_collide(o.shape)
#print(c)
for o in walls:
c = self.shape.shapes_collide(o)
if(len(c.points)>0):
self.damage(c.points[0].distance * 3)
def damage(self, damage):
self.health -= abs(damage)
if self.health < 0:
self.health = 0
#maybe make it part of the player class
def drawWallCollision(arbiter, space, data):
for c in arbiter.contact_point_set.points:
r = max(3, abs(c.distance * 5))
r = int(r)
p = tuple(map(int, c.point_a))
pygame.draw.circle(data["surface"], pygame.Color("red"), p, r, 0)
print('magnitude', math.sqrt(arbiter.total_impulse[0]**2 + arbiter.total_impulse[1]**2))
#print('position', p)
#print(data)
print("its all arbitrary")
s1, s2 = arbiter.shapes
collision_fx.play()
def drawBulletCollision(arbiter, space, data):
s1, s2 = arbiter.shapes
for c in arbiter.contact_point_set.points:
magnitude = math.sqrt(arbiter.total_impulse[0]**2 + arbiter.total_impulse[1]**2)
for p in playerList:
avr = ((c.point_a[0] + c.point_b[0])/2, (c.point_a[1] + c.point_b[1])/2)
distance = (math.sqrt((avr[0] - p.shape.body.position[0]) **2 + (avr[1] - p.shape.body.position[1]) **2 ))
if(distance < Bullet.explosionRadius + Player.radius):
if not(s1.color == s2.color):
p.damage(magnitude)
for b in bulletList:
avr = ((c.point_a[0] + c.point_b[0])/2, (c.point_a[1] + c.point_b[1])/2)
distance = (math.sqrt((avr[0] - p.shape.body.position[0]) **2 + (avr[1] - p.shape.body.position[1]) **2 ))
if(distance < Bullet.explosionRadius + Player.radius):
if not(s1.color == s2.color):
b.damage(magnitude)
pygame.draw.circle(data["surface"], pygame.Color("red"), tuple(map(int, c.point_a)), 10, 0)
print('magnitude', magnitude)
#print('position', p)
#print(data)
print("its all arbitrary")
def drawArbitraryCollision(arbiter, space, data):
collision_fx.play()
class Ship(pygame.sprite.Sprite):
def __init__(self, x, y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("gear.png")
self.rect = self.image.get_rect()
self.rect.center = [x, y]
def rotate(self):
self.image = pygame.transform.rotate(self.image,1)
class Bullet(object):
damage = 2
explosionRadius = 5
def __init__(self, position, size, speed,color):
pts = [(-size, -size), (size, -size), (size, size), (-size, size)]
self.body = copy.deepcopy(pymunk.Body(mass=0.1,moment=1))
self.shape = copy.deepcopy(pymunk.Poly(self.body, pts))
self.shape.body.position = position
self.shape.friction = 0.5
self.shape.elasticity = 1
self.shape.color = color
self.speed = speed
self.size = size
self.shape.collision_type = 2
#space.add(self.body,self.shape)
#bulletList.append(self)
self.lifetime = 0
def getShot(self,angle):
radians = angle * math.pi/180
self.shape.body.apply_impulse_at_local_point((self.speed * math.cos(radians),self.speed * math.sin(radians)),(0,0))
def tick(self):
self.lifetime += 1
if(self.lifetime > 300):
self.shape.body.position = (10000,30)
def damage(self, damage):
self.lifetime = 300
#VELOCITY OF BULLET STARTS WITH VELOCITY OF PLAYER
#MAKE VOLUME OF SOUND DEPEND ON THE IMPULSE FOR THE IMPACTS
#error on purpose so you notice this
#INSTANCES NOT WORKING????
def runPyGame():
# Initialise PyGame.
pygame.init()
# Set up the clock. This will tick every frame and thus maintain a relatively constant framerate. Hopefully.
fps = 60.0
fpsClock = pygame.time.Clock()
running = True
font = pygame.font.SysFont("Arial", 16)
p1 = Player((240,240),space,(132, 66, 245,255))
p2 = Player((1200,400),space,(47, 247, 184,255))
space.add(segmentBot,segmentTop,segmentLef,segmentRit)
# Main game loop.
ch = space.add_collision_handler(1, 0)
ch.data["surface"] = screen
ch.post_solve = drawWallCollision
ch = space.add_collision_handler(1, 2)
ch.data["surface"] = screen
ch.post_solve = drawBulletCollision
ch = space.add_collision_handler(0, 2)
ch.data["surface"] = screen
ch.post_solve = drawArbitraryCollision
dt = 1/fps # dt is the time since last frame.
while True: # Loop forever!
keys = pygame.key.get_pressed()
for event in pygame.event.get():
# We need to handle these events. Initially the only one you'll want to care
# about is the QUIT event, because if you don't handle it, your game will crash
# whenever someone tries to exit.
if event.type == QUIT:
pygame.quit() # Opposite of pygame.init
sys.exit() # Not including this line crashes the script on Windows.
if event.type == KEYDOWN:
if event.key == pygame.K_s:
p1.mode = -(p1.mode - 0.5) + 0.5
print(p1.mode)
if (event.key == pygame.K_k and p1.mode == 0):
p1.shoot()
if event.key == pygame.K_KP_5:
p2.mode = -(p2.mode - 0.5) + 0.5
print(p2.mode)
if (event.key == pygame.K_m and p2.mode == 0):
p2.shoot()
#b = Bullet((200,200),51,51)
if(keys[K_w]):
p1.targetAngle(90)
if(keys[K_q]):
p1.targetAngle(45)
if(keys[K_a]):
p1.targetAngle(0)
if(keys[K_z]):
p1.targetAngle(315)
if(keys[K_x]):
p1.targetAngle(270)
if(keys[K_c]):
p1.targetAngle(225)
if(keys[K_d]):
p1.targetAngle(180)
if(keys[K_e]):
p1.targetAngle(135)
if(keys[K_k] and p1.mode == 1):
p1.rocketForce()
if(keys[K_KP_8]):
p2.targetAngle(90)
if(keys[K_KP_7]):
p2.targetAngle(45)
if(keys[K_KP_4]):
p2.targetAngle(0)
if(keys[K_KP_1]):
p2.targetAngle(315)
if(keys[K_KP_2]):
p2.targetAngle(270)
if(keys[K_KP_3]):
p2.targetAngle(225)
if(keys[K_KP_6]):
p2.targetAngle(180)
if(keys[K_KP_9]):
p2.targetAngle(135)
if(keys[K_m] and p2.mode == 1):
p2.rocketForce()
# Handle other events as you wish.
screen.fill((250, 250, 250)) # Fill the screen with black.
# Redraw screen here.
### Draw stuff
draw_bg()
space.debug_draw(draw_options)
for i in playerList:
i.tick()
screen.blit(
font.render("P1 Health: " + str(p1.health), True, pygame.Color("white")),
(50, 10),
)
screen.blit(
font.render("P2 Health: " + str(p2.health), True, pygame.Color("white")),
(50, 30),
)
for i in bulletList:
i.tick()
ship_group.draw(screen)
# Flip the display so that the things we drew actually show up.
pygame.display.update()
dt = fpsClock.tick(fps)
space.step(0.01)
pygame.display.update()
runPyGame()
I cant point to the exact error since the code is quite long and depends on files I dont have. But here is a general advice for troubleshooting:
Try to give a name to each shape when you create them, and then print it out. Also print out the name of each shape that you add or remove from the space. This should show which shape you are actually removing and will probably make it easy to understand whats wrong.
For example:
...
self.shape = pymunk.Circle(self.body, radius = self.radius)
self.shape.name = "circle 1"
print("Created", self.shape.name)
...
print("Adding", self.shape.name)
space.add(self.body,self.shape)
...
(Note that you need to reset the name of shapes you copy, since otherwise the copy will have the same name.)

Having trouble with a "NameError"

I'm new to classes, and this is my third attempt at making one. I've ran into a NameError which I really have no idea how to solve. Take a look at my program and see if you can help.
import random
import math
import pygame
import pickle
# initialise pygame
pygame.init()
# player class
class player(object):
def __init__(self, playerimage, playerX, playerY = 700, playerX_change = 0):
self.playerimage = pygame.image.load("Main Player.png")
self.playerX = 365
self.playerY = 700
self.playerX_change = 0
# laser class
# ready - bullet not on screen
# fire - bullet is shown on screen and is moving
class laser(object):
def __init__(self, laserimage, laserX, laserY, laserY_change):
self.laserimage = pygame.image.load("laser.png")
self.laserX = 0
self.laserY = 700
self.laserY_change = 10
self.laser_state = "ready"
# alien player / random movement = random.randint()
class alien(object):
def __init__(self, alienimage, alienX, alienY, alienX_change, alienY_change, amount_aliens):
self.alienimage = pygame.image.load("alien.png")
self.alienX = []
self.alienY = []
self.alienX_change = []
self.alienY_change = []
self.amount_aliens = 10
for i in range(ufo.amount_aliens):
ufo.alienimage.append(pygame.image.load('alien.png'))
ufo.alienX.append(random.randint(0, 735))
ufo.alienY.append(random.randint(50, 200))
ufo.alienX_change.append(3)
ufo.alienY_change.append(7)
score = 0
# define player
def main_player(x, y):
screen.blit(male.playerimage, (x, y))
# define laster
def fire_laser(x, y):
lasr.laser_state = "fire"
screen.blit(lasr.laserimage, (x + 16, y + 10))
# define alien
def alien(x, y, i):
screen.blit(ufo.alienimage[i], (x, y))
# collision detection
def hascollision(alienX, alienY, laserX, laserY):
distance = math.sqrt((math.pow(alienX - laserX, 2)) + (math.pow(alienY - laserY, 2)))
if distance < 27:
return True
else:
return False
#frames per second
clock = pygame.time.Clock()
# background
background = pygame.image.load('stars.png')
# display and screen title/icon
(width, height) = (800, 800)
screen = pygame.display.set_mode((width, height))
flip = pygame.display.flip()
pygame.display.set_caption("space fighters")
pygame.event.get()
icon = pygame.image.load('logo.png')
pygame.display.set_icon(icon)
from sys import exit
ufo = alien()
lasr = laser(0, 700, 32, 32)
male = player(365, 700,)
# loop of functions
executed = True
while executed:
screen.fill((63, 62, 63))
# image background
screen.blit(background, (0, 0))
for event in pygame.event.get():
# if key pressed, check which input, right or left?
if event.type == pygame.KEYDOWN:
print("key pressed")
if event.key == pygame.K_a:
male.playerX_change = -6
if event.key == pygame.K_s:
male.playerX_change = 6
if event.type == pygame.KEYUP:
if event.key == pygame.K_a or event.key == pygame.K_s:
male.playerX_change = 0
if event.key == pygame.K_SPACE:
if lasr.laser_state is "ready":
lasr.laserX = male.playerX
fire_laser(lasr.laserX, lasr.laserY)
#frames per second is 60fps
clock.tick(60)
# bounrary algorithm, prevents player moving out/enemy.
male.playerX += male.playerX_change
if male.playerX <= 0:
male.playerX = 0
elif male.playerX >= 736:
male.playerX = 736
# boundry algorithm, make sure alien doesn't go out of bountry
for i in range(ufo.amount_aliens):
ufo.alienX[i] += ufo.alienX_change[i]
if ufo.alienX[i] <= 0:
ufo.alienX_change[i] = 4
ufo.alienY[i] += ufo.alienY_change[i]
elif ufo.alienX[i] >= 736:
ufo.alienX_change[i] = -4
ufo.alienY[i] += ufo.alienY_change[i]
# collision
collision = hascollision(ufo.alienX[i], ufo.alienY[i], lasr.laserX, lasr.laserY)
if collision:
lasr.laserY = 650
lasr.laser_state = "ready"
score += 5
print(score)
alienX[i] = random.randint(0, 735)
alienY[i] = random.randint(50, 200)
alien(ufo.alienX[i], ufo.alienY[i], i)
# movement of laser shot
if lasr.laserY <= 0:
lasr.laserY = 650
lasr.laser_state = "ready"
if lasr.laser_state is "fire":
fire_laser(lasr.laserX, lasr.laserY)
lasr.laserY -= lasr.laserY_change
# updates screen to show screen
main_player(male.playerX, male.playerY)
pygame.display.update()
pygame.quit()
This is the output of the error given by visual studio code (it is on line 39)
for i in range(ufo.amount_aliens):
NameError: name 'ufo' is not defined
The alien class is a bit mixed up. (Although it's hard to tell if this is just an indentation issue in the SO paste.) I'm going to assume that the list of ufos needs to be made outside the class, because this is the only thing that makes sense. Later on in the code, you declare an alien function which will occlude the alien class too. You will need to fix this first - it's best moved into the alien class as alien.draw()
So to make a bunch of aliens, create a list:
alien_image = pygame.image.load('alien.png')
all_ufos = []
for i in range( amount_aliens ):
x_pos = random.randint( 0, 735 )
y_pos = random.randint( 50, 200 )
x_speed = 3
y_speed = 7
all_ufos.append( alien( alien_image, x_pos, y_pos, x_speed, y_speed ) )
Remove the amount_aliens from the alien object, so that it now only represents a single alien.
class alien( object ):
def __init__( self, alienimage, alienX, alienY, alienX_change, alienY_change ):
self.alienimage = alienimage
self.alienX = alienX
self.alienY = alienY
self.alienX_change = alienX_change
self.alienY_change = alienY_change
And move the support functions into the alien class.
def draw( self, screen ):
""" Draw the alien to the screen """
screen.blit( self.alienimage, ( self.alienX, self.alienY ) )
def hasCollision( self, laserX, laserY ):
""" Has the laser at collided with this alien? """
distance = math.sqrt((math.pow(self.alienX - laserX, 2)) + (math.pow(self.alienY - laserY, 2)))
return ( distance < 27 ):
This allows your main loop to iterate over the list of aliens, doing stuff simply:
### Main Loop
while not exiting:
...
# paint all UFO sprites
for ufo in all_ufos:
ufo.draw( screen )
# check all lasers for collision
for laser in all_lasers:
for ufo in all_ufos:
if ( ufo.hasCollision( laser.laserX, laser.laserY ) ):
print( "*boom*" )
What you are doing here is re-creating some of the functionality of the PyGame Sprite and SpriteGroup Classes. It might be worth a quick read of the documentation on it.

unsupported operand type(s) for +=: 'int' and 'NoneType'

def moveWall (paddleWall, paddleWallDirY):
paddleWall.y+=paddleWallDirY
return paddleWall
def main():
pygame.init()
global DISPLAYSURF
##Font information
global BASICFONT, BASICFONTSIZE
BASICFONTSIZE = 20
BASICFONT = pygame.font.Font('freesansbold.ttf', BASICFONTSIZE)
FPSCLOCK = pygame.time.Clock()
DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH,WINDOWHEIGHT))
pygame.display.set_caption('Pong')
#Initiate variable and set starting positions
#any future changes made within rectangles
WallX = WINDOWWIDTH/2 - LINETHICKNESS/2
WallY = (WINDOWHEIGHT)/2 - LINETHICKNESS/2
ballX = WINDOWWIDTH/2 - LINETHICKNESS/2
ballY = WINDOWHEIGHT/2 - LINETHICKNESS/2
playerOnePosition = (WINDOWHEIGHT - PADDLESIZE) /2
playerTwoPosition = (WINDOWHEIGHT - PADDLESIZE) /2
score = 0
#Keeps track of ball direction
ballDirX = -1 ## -1 = left 1 = right
ballDirY = -1 ## -1 = up 1 = down
paddleWallDirX = 0
paddleWallDirY = 1
#Creates Rectangles for ball and paddles.
paddle1 = pygame.Rect(PADDLEOFFSET,playerOnePosition, LINETHICKNESS,PADDLESIZE)
paddle2 = pygame.Rect(WINDOWWIDTH - PADDLEOFFSET - LINETHICKNESS, playerTwoPosition, LINETHICKNESS,PADDLESIZE)
paddle3 = pygame.Rect(PADDLEOFFSET,playerOnePosition, LINETHICKNESS,PADDLESIZE)
paddleWall = pygame.Rect(WallX, WallY, LINETHICKNESS, 100)
ball = pygame.Rect(ballX, ballY, LINETHICKNESS, LINETHICKNESS)
#Draws the starting position of the Arena
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawPaddle(paddle3)
drawPaddle(paddleWall)
drawBall(ball)
pygame.mouse.set_visible(0) # make cursor invisible
while True: #main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# mouse movement commands
elif event.type == MOUSEMOTION:
mousex, mousey = event.pos
paddle1.y = mousey
paddle3.y = mousey - 100
drawArena()
drawPaddle(paddle1)
drawPaddle(paddle2)
drawPaddle(paddle3)
drawPaddle(paddleWall)
drawBall(ball)
paddleWall = moveWall(paddleWall, paddleWallDirY)
ball = moveBall(ball, ballDirX, ballDirY)
ballDirX, ballDirY = checkEdgeCollision(ball, ballDirX, ballDirY)
paddleWallDirY = checkEdgeCollisionWall(paddleWall, paddleWallDirY)
score = checkPointScored(paddle1, paddle3, ball, score, ballDirX)
ballDirX = ballDirX * checkHitBall(ball, paddle1, paddle2, paddle3, paddleWall, ballDirX)
paddle2 = artificialIntelligence (ball, ballDirX, paddle2)
I can't fix this and i did give paddleWallDirY the value of 1 in the main method
Your second parameter is None either directly:
moveWall(pw, None)
or indirectly:
x = None
...
moveWall(pw, x)
Please note that the None value can be a result of a function call, for example.

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.

Categories

Resources