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.