Cannot see bullets when game is running - python
Hello, so I can only see the bullet when i'm closing my game's window, but I do not see the mistake.
import pygame, math, random, os
pygame.init()
clock = pygame.time.Clock()
width = 800
height = 608
screen = pygame.display.set_mode((width, height))
running = True
gameover = False
levelferdig = False
levelnr = 0
ferdig = False
jump = False
levels =[[[1,1,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,1],
[1,0,8,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,7,0,0,0],
[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],
[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0],
[1,0,0,2,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]],
[[1,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,1],
[0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0],
[9,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,1,0,0,0,0,1],
[0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1],
[0,0,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1],
[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1],
[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0],
[0,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0],
[0,1,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0],
[0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0],
[0,1,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,1,1,1,1,0,0,0,0,0],
[0,0,0,2,0,0,0,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,8,1,1]]]
ghostgruppe = pygame.sprite.Group()
tilegruppe = pygame.sprite.Group()
utganggruppe = pygame.sprite.Group()
backgroundgruppe_1 = pygame.sprite.Group()
backgroundgruppe_2 = pygame.sprite.Group()
moving_sprites = pygame.sprite.Group()
spillergruppe = pygame.sprite.Group()
bullet_img = pygame.transform.scale(pygame.image.load(os.path.join('Bullets', 'bullet.png.png')), (10,10))
background_image_2 = pygame.image.load('skog.png').convert()
background_image_1 = pygame.image.load("beach.png").convert()
pygame.display.set_caption('pygame') #setter navnet på spillet når du åpner spillet
icon = pygame.image.load('menneske.png')
pygame.display.set_icon(icon)
font = pygame.font.Font('freesansbold.ttf', 72 ) #font som skal brukes
gameovertekst = font.render('Game over', True, (255,0,0)) #farge og tekst gameover
gameoverrect = gameovertekst.get_rect()
gameoverrect.center = (width/2, height/2)
font = pygame.font.Font('freesansbold.ttf', 72 ) #font som skal brukes
levelferdigtekst = font.render('Ferdig', True, (0,255,0)) #farge og tekst gameover
levelferdigrect = levelferdigtekst.get_rect()
levelferdigrect.center = (width/2, height/2)
ferdigtekst = font.render('Victory', True, (0,0,255))
ferdigrect = levelferdigtekst.get_rect()
ferdigrect.center = (width/2, height/2)
class Spiller(pygame.sprite.Sprite):
def __init__(self,x,y):
super().__init__()
self.spiller_animation = False
self.sprites = []
self.sprites.append(pygame.image.load('spiller.rett(1).png'))
self.sprites.append(pygame.image.load('spiller.høyre(1).png'))
self.sprites.append(pygame.image.load('spiller.venstre(1).png'))
self.sprites.append(pygame.image.load('spiller.hopp(1).png'))
self.current_sprite = 0
self.image = self.sprites[self.current_sprite]
self.rect = self.image.get_rect()
self.rect.topleft =[x,y]
self.bullets = [] #list
self.x = x
self.y = y
self.stepIndex = 0
self.face_right = True
self.face_left = False
self.fy = 10
self.fx = 10
self.jump = False
def direction(self):
if self.face_right:
return 1
if self.face_left:
return -1
def animation(self):
self.spiller_animation = True
def skytt(self):
if trykketliste[pygame.K_RIGHT] and not gameover:
bullet = Bullet(self.x, self.y, self.direction())
self.bullets.append(bullet)
for bullet in self.bullets:
bullet.move()
def reset(self):
self.fartx = 0
self.farty = 0
def update(self,speed):
if self.spiller_animation == True:
self.current_sprite += speed
if int(self.current_sprite) >= len(self.sprites):
self.current_sprite = 0
self.is_animating = False
self.image = self.sprites[int(self.current_sprite)]
self.rect.x += self.fartx
tiletreffliste = pygame.sprite.spritecollide(self,tilegruppe, False)
if tiletreffliste:
if self.fartx > 0:
self.rect.right = tiletreffliste[0].rect.left
else:
self.rect.left = tiletreffliste[0].rect.right
self.rect.y += self.farty
tiletreffliste = pygame.sprite.spritecollide(self, tilegruppe, False)
if tiletreffliste:
if self.farty > 0:
self.rect.bottom = tiletreffliste[0].rect.top
else:
self.rect.top = tiletreffliste[0].rect.bottom
utgangtreffliste = pygame.sprite.spritecollide(self, utganggruppe, False)
if utgangtreffliste:
global levelferdig
levelferdig = True
global levelnr
levelnr += 1
restart()
class Bullet:
def __init__(self,x,y, direction):
super().__init__()
self.x = x + 15
self.y = y + 25
self.direction = direction
def draw_bullet(self):
screen.blit(bullet_img, (self.x, self.y))
def move(self):
if self.direction == 1:
self.x += 15
if self.direction == -1:
self.x -= 15
class Ghost(pygame.sprite.Sprite):
def __init__(self, x, y, fx,fy):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('ghost.png').convert_alpha()
self.rect = self.image.get_rect() #self rect rektangler, fin rektangel bilde som passer
self.rect.x = x
self.rect.y = y
self.fartx = fx
self.farty = fy
def flytt(self):
self.rect.x = self.rect.x + self.fartx
self.rect.y = self.rect.y + self.farty
def update(self):
# Flytter høyre/venstre og sjekker kollisjon
self.rect.x += self.fartx
tiletreffliste = pygame.sprite.spritecollide(self,tilegruppe, False)
if tiletreffliste:
if self.fartx > 0:
self.rect.right = tiletreffliste[0].rect.left
else:
self.rect.left = tiletreffliste[0].rect.right
self.fartx *= -1
self.rect.y += self.farty
tiletreffliste = pygame.sprite.spritecollide(self, spillergruppe, False)
if tiletreffliste:
if self.farty > 0:
self.rect.bottom = tiletreffliste[0].rect.top
else:
self.rect.top = tiletreffliste[0].rect.bottom
self.farty *= -1
def treffTile(self):
if self.rect.x > width or self.rect.x < 0:
self.fartx = self.fartx * -1
if self.rect.y > height or self.rect.y < 0:
self.farty = self.farty * -1
class Tile(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('sand.png').convert_alpha()
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Utgang(pygame.sprite.Sprite):
def __init__(self,x,y):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load('dør.png')
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
def restart():
global gameover
global levelferdig
gameover = False
levelferdig = False
for tile in tilegruppe:
tile.kill()
for utgang in utganggruppe:
utgang.kill()
for ghost in ghostgruppe:
ghost.kill()
spiller.reset()
for i in range(5): #hvor mange ghosts skal vi ha
ghost = Ghost(random.randint(0,width),random.randint(0, height), random.randint(1,8),random.randint(1,8))
ghostgruppe.add(ghost)
if levelnr < len(levels):
for y,rad in enumerate(levels[levelnr]):
for x,verdi in enumerate(rad):
if verdi == 1:
tile = Tile(x*32,y*32)
tilegruppe.add(tile)
if verdi == 9:
utgang = Utgang(x*32, y*32)
utganggruppe.add(utgang)
if verdi == 8:
spiller.rect.x = x*32
spiller.rect.y = y*32
else:
global ferdig
ferdig = True
#skytt
spiller = Spiller(100, 100)
moving_sprites.add(spiller)
restart()
while running:
pygame.display.bullet()
spiller.farty = 0
spiller.fartx = 0
trykketliste = pygame.key.get_pressed()
spiller.skytt()
background_image_1 = pygame.image.load("beach.png").convert()
screen.blit(background_image_1, [0,0])
if trykketliste[pygame.K_RIGHT] and not gameover:
spiller.farty = -1
spiller.sprites.append(pygame.image.load('spiller.venstre(1).png'))
spiller.animation()
spiller.skytt()
if trykketliste[pygame.K_LEFT] and not gameover:
spiller.farty = 1
spiller.sprites.append(pygame.image.load('spiller.høyre(1).png'))
spiller.animation()
if trykketliste[pygame.K_UP] and not gameover:
spiller.fartx = -1
spiller.animation()
spiller.sprites.append(pygame.image.load('spiller.hopp(1).png'))
if trykketliste[pygame.K_DOWN]and not gameover:
spiller.fartx = 1
spiller.animation()
spiller.sprites.append(pygame.image.load('spiller.rett(1).png'))
if jump is False and trykketliste[pygame.K_SPACE] and not gameover:
jump = True
spiller.animation()
spiller.sprites.append(pygame.image.load('spiller.hopp(1).png'))
if jump is True:
spiller.rect.y -= spiller.farty *4
spiller.farty -= 1
if spiller.farty < -10:
jump = False
spiller.farty = 10
if levelnr == 1:
background_image_1 = pygame.image.load("skog.png").convert()
screen.blit(background_image_2, [0,0])
spillertruffet = pygame.sprite.groupcollide(spillergruppe, ghostgruppe, False, False, pygame.sprite.collide_mask)
if spillertruffet:
gameover = True
ghosttruffet = pygame.sprite.groupcollide(ghostgruppe, spillergruppe, True, True, pygame.sprite.collide_mask)
if ghosttruffet:
spiller.kill()
#Gruppene oppdateres
ghostgruppe.update()
tilegruppe.update()
utganggruppe.update()
spillergruppe.update()
moving_sprites.draw(screen)
moving_sprites.update(0.25)
#gruppene vises på skjermen.
ghostgruppe.draw(screen)
tilegruppe.draw(screen)
utganggruppe.draw(screen)
spillergruppe.draw(screen)
if gameover:
screen.blit(gameovertekst,gameoverrect)
if levelferdig:
screen.blit(levelferdigtekst, levelferdigrect)
spillergruppe.draw(screen)
clock.tick(60)
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.K_n:
levelnr = O
restart()
for bullet in spiller.bullets:
bullet.draw_bullet()
pygame.time.delay(30)
pygame.display.flip()
pygame.quit()
You have to draw the bullets after drawing the background. Use a loop to iterate through the list of bullets and call the draw_bullet method for each bullet:
while running:
# pygame.display.bullet() <--- DELETE
spiller.farty = 0
spiller.fartx = 0
trykketliste = pygame.key.get_pressed()
spiller.skytt()
background_image_1 = pygame.image.load("beach.png").convert()
screen.blit(background_image_1, [0,0])
# INSERT
for bullet in spiller.bullets:
bullet.draw_bullet()
# [...]
pygame.display.update()
# [...]
screen.blit(background_image_1, [0,0]) draws the background and hides anything previously drawn. pygame.display.update() updates the display and makes everything that is drawn visible. Therefor you need to draw all the objects of the scene after screen.blit(background_image_1, [0,0]) and before pygame.display.update().
Related
I am having trouble with my stat function in my player class
When I shoot at my cement block sprites I have it set so that self.score is self.score += 1 in my player collision function, but when I shoot my cement blocks and destroy them, either 1 or 2 points is added at random to my score. Why? How can I fix this? A clear example is, I shoot at and destroy 2 cement blocks in a row and 1 point is added for each one destroyed which means my score is 2, which is what I want cause I want to add 1 point to my score whenever I destroy a cement block, but then when I shoot and destroy the third cement block, 2 points are added instead of 1 bringing my score to 4 instead of being a score of 3 points. Github: https://github.com/Enoc-Mena99/AutoPilot My code: import random import pygame import pygame.freetype pygame.init() #screen settings WIDTH = 1000 HEIGHT = 400 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("AutoPilot") screen.fill((255, 255, 255)) #fps FPS = 120 clock = pygame.time.Clock() #load images bg = pygame.image.load('background/street.png').convert_alpha() # background bullets = pygame.image.load('car/bullet.png').convert_alpha() debris_img = pygame.image.load('debris/cement.png') #define game variables shoot = False #player class class Player(pygame.sprite.Sprite): def __init__(self, scale, speed): pygame.sprite.Sprite.__init__(self) self.bullet = pygame.image.load('car/bullet.png').convert_alpha() self.bullet_list = [] self.speed = speed #self.x = x #self.y = y self.moving = True self.frame = 0 self.flip = False self.direction = 0 self.score = 0 #load car self.images = [] img = pygame.image.load('car/car.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width()) * scale, (int(img.get_height()) * scale))) self.images.append(img) self.image = self.images[0] self.rect = self.image.get_rect() self.update_time = pygame.time.get_ticks() self.movingLeft = False self.movingRight = False self.rect.x = 465 self.rect.y = 325 #draw car to screen def draw(self): screen.blit(self.image, (self.rect.centerx, self.rect.centery)) #move car def move(self): #reset the movement variables dx = 0 dy = 0 #moving variables if self.movingLeft and self.rect.x > 33: dx -= self.speed self.flip = True self.direction = -1 if self.movingRight and self.rect.x < 900: dx += self.speed self.flip = False self.direction = 1 #update rectangle position self.rect.x += dx self.rect.y += dy #shoot def shoot(self): bullet = Bullet(self.rect.centerx + 18, self.rect.y + 30, self.direction) bullet_group.add(bullet) #check collision def collision(self, debris_group): for debris in debris_group: if pygame.sprite.spritecollide(debris, bullet_group, True): debris.health -= 1 if debris.health <= 0: self.score += 1 #player stats def stats(self): myfont = pygame.font.SysFont('comicsans', 30) scoretext = myfont.render("Score: " + str(self.score), 1, (0,0,0)) screen.blit(scoretext, (100,10)) #bullet class class Bullet(pygame.sprite.Sprite): def __init__(self, x, y, direction): pygame.sprite.Sprite.__init__(self) self.speed = 5 self.image = bullets self.rect = self.image.get_rect() self.rect.center = (x,y) self.direction = direction def update(self): self.rect.centery -= self.speed #check if bullet has gone off screen if self.rect.centery < 1: self.kill() #debris class class Debris(pygame.sprite.Sprite): def __init__(self,scale,speed): pygame.sprite.Sprite.__init__(self) self.scale = scale self.x = random.randrange(100,800) self.speed_y = 10 self.y = 15 self.speed = speed self.vy = 0 self.on_ground = True self.move = True self.health = 4 self.max_health = self.health self.alive = True self.velocity = random.randrange(1,2) self.speed_x = random.randrange(-3,3) self.moving_down = True self.is_destroyed = False #load debris self.image = debris_img self.rect = self.image.get_rect() self.rect.x = random.randrange(100, 800) self.rect.y = random.randrange(-150, -100) self.rect.center = (self.x,self.y) #load explosion self.img_explosion_00 = pygame.image.load('explosion/0.png').convert_alpha() self.img_explosion_00 = pygame.transform.scale(self.img_explosion_00, (self.img_explosion_00.get_width() * 2, self.img_explosion_00.get_height() * 2)) self.img_explosion_01 = pygame.image.load('explosion/1.png').convert_alpha() self.img_explosion_01 = pygame.transform.scale(self.img_explosion_01, (self.img_explosion_01.get_width() * 2, self.img_explosion_01.get_height() * 2)) self.img_explosion_02 = pygame.image.load('explosion/2.png').convert_alpha() self.img_explosion_02 = pygame.transform.scale(self.img_explosion_02, (self.img_explosion_02.get_width() * 2, self.img_explosion_02.get_height() * 2)) self.img_explosion_03 = pygame.image.load('explosion/3.png').convert_alpha() self.img_explosion_03 = pygame.transform.scale(self.img_explosion_03, (self.img_explosion_03.get_width() * 2, self.img_explosion_03.get_height() * 2)) #explosion list self.anim_explosion = [self.img_explosion_00, self.img_explosion_01, self.img_explosion_02, self.img_explosion_03] self.anim_index = 0 self.frame_len = 10 #spawn new debris def spawn_new_debris(self): self.rect.x = random.randrange(100, 800) self.rect.y = random.randrange(-150, -100) self.velocity = random.randrange(1, 2) self.speed_x = random.randrange(-3, 3) #respawn debris when they go of the screen def boundaries(self): if self.rect.left > WIDTH + 10 or self.rect.right < -10 or self.rect.top > HEIGHT + 10: self.spawn_new_debris() #update image def update(self): self.rect.y += self.velocity self.rect.x += self.speed_x self.boundaries() if self.health <= 0: max_index = len(self.anim_explosion) - 1 if self.anim_index > max_index: self.kill() else: if self.frame_len == 0: self.image = self.anim_explosion[self.anim_index] self.anim_index += 1 self.frame_len = 10 else: self.frame_len -= 1 #make debris fall down def falldown(self): self.rect.centery += self.velocity if self.moving_down and self.rect.y > 350: self.kill() ######################CAR/DEBRIS########################## player = Player(1,5) ########################################################## #groups bullet_group = pygame.sprite.Group() debris_group = pygame.sprite.Group() all_sprites = pygame.sprite.Group() for x in range(50): d = Debris(1, 5) debris_group.add(d) all_sprites.add(d) #game runs here run = True while run: #draw street screen.blit(bg, [0, 0]) #update groups bullet_group.update() bullet_group.draw(screen) debris_group.update() debris_group.draw(screen) #draw car player.draw() player.move() player.collision(debris_group) player.stats() #update all sprites all_sprites.update() all_sprites.draw(screen) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False #check if key is down if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: run = False if event.key == pygame.K_a: player.movingLeft = True if event.key == pygame.K_d: player.movingRight = True if event.key == pygame.K_SPACE: player.shoot() shoot = True #check if key is up if event.type == pygame.KEYUP: if event.key == pygame.K_a: player.movingLeft = False if event.key == pygame.K_d: player.movingRight = False #update the display pygame.display.update() pygame.display.flip() clock.tick(FPS) pygame.quit()
Do not count debris objects with healt <= 0: class Player(pygame.sprite.Sprite): # [...] def collision(self, debris_group): for debris in debris_group: # if health > 0 and collision: if debris.health > 0 and pygame.sprite.spritecollide(debris, bullet_group, True): debris.health -= 1 if debris.health <= 0: self.score += 1
Enemy collision with pygame.sprite.spritecollide()
In my game, there is a sprite player which I can control. It can move right or left, it can jump, shoot fireballs(bullets) and a breathe fire. I have added an enemy which can move on itself from right to left on a limited distance that I set. What I would like to do now is make my player loose health if it collides with the enemy sprite using pygame.sprite.spritecollide(). However it isn't working out well I don't know how to fix my issue which is the following: if I run my code below it says NameError: name 'enemy_list' is not defined. The errored line is in Sprite1.py in the Player class under the update function. How do I fix my code? I created my Enemy class and Level class with the following website: https://opensource.com/article/18/5/pygame-enemy. I'm open to all suggestions. Thanks beforehand! I separated my code into three files: main.py, settings.py and Sprite1.py. Here's main.py: import pygame import os import sys import time from pygame import mixer from Sprite1 import * from settings import * ''' Setup ''' pygame.init() clock = pygame.time.Clock() pygame.mixer.music.load('.\\sounds\\Fairy.mp3') pygame.mixer.music.play(-1, 0.0) all_sprites = pygame.sprite.Group() player = Player(all_sprites) player.rect.x = 500 player.rect.y = 500 eloc = [] eloc = [400,500] enemy_list = Level.bad( 1, eloc ) showStartScreen(surface) x = 0 ''' Main loop ''' main = True while main == True: background = pygame.image.load(os.path.join('images', 'Bg.png')).convert() surface.blit(background, (0, 0)) for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() main = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: player.control(-steps,0) if event.key == pygame.K_RIGHT: player.control(steps,0) if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT: player.control(steps,0) if event.key == pygame.K_RIGHT: player.control(-steps,0) keys = pygame.key.get_pressed() if not(isJump): if keys[pygame.K_UP]: isJump = True else: if jumpCount >= -10: player.rect.y -= (jumpCount * abs(jumpCount)) * 1 jumpCount -= 2 else: jumpCount = 10 isJump = False # dt = time since last tick in milliseconds. dt = clock.tick(60) / 1000 all_sprites.update(dt) player.update(dt) all_sprites.draw(surface) #refresh player position enemy_list.draw(surface) for e in enemy_list: e.move() pygame.display.flip() Here's my settings.py: import pygame isJump = False jumpCount = 10 width = 960 height = 720 fps = 40 # frame rate pygame.display.set_caption('B.S.G.') surface = pygame.display.set_mode((width, height)) PLAYER_ACC = 0.5 PLAYER_FRICTION = -0.12 PLAYER_GRAV = 0.8 PLAYER_JUMP = 20 PLAYER_LAYER = 2 PLATFORM_LAYER = 1 RED = (255, 0, 0) steps = 10 # how fast to move And here's my Sprite1.py: import pygame import sys import os import time from pygame import mixer from pygame.locals import * from settings import * vec = pygame.math.Vector2 def showStartScreen(surface): show = True while (show == True): background = pygame.image.load(os.path.join('images', 'Starting_scr.png')) # rect = surface.get_rect() surface.blit(background, (0,0)) pygame.display.flip() for event in pygame.event.get(): if event.type == pygame.MOUSEBUTTONDOWN: show = False class Player(pygame.sprite.Sprite): def __init__(self, all_sprites): pygame.sprite.Sprite.__init__(self) self.movex = 0 self.movey = 0 self.frame = 0 self.health = 10 self.jumping = False self.images = [] self.imagesleft = [] self.imagesright = [] self.direction = "right" self.alpha = (0,0,0) self.ani = 4 # animation cycles self.all_sprites = all_sprites self.add(self.all_sprites) self.fire_timer = .1 self.bullet_timer = .1 self.pos = vec(40, height - 100) self.vel = vec(0, 0) for i in range(1,5): img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert() img.convert_alpha() img.set_colorkey(self.alpha) self.imagesright.append(img) self.image = self.imagesright[0] self.rect = self.image.get_rect() for i in range(1,5): img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert() img = pygame.transform.flip(img, True, False) img.convert_alpha() img.set_colorkey(self.alpha) self.imagesleft.append(img) self.image = self.imagesleft[0] self.rect = self.image.get_rect() def control(self,x,y): ''' control player movement ''' self.movex += x self.movey -= y def update(self, dt): ''' Update sprite position ''' self.rect.x = self.rect.x + self.movex self.rect.y = self.rect.y + self.movey enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False) for enemy in ennemy_hit_list: self.health -= 1 print(self.health) # moving left if self.movex < 0: self.frame += 1 if self.frame > 3*self.ani: self.frame = 0 self.image = self.imagesleft[self.frame//self.ani] self.direction = "left" # moving right if self.movex > 0: self.frame += 1 if self.frame > 3*self.ani: self.frame = 0 self.image = self.imagesright[self.frame//self.ani] self.direction = "right" keys = pygame.key.get_pressed() if keys[pygame.K_SPACE]: self.bullet_timer -= dt # Subtract the time since the last tick. if keys[pygame.K_x]: self.fire_timer -= dt if self.bullet_timer <= 0: self.bullet_timer = 100 # Bullet ready. if keys: # Left mouse button. # Create a new bullet instance and add it to the groups. if self.direction == "right": Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites) else: Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites) self.bullet_timer = .5 # Reset the timer. if self.fire_timer <= 0: self.fire_timer = 100 if keys: if self.direction == "right": Fire([self.rect.x + 170, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites) else: Fire([self.rect.x - 90, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites) self.fire_timer = .1 if self.health == 0: self.kill() class Enemy(pygame.sprite.Sprite): ''' Spawn an enemy ''' def __init__(self,x,y,img): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(os.path.join('images',img)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.counter = 0 # counter variable def move(self): ''' enemy movement ''' distance = 20 speed = 15 if self.counter >= 0 and self.counter <= distance: self.rect.x += speed elif self.counter >= distance and self.counter <= distance*2: self.rect.x -= speed else: self.counter = 0 self.counter += 1 class Bullet(pygame.sprite.Sprite): IMAGE = None FLIPPED_IMAGE = None def __init__(self, pos, direction, *sprite_groups): super().__init__(*sprite_groups) # cache images if not Bullet.IMAGE: Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png')) Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False) if direction == "right": self.vel = pygame.math.Vector2(750, 0) self.image = Bullet.IMAGE else: self.vel = pygame.math.Vector2(-750, 0) self.image = Bullet.FLIPPED_IMAGE self.pos = pygame.math.Vector2(pos) self.rect = self.image.get_rect(center=pos) def update(self, dt): # Add the velocity to the position vector to move the sprite self.pos += self.vel * dt self.rect.center = self.pos # Update the rect pos. if not pygame.display.get_surface().get_rect().colliderect(self.rect): self.kill() class Fire(pygame.sprite.Sprite): IMAGE = None FLIPPED_IMAGE = None def __init__(self, pos, direction, *sprite_groups): super().__init__(*sprite_groups) # cache images if not Fire.IMAGE: Fire.IMAGE = pygame.image.load(os.path.join('images','fire_drag.png')) Fire.FLIPPED_IMAGE = pygame.transform.flip(Fire.IMAGE, True, False) if direction == "right": self.image = Fire.IMAGE self.vel = pygame.math.Vector2(0, 0) else: self.image = Fire.FLIPPED_IMAGE self.vel = pygame.math.Vector2(0, 0) self.pos = pygame.math.Vector2(pos) self.rect = self.image.get_rect(center=pos) def update(self, dt): self.too = True self.pos += self.vel * dt self.rect.center = self.pos # Update the rect pos. if self.too == True: self.kill() class Level(): def bad(lvl,eloc): if lvl == 1: enemy = Enemy(eloc[0],eloc[1],'cookie1.png') # spawn enemy enemy_list = pygame.sprite.Group() # create enemy group enemy_list.add(enemy) # add enemy to group if lvl == 2: print("Level " + str(lvl) ) return enemy_list def loot(lvl,lloc): print(lvl)
enemy_list is defined in global namespace, in main.py, thus it is not accessible in the module Sprite.py. Add an additional argument to the update method of the class Player: class Player(pygame.sprite.Sprite): # [...] def update(self, dt, enemy_list): # [...] enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False) # [...] Since player is a member of all_sprites, you have to add the argument to the update methods of the other sprites (Enemy, Bullet), too. Pass enemy_list to the update method all_sprites in the main application loop. Note the update method of Player is invoked by all_sprites.update, thus player.update(dt, enemy_list) is superflous: while main == True: # [...] all_sprites.update(dt, enemy_list) # [...]
Check for collision and stop velocity in pygame
I am trying to make a simple platformer in pygame, with simulated gravity and collision. I can't make the collision working. On collision with a sprite, the player slowly falls through the sprite and continues falling at normal speed when reached through. Main.py: class Game: def __init__(self): # initialize pygame library pg.init() pg.mixer.init() # initialize screen self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) self.clock = pg.time.Clock() self.font = pg.font.match_font(FONT_NAME) self.running = True self.playing = True def new(self): # initzialize sprite groups self.sprites = pg.sprite.Group() self.objects = pg.sprite.Group() self.p = Player(self) self.sprites.add(self.p) self.g = Ground() self.sprites.add(self.g) self.objects.add(self.g) self.o = Object(100, 350, 100, 20) self.sprites.add(self.o) self.objects.add(self.o) self.collide = False self.run() # constant running functions def run(self): while self.playing: self.clock.tick(FPS) self.events() self.update() self.draw() self.running = False def events(self): for event in pg.event.get(): if event.type == pg.QUIT: self.playing = False if event.type == pg.KEYDOWN: if event.key == pg.K_UP: self.p.jump() def update(self): self.sprites.update() hits = pg.sprite.spritecollide(self.p, self.objects, False) if hits: self.collide = True if self.p.vel.y >= 0.0: self.p.x = hits[0].rect.top print("Collide bottom") elif self.p.vel.y < 0: self.p.top = hits[0].rect.bottom elif self.p.vel.x > 0: self.p.rect.right = hits[0].rect.left elif self.p.vel.x < 0: self.p.rect.left = hits[0].rect.right self.p.vel.y = 0 #self.p.acc.y = 0 #print(f"Collision with {hits[0].name}") else: self.collide = False def draw(self): self.screen.fill(BLACK) self.sprites.draw(self.screen) self.drawtext(f"X Pos: = {int(self.p.pos.x)}", 15, WHITE, WIDTH - 5, 20, 3) self.drawtext(f"Y Pos: = {int(self.p.pos.y)}", 15, WHITE, WIDTH - 5, 40, 3) self.drawtext(f"Y Velocity = {self.p.vel.y}", 15, WHITE, 5, 50, 0) self.drawtext(f"Y Accelleration = {self.p.acc.y}", 15, WHITE, 5, 70, 0) self.drawtext(f"Collision: = {self.collide}", 15, WHITE, 5, 200, 0) #print(self.p.vel.y) pg.display.flip() # other functions def drawtext(self, text, size, color, x, y, align): font = pg.font.Font(self.font, size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() if align == 0: text_rect.midleft = (x, y) elif align == 1: text_rect.midtop = (x, y) elif align == 2: text_rect.midbottom = (x, y) elif align == 3: text_rect.midright = (x, y) else: text_rect.center = (x, y) self.screen.blit(text_surface, text_rect) # def checkCollisionY(self): # hits = pg.sprite.spritecollide(self.p, self.objects, False) # if hits: # self.collide = True # return True # else: # self.collide = False # return False g = Game() while g.running: g.new() pg.quit() Sprites.py: from settings import * import pygame as pg vec = pg.math.Vector2 class Player(pg.sprite.Sprite): def __init__(self, game): pg.sprite.Sprite.__init__(self) self.game = game self.width = 30 self.height = 30 self.image = pg.Surface((self.width, self.height)) self.image.fill(YELLOW) self.rect = self.image.get_rect() self.rect.center = vec(150, 100) self.pos = vec(150, 100) self.vel = vec(0, 0) self.acc = vec(0, 0) def update(self): self.acc = vec(0, PLAYER_GRAV) #input keys = pg.key.get_pressed() if keys[pg.K_LEFT]: self.acc.x = -PLAYER_ACC if keys[pg.K_RIGHT]: self.acc.x = PLAYER_ACC self.acc.x += self.vel.x * PLAYER_FRICTION self.vel += self.acc self.pos += self.vel + 0.5 * self.acc print(f"{self.vel.y} + 0.5 * {self.acc.y} = {self.vel.y + 0.5 * self.acc.y}") self.rect.topleft = self.pos def jump(self): hits = pg.sprite.spritecollide(self, self.game.objects, False) if hits: self.vel.y = -20 class Object(pg.sprite.Sprite): def __init__(self, x, y, w, h): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((w, h)) self.image.fill((255, 0, 144)) self.name = "Object" self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y class Ground(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.name = "Ground" self.image = pg.image.load("ground.png") self.rect = self.image.get_rect() self.rect.x = -100 self.rect.y = 550 Settings.py: # game settings TITLE = "My Game" WIDTH = 480 HEIGHT = 800 FPS = 60 FONT_NAME = 'impact' #Player properties PLAYER_ACC = 0.7 PLAYER_FRICTION = -0.12 PLAYER_GRAV = 0.7 # define colors WHITE = (255, 255, 255) BLACK = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) YELLOW = (255, 255, 0) CYAN = (0, 255, 255) PURPLE = (255, 0, 255) The important code here is the update() in main.py and update() in sprites.py. Help? EDIT hits = pg.sprite.spritecollide(self.p, self.objects, False) for hit in hits: self.collide = True if self.p.vel.x > 0.0: self.p.rect.right = hit.rect.left self.p.pos.x = self.p.rect.centerx self.p.vel.x = 0 elif self.p.vel.x < 0.0: self.p.rect.left = hit.rect.right self.p.pos.x = self.p.rect.centerx self.p.vel.x = 0 self.p.pos.x = self.p.rect.x else: self.collide = False hits = pg.sprite.spritecollide(self.p, self.objects, False) for hit in hits: self.collide = True if self.p.vel.y >= 0.0: self.p.rect.bottom = hit.rect.top self.p.pos.y = self.p.rect.centery self.p.vel.y = 0 elif self.p.vel.y < 0.0: self.p.rect.top = hit.rect.bottom self.p.pos.y = self.p.rect.centery self.p.vel.y = 0 self.p.pos.y = self.p.rect.y else: self.collide = False
Your Player class doesn't have x and y attributes but a pos attribute which you need to change after a collision. The rect of the object needs to be updated as well and it's better to do that first and then set the pos.y coordinate to the rect.centery coordinate afterwards. if self.p.vel.y >= 0.0: self.p.rect.bottom = hits[0].rect.top self.p.pos.y = self.p.rect.centery self.p.vel.y = 0 Do the same for the other directions. Also, the horizontal and vertical movement should be handled separately, otherwise you'll see odd jumps for example from the side to the top of a platform. Take a look at the first part of this platformer example. And in the jump method you need to move the rect down by 1 pixel so that it's able to collide with the platform sprites. def jump(self): self.rect.y += 1 # ... Here's a complete, runnable example: import pygame as pg # game settings TITLE = "My Game" WIDTH = 480 HEIGHT = 800 FPS = 60 FONT_NAME = 'impact' #Player properties PLAYER_ACC = 0.7 PLAYER_FRICTION = -0.12 PLAYER_GRAV = 0.7 # define colors WHITE = (255, 255, 255) BLACK = (0, 0, 0) YELLOW = (255, 255, 0) vec = pg.math.Vector2 class Player(pg.sprite.Sprite): def __init__(self, game): pg.sprite.Sprite.__init__(self) self.game = game self.image = pg.Surface((30, 30)) self.image.fill(YELLOW) self.rect = self.image.get_rect(center=(150, 100)) self.pos = vec(150, 100) self.vel = vec(0, 0) self.acc = vec(0, 0) self.objects = game.objects def update(self): self.acc = vec(0, PLAYER_GRAV) #input keys = pg.key.get_pressed() if keys[pg.K_LEFT]: self.acc.x = -PLAYER_ACC if keys[pg.K_RIGHT]: self.acc.x = PLAYER_ACC self.acc.x += self.vel.x * PLAYER_FRICTION self.vel += self.acc # Move along the x-axis first. self.pos.x += self.vel.x + 0.5 * self.acc.x # print(f"{self.vel.y} + 0.5 * {self.acc.y} = {self.vel.y + 0.5 * self.acc.y}") self.rect.centerx = self.pos.x # Check if the sprite collides with a platform. hits = pg.sprite.spritecollide(self, self.objects, False) if hits: # Reset the x position. if self.vel.x > 0: self.rect.right = hits[0].rect.left self.pos.x = self.rect.centerx self.vel.x = 0 elif self.vel.x < 0: self.rect.left = hits[0].rect.right self.pos.x = self.rect.centerx self.vel.x = 0 # Move along the y-axis. self.pos.y += self.vel.y + 0.5 * self.acc.y self.rect.centery = self.pos.y # Check if the sprite collides with a platform. hits = pg.sprite.spritecollide(self, self.objects, False) if hits: # Reset the y position. if self.vel.y >= 0.0: self.rect.bottom = hits[0].rect.top self.pos.y = self.rect.centery self.vel.y = 0 elif self.vel.y < 0: self.rect.top = hits[0].rect.bottom self.pos.y = self.rect.centery self.vel.y = 0 def jump(self): self.rect.y += 1 # Move it down to check if it collides with a platform. hits = pg.sprite.spritecollide(self, self.game.objects, False) if hits: self.vel.y = -20 self.rect.y -= 1 # Move it up again after the collision check. class Object(pg.sprite.Sprite): def __init__(self, x, y, w, h): pg.sprite.Sprite.__init__(self) self.image = pg.Surface((w, h)) self.image.fill((255, 0, 144)) self.name = "Object" self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y class Ground(pg.sprite.Sprite): def __init__(self): pg.sprite.Sprite.__init__(self) self.name = "Ground" self.image = pg.Surface((500, 300)) self.image.fill((90, 30, 30)) self.rect = self.image.get_rect() self.rect.x = -100 self.rect.y = 550 class Game: def __init__(self): pg.init() pg.mixer.init() self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) self.clock = pg.time.Clock() self.font = pg.font.match_font(FONT_NAME) self.running = True self.playing = True def new(self): self.sprites = pg.sprite.Group() self.objects = pg.sprite.Group() self.p = Player(self) self.sprites.add(self.p) self.g = Ground() self.sprites.add(self.g) self.objects.add(self.g) rects = [(100, 350, 100, 20), (50, 380, 100, 20), (200, 450, 100, 100)] for x, y, w, h in rects: obj = Object(x, y, w, h) self.sprites.add(obj) self.objects.add(obj) self.collide = False self.run() def run(self): while self.playing: self.clock.tick(FPS) self.events() self.update() self.draw() self.running = False def events(self): for event in pg.event.get(): if event.type == pg.QUIT: self.playing = False if event.type == pg.KEYDOWN: if event.key == pg.K_UP: self.p.jump() def update(self): self.sprites.update() def draw(self): self.screen.fill(BLACK) self.sprites.draw(self.screen) pg.display.flip() g = Game() while g.running: g.new() pg.quit()
Collision detection not working in pygame
I am making a game at the moment and I am experiencing problems with collision detection. I am making an end of level block but it can not detect if the player is standing on it to change to level 2. The collision detection for the block is found in player.updater(). As well as this the block is a class and in a group called endPlatform to allow the collision detection to work. The game runs perfectly fine however it can not detect when the Player hits Endplatform. I get no errors which show up. EndPlatform: class EndPlatform(pygame.sprite.Sprite): def __init__(self, display): super().__init__() self.image = pygame.image.load("endPlatform.png") self.rect = self.image.get_rect() display.blit(self.image, self.rect) Player: class Player(pygame.sprite.Sprite): def __init__(self): super().__init__() # Is it touching the floor? self.standing = True # Rendering image and creating some variables self.image = pygame.image.load("Slime.png") self.sprite_x_change = 0 self.sprite_y_change = 0 self.rect = self.image.get_rect() self.rect.y = 460 self.rect.x = 120 # Mobility: Left, right, up and stop def move_right(self): self.sprite_x_change = 8 def move_left(self): self.sprite_x_change = -8 def move_up(self, platform): if self.standing == True: self.sprite_y_change = -25 self.standing = False def stop(self): self.sprite_x_change = 0 def sprint(self): self.sprite_x_change += 10 def updater(self, platforms, powerups, score, endPlatform): self.gravity() self.rect.x += self.sprite_x_change self.standing = False platforms_hit = pygame.sprite.spritecollide(self, platforms, False) for blocks in platforms_hit: if self.sprite_x_change > 0: self.rect.right = blocks.rect.left elif self.sprite_x_change < 0: self.rect.left = blocks.rect.right self.rect.y += self.sprite_y_change platforms_hit = pygame.sprite.spritecollide(self, platforms, False) for blocks in platforms_hit: # Going down if self.sprite_y_change > 0: self.rect.bottom = blocks.rect.top - 1 self.standing = True # Going up elif self.sprite_y_change < 0: self.rect.top = blocks.rect.bottom self.standing = False self.sprite_y_change = 0 coins_hit = pygame.sprite.spritecollide(self, powerups, True) if len(coins_hit) > 0: score.add() endLevel = pygame.sprite.spritecollide(self, endPlatform, True) if len(endLevel) > 0: score.add() All the code: import pygame import random pygame.font.init() # Colours + Global constants WHITE = (255, 255, 255) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) BLACK = (0, 0, 0) RANDOM = (12, 211, 123) WIDTH = 800 HEIGHT = 600 SIZE = (WIDTH, HEIGHT) AGENT = pygame.font.SysFont("Agent Orange", 30) # CLASSES # Block is the common platform class EndPlatform(pygame.sprite.Sprite): def __init__(self, display): super().__init__() self.image = pygame.image.load("endPlatform.png") self.rect = self.image.get_rect() display.blit(self.image, self.rect) class Coins(pygame.sprite.Sprite): def __init__(self, display): super().__init__() self.image = pygame.image.load("hud_coins.png") self.rect = self.image.get_rect() display.blit(self.image, self.rect) class Score: def __init__(self): self.score = 0 def msgs(self, msg, colour, display): screen_text = AGENT.render(msg, True, colour) display.blit(screen_text, [0, 0]) def add(self): self.score += 1 class Monster(pygame.sprite.Sprite): def __init__(self, length, height, colour): super().__init__() self.image = pygame.Surface([length, height]) self.image.fill(colour) self.rect = self.image.get_rect() # Setting Y coordinates self.rect.y = HEIGHT - 80 def jump(self): self.rect.y = -10 class Block(pygame.sprite.Sprite): def __init__(self, length, height, colour): super().__init__() # Making image self.image = pygame.Surface([length, height]) self.image.fill(colour) self.rect = self.image.get_rect() # Setting Y coordinates self.rect.y = 468 class Platform(pygame.sprite.Sprite): def __init__(self, display, x_screen, y_screen, x_sheet, y_sheet, height, length): super().__init__() self.tiles = pygame.image.load("tiles_spritesheet.png") self.image = self.tiles.subsurface(pygame.Rect(x_sheet, y_sheet, height, length)) self.rect = self.image.get_rect(x=x_screen, y=y_screen) class Player(pygame.sprite.Sprite): def __init__(self): super().__init__() # Is it touching the floor? self.standing = True # Rendering image and creating some variables self.image = pygame.image.load("Slime.png") self.sprite_x_change = 0 self.sprite_y_change = 0 self.rect = self.image.get_rect() self.rect.y = 460 self.rect.x = 120 # Mobility: Left, right, up and stop def move_right(self): self.sprite_x_change = 8 def move_left(self): self.sprite_x_change = -8 def move_up(self, platform): if self.standing == True: self.sprite_y_change = -25 self.standing = False def stop(self): self.sprite_x_change = 0 def sprint(self): self.sprite_x_change += 10 def updater(self, platforms, powerups, score, endPlatform): self.gravity() self.rect.x += self.sprite_x_change self.standing = False platforms_hit = pygame.sprite.spritecollide(self, platforms, False) for blocks in platforms_hit: if self.sprite_x_change > 0: self.rect.right = blocks.rect.left elif self.sprite_x_change < 0: self.rect.left = blocks.rect.right self.rect.y += self.sprite_y_change platforms_hit = pygame.sprite.spritecollide(self, platforms, False) for blocks in platforms_hit: # Going down if self.sprite_y_change > 0: self.rect.bottom = blocks.rect.top - 1 self.standing = True # Going up elif self.sprite_y_change < 0: self.rect.top = blocks.rect.bottom self.standing = False self.sprite_y_change = 0 coins_hit = pygame.sprite.spritecollide(self, powerups, True) if len(coins_hit) > 0: score.add() endLevel = pygame.sprite.spritecollide(self, endPlatform, True) if len(endLevel) > 0: score.add() def gravity(self): self.sprite_y_change += 3 class Level: def __init__(self): # Creating groups self.endPlatform = pygame.sprite.Group() self.powerups = pygame.sprite.Group() self.sprites = pygame.sprite.Group() self.all_things = pygame.sprite.Group() self.platforms = pygame.sprite.Group() self.entities = pygame.sprite.Group() self.shift_x = 0 self.shift_y = 0 def updater(self, display, score): self.all_things.draw(display) score.msgs("Score: " + str(score.score), RED, display) def scroll_x(self, shift_x_change): self.shift_x += shift_x_change for platform in self.entities: platform.rect.x += shift_x_change def scroll_y(self, shift_y_change): self.shift_y += shift_y_change for platform in self.entities: platform.rect.y += shift_y_change class Level01(Level): def __init__(self, player1, monster, display): # Initialise level1 super().__init__() # Level01 things block = Block(245, 3, BLACK) Level.all_things = self.all_things self.sprites.add(player1, monster) self.platforms.add(block) self.all_things.add(player1, block, monster) self.entities.add(block) theLevel = [] level = [[600, 400, 648, 0, 70, 70], [740, 320, 648, 0, 70, 70], [380, 400, 648, 0, 70, 70], [900, 280, 648, 0, 70, 70], [1200, 530, 648, 0, 70, 70], [1350, 450, 648, 0, 70, 70], [1500, 550, 648, 0, 70, 70], [1680, 500, 648, 0, 70, 70], ] for platform in theLevel: block = Block(platform[0], platform[1], RED) block.rect.x = platform[2] block.rect.y = platform[3] self.platforms.add(block) self.all_things.add(block) self.entities.add(block) for goodPlatform in level: platform = Platform(display, goodPlatform[0], goodPlatform[1], goodPlatform[2], goodPlatform[3], goodPlatform[4], goodPlatform[5]) self.platforms.add(platform) self.all_things.add(platform) self.entities.add(platform) for n in range(1): coin = Coins(display) coin.rect.x = random.randint(0, WIDTH*3) coin.rect.y = 400 self.all_things.add(coin) self.entities.add(coin) self.powerups.add(coin) platforms_hit = pygame.sprite.spritecollide(coin, self.entities, False) for hit in platforms_hit: coin.rect.x = random.randrange(0, WIDTH*3) finalPlatform = EndPlatform(display) finalPlatform.rect.x = 1900 finalPlatform.rect.y = 420 self.all_things.add(finalPlatform) self.entities.add(finalPlatform) self.platforms.add(finalPlatform) self.endPlatform.add(finalPlatform) class Level02(Level): def __init__(self, player1, monster): super().__init__() # Level01 things block = Block(245, 3, BLACK) Level.all_things = self.all_things self.sprites.add(player1, monster) self.platforms.add(block) self.all_things.add(player1, block, monster) def main(): # Init pygame pygame.init() # Set screen backgrounds = ["background2.jpg", "background.jpg"] background = pygame.image.load(backgrounds[0]) backgroundRect = background.get_rect() display = pygame.display.set_mode(background.get_size()) # Creating FPS thingy clock = pygame.time.Clock() # Making levels + Player score = Score() monster = Monster(30, 30, RANDOM) player = Player() level_1 = Level01(player, monster, display) level_2 = Level02(player, monster) # Choosing level levelList = [] levelList.append(level_1) levelList.append(level_2) currentLevelNumber = 0 # Game loop loop = True while loop == True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_RIGHT: player.move_right() if event.key == pygame.K_LEFT: player.move_left() if event.key == pygame.K_UP: player.move_up(currentLevel.platforms) if event.key == pygame.KMOD_LSHIFT and event.key == pygame.K_RIGHT: player.sprint() if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT and player.sprite_x_change < 0: player.stop() if event.key == pygame.K_RIGHT and player.sprite_x_change > 0: player.stop() if event.key == pygame.KMOD_LSHIFT: player.sprite_x_change -= 10 # Update things #monster.jump() if player.rect.x > 400: player.rect.x = 400 currentLevel.scroll_x(-10) if player.rect.x >= WIDTH: player.rect.x = WIDTH currentLevel.scroll(0) if player.rect.y >= HEIGHT: main() if player.sprite_x_change < 0 and player.rect.x >= 120: currentLevel.scroll_x(0) if player.rect.left <= 120 and player.sprite_x_change < 0: player.rect.x = 120 player.rect.left = 120 currentLevel.scroll_x(10) ''' if player.rect.y <= 300: if player.standing == False and player.sprite_y_change < 0: currentLevel.scroll_y(10) if currentLevel.shift_y > 0: y_speed = -4 if player.standing == True and player.rect.y < 300: y_speed = 4 print(currentLevel.shift_y) currentLevel.scroll_y(y_speed) ''' currentLevel = levelList[currentLevelNumber] if currentLevel.shift_x > 0: currentLevel.scroll_x(currentLevel.shift_x * -1) display.blit(background, backgroundRect) player.updater(currentLevel.platforms, currentLevel.powerups, score, currentLevel.endPlatform) currentLevel.updater(display, score) # Refresh screen clock.tick(30) pygame.display.update() pygame.quit() loop = False if __name__ == "__main__": main()
It seems I found the problem, for some daft reason you can't use collision detection twice on the same object. I used it once so that the player could stand on the block and another time so that you could go on to the next level!
The reason why it doesn't switch to the next level is that you change the position of the rect when it collides with a platform, so the player.rect gets moved out of the blocks.rect and therefore can't collide again when you call spritecollide with the endPlatform group. A quick and dirty fix would be to check in the for blocks in platforms_hit: loops if the block is in the endPlatform group and then return True: for blocks in platforms_hit: if blocks in endPlatform: score.add() return True And then increase the currentLevelNumber in the main function if True is returned: change_level = player.updater(currentLevel.platforms, currentLevel.powerups, score, currentLevel.endPlatform) if change_level: currentLevelNumber += 1
__init__() takes exactly 3 arguments (1 given)?
It is asking for 3 arguments and i have given it one. How do i give it 2 more and could you explain how to do that as well? Thanks import pygame, random, collisionObjects pygame.init() screen = pygame.display.set_mode((640,480)) class Pirate(pygame.sprite.Sprite): EAST = 0 def __init__(self, screen, dx): self.screen = screen pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("king_pirate/running e0000.bmp") self.image = self.image.convert() tranColor = self.image.get_at((1, 1)) self.image.set_colorkey(tranColor) self.rect = self.image.get_rect() self.rect.inflate_ip(-50, -30) self.rect.center = (0, random.randrange(30,450)) self.img = [] self.loadPics() self.frame = 0 self.delay = 4 self.pause = self.delay self.dx = dx def update(self): #set delay self.pause -= 1 if self.pause <= 0: self.pause = self.delay self.frame += 1 if self.frame > 7: self.frame = 0 self.image = self.img[self.frame] self.rect.centerx += self.dx if self.rect.centerx > self.screen.get_width(): self.rect.centerx = 0 self.rect.centery = random.randrange(30,450) #load pictures def loadPics(self): for i in range(8): imgName = "king_pirate/running e000%d.bmp" % i tmpImg = pygame.image.load(imgName) tmpImg.convert() tranColor = tmpImg.get_at((0, 0)) tmpImg.set_colorkey(tranColor) self.img.append(tmpImg) class Pirate2(pygame.sprite.Sprite): WEST = 0 def __init__(self, screen, dx): self.screen = screen pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("pirate/running w0000.bmp") self.image = self.image.convert() tranColor = self.image.get_at((1, 1)) self.image.set_colorkey(tranColor) self.rect = self.image.get_rect() self.rect.inflate_ip(-50, -30) self.rect.center = (640, random.randrange(20,460)) self.img = [] self.loadPics() self.frame = 0 self.delay = 4 self.pause = self.delay self.dx = dx def update(self): #set delay self.pause -= 1 if self.pause <= 0: self.pause = self.delay self.frame += 1 if self.frame > 7: self.frame = 0 self.image = self.img[self.frame] self.rect.centerx -= self.dx if self.rect.centerx < 0: self.rect.centerx = self.screen.get_width() self.rect.centery = random.randrange(20,460) #load pictures def loadPics(self): for i in range(8): imgName = "pirate/running w000%d.bmp" % i tmpImg = pygame.image.load(imgName) tmpImg.convert() tranColor = tmpImg.get_at((0, 0)) tmpImg.set_colorkey(tranColor) self.img.append(tmpImg) #set up class for gold object, class Gold(pygame.sprite.Sprite): def __init__(self, screen, imageFile): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(imageFile) self.image = self.image.convert() self.rect = self.image.get_rect() self.rect.centerx = random.randrange(0, screen.get_width()) self.rect.centery = random.randrange(0, screen.get_height()) #main character class class Thief(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load("thief2.gif") self.image = self.image.convert() tranColor = self.image.get_at((1, 1)) self.image.set_colorkey(tranColor) self.rect = self.image.get_rect() self.rect.inflate_ip(-15, -10) self.rect.center = (30, (screen.get_height()-40)) self.dx = 30 self.dy = 30 if not pygame.mixer: print("problem with sound") else: pygame.mixer.init() self.collectcoin = pygame.mixer.Sound("collectcoin.wav") self.hit = pygame.mixer.Sound("hit.ogg") def update(self): if self.rect.bottom > screen.get_height(): self.rect.centery = (screen.get_height()-40) elif self.rect.top < 0: self.rect.centery = 40 elif self.rect.right > screen.get_width(): self.rect.centerx = (screen.get_width()-30) elif self.rect.left < 0: self.rect.centerx = 30 #define movements def moveUp(self): self.rect.centery -= self.dy def moveDown(self): self.rect.centery += self.dy def moveLeft(self): self.rect.centerx -= self.dx def moveRight(self): self.rect.centerx += self.dx def reset(self): self.rect.center = (30, (screen.get_height()-40)) #set up a scoreboard class Scoreboard(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.lives = 0 self.score = 0 self.font = pygame.font.SysFont("None", 40) self.number = 0 #with a self updating label def update(self): self.text = "Damage: %d %% Gold Taken: %d" % (self.lives, self.score) self.image = self.font.render(self.text, 1, (199,237,241)) self.rect = self.image.get_rect() #define the game function def game(): #set up background background = pygame.Surface(screen.get_size()) background = pygame.image.load("sand.jpg") background = pygame.transform.scale(background, screen.get_size()) screen.blit(background, (0, 0)) #initialize pirates & scoreboard sprites pirate = Pirate() scoreboard = Scoreboard() #create two arrays for multiple gold object occurances #two arrays are used for better distribution on screen gold1 = [] numberofGold = 16 for i in range(numberofgolds): oneGold = golds(screen,"gold1.png") golds1.append(onegold) for gold in golds1: gold.rect.centerx = random.randrange(20,620) gold.rect.centery = random.randrange(20,240) gold.rect.inflate_ip(-5, -5) gold2 = [] for i in range(numberofgolds): onegold = golds(screen,"gold1.png") golds2.append(onegold) for gold in golds2: gold.rect.centerx = random.randrange(20,620) gold.rect.centery = random.randrange(250,460) gold.rect.inflate_ip(-5, -5) totalgolds = ((len(golds1)-1)+(len(golds2)-1)) #initialize gold sprites goldSprites = pygame.sprite.Group(golds1, #initialize pirate sprites & instances pirate1 = pirate1(screen,13) pirate2 = pirate2(screen,13) pirate3 = pirate1(screen,11) pirate4 = pirate2(screen,11) pirate5 = pirate1(screen,13) pirateSprites = pygame.sprite.Group(pirate1, pirate2, pirate3, pirate4, pirate5) #use ordered updates to keep clean appearance allSprites = pygame.sprite.OrderedUpdates(goldSprites, thief, pirateSprites, scoreboard) #set up clock & loop clock = pygame.time.Clock() keepGoing = True while keepGoing: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: keepGoing = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: thief.moveUp() elif event.key == pygame.K_DOWN: thief.moveDown() elif event.key == pygame.K_LEFT: thief.moveLeft() elif event.key == pygame.K_RIGHT: thief.moveRight() elif event.key == pygame.K_ESCAPE: keepGoing = False #check collisions here hitpirates = pygame.sprite.spritecollide(thief, pirateSprites, False) hitgold = pygame.sprite.spritecollide(thief, goldSprites, True) if hitpirates: thief.hit.play() scoreboard.lives += 1 if scoreboard.lives >= 100: keepGoing = False number = 0 if hitgolds: thief.collectcoin.play() scoreboard.score += 1 totalgolds -= 1 if totalgolds <= 0: keepGoing = False number = 1 #draw sprites allSprites.clear(screen, background) allSprites.update() allSprites.draw(screen) pygame.display.flip() return scoreboard.score return scoreboard.number def instructions(score, number): pygame.display.set_caption("Hunt for Gold!") background = pygame.Surface(screen.get_size()) background = pygame.image.load("sand.jpg") background = pygame.transform.scale(background, screen.get_size()) screen.blit(background, (0, 0)) if number == 0: message = "Sorry try again..." elif number == 1: message = "The theif escapes!" else: message = "Onto the hunt for gold!" insFont = pygame.font.SysFont("Calibri", 25) insLabels = [] instructions = ( "Last score: %d" % score , "%s" % message, "", "GOLD!", "Get all the gold before you are " "obliterated!", "Use arrow keys to move the thief.", "Space to start, Esc to quit." ) for line in instructions: tempLabel = insFont.render(line, 1 , (0,0,0)) insLabels.append(tempLabel) #set up homescreen loop keepGoing = True clock = pygame.time.Clock() while keepGoing: clock.tick(30) for event in pygame.event.get(): if event.type == pygame.QUIT: keepGoing = False donePlaying = True if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: keepGoing = False donePlaying = False if event.key == pygame.K_ESCAPE: keepGoing = False donePlaying = True for i in range(len(insLabels)): screen.blit(insLabels[i], (50, 30*i)) pygame.display.flip() return donePlaying #define main function def main(): donePlaying = False score = 0 message = "" while not donePlaying: donePlaying = instructions(score, message) if not donePlaying: score = game() else: pygame.quit() if __name__ == "__main__": main()
Glancing at your code, this line: pirate = Pirate() Your Pirate class expects self, screen, dx. You only implicitly provide self. I can only guess at what you want, especially since I don't know off the bat what dx is supposed to mean in respect to your game, but this will probably at least avoid the error: pirate = Pirate(pygame.display.get_surface(), 60)