Player has ability to stand on iterable platforms, but he can't stand on the not iterable platform - Platform4. How to correct this problem?
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
pygame.sprite.Sprite.__init__(self)
# [...]
def update(self):
hits_4 = pygame.sprite.spritecollide(player, platform4, False)
if hits_4:
self.pos.y = hits_4[0].rect.top + 1
self.vel.y = 0
class Platform4(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = platform_images4
self.image.set_colorkey(WHITE1)
self.rect = self.image.get_rect()
self.rect.centerx = 300
self.rect.centery = 500
def update(self):
self.rect.move_ip(-1, 0)
if self.rect.right <= 0:
self.kill()
platform4 = Platform4()
all_sprites = pygame.sprite.Group()
all_sprites.add(player, fire, platform4)
platform4 is a pygame.sprite.Sprite object. For the collision of 2 Sprite objets you have to use pygame.sprite.collide_rect:
hits_4 = pygame.sprite.spritecollide(player, platform4, False)
hits_4 = pygame.sprite.collide_rect(player, platform4)
Related
I have been trying to create a game form scratch in Python using Pygame. I followed a tutorial for the most part and have hit a wall. The game is a simple platformer and I'm having trouble adding in collisions. I have looked at many other examples but cant seem to find where abouts to add in the pygame.sprite.collide_rect command and how to get it to stop the players y velocity so that he stops ontop of a platform. Any help would be greatly appreciated! Thanks.
The code
import random
import pygame as pg
pg.init()
icon = pg.image.load("soldier.png")
pg.display.set_icon(icon)
backgroundimage = pg.image.load("background.png")
FPS = 50
Width = 512
Height = 384
Red = (255, 0, 0)
#vec = pg.math.Vector2
class platform(pg.sprite.Sprite):
def __init__(self, x, y):
pg.sprite.Sprite.__init__(self)
self.image = pg.image.load("plat.png")
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
class Player(pg.sprite.Sprite):
def __init__(self):
pg.sprite.Sprite.__init__(self)
self.image = pg.image.load("Spaceman.png")
self.rect = self.image.get_rect()
self.rect.center = (Width / 2, Height / 2)
self.vx = 0
self.vy = 0
#self.pos = vec(Width / 2, Height / 2)
self.acc = 0.2
def update(self):
self.vy = self.vy + self.acc
self.vx = 0
#self.acc = vec(0, 0.5)
keys = pg.key.get_pressed()
if keys[pg.K_SPACE]:
while self.vy > 0:
self.vy = -5 + self.acc
if keys[pg.K_LEFT]:
self.vx = -5
self.image = pg.image.load("Spaceman2.png")
if keys[pg.K_RIGHT]:
self.vx = 5
self.image = pg.image.load("Spaceman.png")
self.rect.x += self.vx
self.rect.y += self.vy
if self.rect.left > Width:
self.rect.right = 0
if self.rect.right < 0:
self.rect.left = Width
class Game:
def __init__(self):
pg.init()
pg.mixer.init()
self.screen = pg.display.set_mode((Width,Height))
pg.display.set_caption("OH NOOOO")
self.clock = pg.time.Clock()
self.running = True
def new(self):
self.all_sprites = pg.sprite.Group()
self.platforms = pg.sprite.Group()
self.soldier = pg.sprite.Group()
self.player = Player()
self.all_sprites.add(self.player)
self.soldier.add(self.player)
p1 = platform(200, 200)
self.all_sprites.add(p1)
self.platforms.add(p1)
self.run()
def run(self):
self.playing = True
while self.playing:
self.clock.tick(FPS)
self.events()
self.update()
self.draw()
def update(self):
self.screen.blit(backgroundimage,[0,0])
self.all_sprites.update()
def events(self):
for event in pg.event.get():
if event.type == pg.QUIT:
if self.playing:
self.playing = False
self.running = False
def draw(self):
self.all_sprites.draw(self.screen)
pg.display.flip()
def show_start_screen(self):
pass
def show_go_screen(self):
pass
g = Game()
g.show_start_screen()
while g.running:
g.new()
g.show_go_screen()
pg.quit()
This is all of the code so far and I've made three groups within this code; all_sprites, soldier and platforms but cant figure out how to make soldier and platforms groups collide. Any help is greatly appreciated thanks!
Use pygame.sprite.groupcollide() to detect the collision of pygame.sprite.Sprite objects in 2 separate pygame.sprite.Groups:
if pygame.sprite.groupcollide(self.soldier, self.platforms, False, Fasle):
print("hit")
class NPC(pg.sprite.Sprite):
def __init__(self,x,y,image):
self.copyimg = pg.image.load(image).convert_alpha()
pg.sprite.Sprite.__init__(self)
self.image = self.copyimg.copy()
#self.copyimg.fill(RED)
self.rect = self.image.get_rect()
self.radius = int(self.rect.width / 3)
#pg.draw.circle(self.copyimg,RED,self.rect.center,self.radius)
self.rect.center = (x,y)
self.pos = vec(x,y)
self.vel = vec(0,0)
self.acc = vec(0,0)
self.speed = 0.3
self.friction = -0.02
self.rot = 0
self.chasex = True
self.chasey = True
self.directing = 1
self.times = pg.time.get_ticks()
self.mainmenu = True
def rotate(self):
self.rot = self.rot % 360
newimage = pg.transform.rotate(self.copyimg,int(self.rot%360))
#pg.draw.rect(screen,WHITE,self.rect,5)
#old_center = self.rect.center
self.image = newimage
self.rect = self.image.get_rect()
#self.rect.center = old_center
def shoot(self):
bullet = BulletPlayer(self.pos.x,self.pos.y,self.rot,lasers['laserblue'][random.randint(0,len(lasers['laserblue'])-1)])
bulletgroupenemy.add(bullet)
pass
class Bullet(pg.sprite.Sprite):
def __init__(self,x,y,rotation,image):
pg.sprite.Sprite.__init__(self)
self.cop = pg.image.load(image).convert_alpha()
self.image = self.cop.copy()
self.rect = self.image.get_rect()
self.rect.bottom = y
self.rect.centerx = x
self.shootspeed = 10
self.rotation = rotation
def update(self):
self.rotation = self.rotation % 360
newimage = pg.transform.rotate(self.cop,int(self.rotation))
oldcenter = self.rect.center
self.image = newimage
self.rect = self.image.get_rect()
self.rect.center = oldcenter
keys = pg.key.get_pressed()
if self.rect.x < 0 or self.rect.x >WIDTH or self.rect.y > HEIGHT or self.rect.y < 0:
self.kill()
I have a NPC class and bullet class like that and ofcourse there is mainplayer that we can control. and as you can see there is shoot method with in the NPC class. this is calling automatically
by npc it self how ever when i shoot npc with a bullet and call spritecollide function
hitsenemy = pg.sprite.spritecollide(playerlist[i],bulletgroup,True)
if hitsenemy:
playerlist[i].kill()
the npc get kills thats correct but somehow it is keeping to shoot. the shoot function still works how this can be !. i just killed by using this hitsenemy . and also i use this for loop to add spride group. How can i prevent that i dont want it to keep shooting
playerlist = [Player(300,200,'playerShip2_blue.png')]
for players in playerlist:
allsprites.add(players)
playergroup.add(players)
i have also this allsprites group allsprites = pg.sprite.Group()
this method belongs the player class which i didnt share because but this is how i shoot with player class.
def shoot(self):
bullet = BulletPlayer(self.rect.centerx,self.rect.centery,self.rot,lasers['lasergreen'])
bulletgroup.add(bullet)
allsprites.add(bullet)
playerlist is a list but not a pygame.sprite.Group. pygame.sprite.Sprite.kill
remove the Sprite from all Groups
Therefor when you call kill, the Sprite is removed from all Groups but it is still in the playerlist.
You have to remove the Sprite from the list. See How to remove items from a list while iterating?
hitsenemy = pg.sprite.spritecollide(playerlist[i],bulletgroup,True)
if hitsenemy:
playerlist[i].kill()
playerlist.pop(i)
Alternatively, consider using a group instead of a list. Note the Sprites in a Group can be iterated. And the list of Sprites in the Group can be obtained via pygame.sprite.Group.sprites().
I am trying to build a simple version of Flappy Bird. To detect collisions between my circle(Flappy Bird) and my rectangles(Pipes) I was using pygame.sprite.collide_rect() but I wanted a better way of handling collisions.
But using mask collision causes no detection of the collision. The circle passes directly through the rectangle as if it isn't there.
Here is my code:
bird_group = pygame.sprite.Group()
pipe_group = pygame.sprite.Group()
class Bird(pygame.sprite.Sprite):
def __init__(self, x_loc, y_loc, velocity):
super(Bird, self).__init__()
self.velocity = velocity
self.x_loc = x_loc
self.y_loc = y_loc
self.image = pygame.image.load(os.path.join(game_folder,"index2.png")).convert()
self.image.set_colorkey(WHITE)
self.image = pygame.transform.scale(self.image,(60,65))
self.rect = self.image.get_rect()
self.rect.center = (x_loc,y_loc)
def update(self):
self.rect.y += self.velocity
self.velocity = self.velocity+1
self.mask = pygame.mask.from_surface(self.image)
def jump(self):
self.velocity = -10
def boundary_collison(self):
if self.rect.bottom+100>=display_height or self.rect.top<=0:
return True
class UpperPipe(pygame.sprite.Sprite):
"""docstring for UpperPipe"""
def __init__(self, pipe_x, pipe_height, pipe_speed):
super(UpperPipe, self).__init__()
self.pipe_speed = pipe_speed
self.image = pygame.Surface((pipe_width, pipe_height))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.x = (pipe_x)
self.rect.y = (0)
def update(self):
self.rect.x -= self.pipe_speed
self.mask = pygame.mask.from_surface(self.image)
def x_cord(self):
return self.rect.x
class LowerPipe(pygame.sprite.Sprite):
"""docstring for UpperPipe"""
def __init__(self, pipe_x, pipe_height, pipe_speed):
super(LowerPipe, self).__init__()
self.pipe_speed = pipe_speed
self.image = pygame.Surface((pipe_width, display_height-(pipe_gap+pipe_height)))
self.image.fill(GREEN)
self.rect = self.image.get_rect()
self.rect.x = (pipe_x)
self.rect.y = (pipe_height+pipe_gap)
def update(self):
self.rect.x -= self.pipe_speed
self.mask = pygame.mask.from_surface(self.image)
def x_cord(self):
return self.rect.x
The following code I use to make the sprites:
bird = Bird(x_loc,y_loc,velocity)
bird_group.add(bird)
pipe_list = []
init_pipe_x = 500
for make in range(pipe_count):
pipe_x = init_pipe_x+((between_pipe+pipe_width)*make)
pipe_height = (round(random.uniform(0.2,0.8), 2))*(display_height-pipe_gap)
upper = UpperPipe(pipe_x,pipe_height,pipe_speed)
lower = LowerPipe(pipe_x,pipe_height,pipe_speed)
add_pipe = [upper,lower]
pipe_list.append(add_pipe)
pipe_group.add(upper)
pipe_group.add(lower)
For detection inside my game loop I use the following code:
bird_hits = pygame.sprite.spritecollide(bird,pipe_group,False,pygame.sprite.collide_mask)
if bird_hits:
gameExit = True
The pygame.Surfaces that you pass to mask.from_surface must have an alpha channel. That means you either have to call the convert_alpha or the set_colorkey method of the surfaces.
class UpperPipe(pygame.sprite.Sprite):
def __init__(self, pipe_x, pipe_height, pipe_speed):
super(LowerPipe, self).__init__()
self.pipe_speed = pipe_speed
# Either call `convert_alpha` ...
self.image = pygame.Surface((pipe_width, display_height-(pipe_gap+pipe_height))).convert_alpha()
self.image.fill(GREEN)
# ... or call `set_colorkey`.
# I think surfaces converted with convert_alpha are blitted faster.
# self.image.set_colorkey((0, 0, 0))
# You also don't have to create the mask repeatedly in the
# update method. Just call it once in the __init__ method.
self.mask = pygame.mask.from_surface(self.image)
You haven't defined any collide_mask in your class : something like
self.mask = pygame.mask.from_surface(image)
So if the rect of your Upper and lower pipe corresponds to the hitbix of these: simply use
bird_hits = pygame.sprite.spritecollide(bird,pipe_group,False)
or create a self.mask in your class to use
bird_hits = pygame.sprite.spritecollide(bird,pipe_group,False,pygame.sprite.collide_mask)
I've been creating a smup game. The problem is that I have multiple instances of enemies within the game which are supposed to fall from the top of the screen.All of my instances except for one hang at the top of the screen. For some bizarre reason it appears that only one instance of my enemy objects seem to move. I've spent hours trying to fix it to absolutely no avail. I've also browsed a plethora of tutorials on how to create classes, and I can't find anything really wrong with my code. Please help.
import pygame,random,os
from pygame.locals import *
'initialize pygame'
pygame.init()
'set variables'
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
black = (0,0,0)
white = (255,255,255)
width = 1280
height = 720
'create window'
screen = pygame.display.set_mode((1280,720))
clock = pygame.time.Clock()
'sprite groups'
all_sprites = pygame.sprite.Group()
enemies = pygame.sprite.Group()
'classes'
class Player(pygame.sprite.Sprite):
def __init__(self):
self.x, self.y = pygame.mouse.get_pos()
pygame.sprite.Sprite.__init__(self)
#self.image = pygame.Surface((32,32))++--3
#$self.image.fill((green))
self.image = pygame.image.load("vehicle.png")
self.image.set_colorkey(white)
self.rect = self.image.get_rect()
self.rect.center = (width/2,700)
self.speed = 0
def move(self):
self.keypress = pygame.key.get_pressed()
if self.keypress[pygame.K_a]:
self.speed = 3
self.rect.x -= self.speed
if self.keypress[pygame.K_d]:
self.speed = 3
self.rect.x += self.speed
#self.rect.x += 1
if self.rect.left > width:
self.rect.right = 0
if self.rect.right < 0:
self.rect.left = 1280
class Enemy(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("missile.png")
self.rect = self.image.get_rect()
self.rect.x = random.randrange(50,width)
self.rect.y = random.randrange(-100,-40)
self.speedy = random.randrange(1,5)
def enmove(self):
self.rect.y = self.rect.y + self.speedy
if self.rect.top > height:
self.rect.x = random.randrange(50,width)
self.rect.y = random.randrange(-100,-40)
self.speedy = random.randrange(1,5)
class bullet(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.Surface((32,32))
self.rect = self.image.get_rect()
def bmove(self):
pass
player = Player()
for r in range(9):
enemy = Enemy()
enemies.add(enemy)
while True:
pygame.event.pump()
'main loop'
player.move()
enemy.enmove()
all_sprites.add(player)
screen.fill(black)
all_sprites.draw(screen)
enemies.draw(screen)
hits = pygame.sprite.spritecollide(player,enemies,False)
if hits == True:
player.all_sprites.remove(player)
print('true')
all_sprites.update()
pygame.display.update()
print(hits)
Your problem seem to be that you move only last enemy:
enemy.enmove()
You should try iterate your enemies group and move every enemy seperately
this is my first post. I need to make a working game for my final project. Basically the idea is to have the character collide with an Item sprite and Have a random item display on the screen telling the player what the item is and where to take it.
#Initialize
import pygame
import random
pygame.init()
#Display
screen = pygame.display.set_mode((1180, 900))
class PaperBoy(pygame.sprite.Sprite):
def __init__(self,startY):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("paperboy.gif")
self.rect = self.image.get_rect()
self.image = self.image.convert()
self.rect.centery = startY
self.dx= 300
self.dy= 300
def update(self):
#adjust x/y to dx/dy
self.rect.centerx = self.rect.centerx+self.dx
self.rect.centery = self.rect.centery+self.dy
#check Boundaries
#Check right
if self.rect.centerx >= 670:
self.rect.centerx =670
#Check left
elif self.rect.centerx <= 220:
self.rect.centerx = 220
#Check Bottom
if self.rect.centery >= 700:
self.rect.centery = 700
#Check Top
elif self.rect.centery <= 200:
self.rect.centery = 200
def moveUp(self):
self.dx=0
self.dy=-5
def moveDown(self):
self.dx =0
self.dy =5
def moveLeft(self):
self.dx =-5
self.dy = 0
def moveRight(self):
self.dx =5
self.dy =0
"""
mousex, mousey = pygame.mouse.get_pos()
self.rect.centery = mousey
#Check X boundary.
if mousex >= 670:
self.rect.right = 670
elif mousex <= 210:
self.rect.left = 210
else:
self.rect.centerx = mousex
#Check Y boundary.
if mousey >= 670:
self.rect.top = 670
elif mousey >= 250:
self.rect.top = 250
if mousex >= 250 and mousey >= 220:
self.rect.left = 250
self.rect.top = 670
else:
self.rect.centery = mousey
"""
class Parcel(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("parcel.png")
self.rect = self.image.get_rect()
self.image = self.image.convert()
def update(self):
self.rect.center = (200,600)
"""(random.randint(300,800)),(random.randint(300,800))"""
"""
================================HUD======================================
"""
#Green Y
class ItemHUD(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("itemhud.png")
self.rect = self.image.get_rect()
self.image = self.image.convert()
def update(self):
self.rect.center = (950,200)
#Red A
class WhereHUD(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("where.png")
self.rect = self.image.get_rect()
self.image = self.image.convert()
def update(self):
self.rect.center = (950, 350)
#Small Green
class TimeHUD(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("timehud.png")
self.rect = self.image.get_rect()
self.image = self.image.convert()
def update(self):
self.rect.center = (915, 850)
#Yellow
class GoldHUD(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.image = pygame.image.load("gold.png")
self.rect = self.image.get_rect()
self.image = self.image.convert()
def update(self):
self.rect.center = (915, 700)
"""
=================================HUD OBJECTS==============================
"""
"""
------------------------------------MAIN-----------------------------------
"""
def main():
pygame.display.set_caption("A Link to the Parcel")
background = pygame.image.load('village.png').convert()
allSprites=pygame.sprite.Group()
parcel = Parcel()
#Heads up Display
itemHud = ItemHUD()
timeHud = TimeHUD()
goldHud = GoldHUD()
whereHud = WhereHUD()
#Player
paperboy = PaperBoy(200)
#Sprites added to AllSprites Group
allSprites.add(paperboy)
allSprites.add(parcel)
allSprites.add(itemHud)
allSprites.add(timeHud)
allSprites.add(goldHud)
allSprites.add(whereHud)
font = pygame.font.Font(None, 25)
goldSack = 0
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.KEYUP:
if event.key==pygame.K_UP:
paperboy.moveUp()
elif event.key==pygame.K_DOWN:
paperboy.moveDown()
elif event.key==pygame.K_LEFT:
paperboy.moveLeft()
elif event.key==pygame.K_RIGHT:
paperboy.moveRight()
fontTitle = font.render("A Link to the Parcel", True, (255,255,255,))
screen.blit(background, (0, 0))
screen.blit(fontTitle, [925,100])
allSprites.clear(screen, background,)
allSprites.update()
allSprites.draw(screen)
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
If I understand what you mean, you have a bunch of Sprite types, and you want to choose one at random. To do that, just put them all in a list, use random.choice to pick one, and then instantiate it. Like this:
class OneKindOfParcel(Parcel): # etc.
class AnotherKindOfParcel(Parcel): # etc.
class AThirdKindOfParcel(Parcel): # etc.
parcels = [OneKindOfParcel, AnotherKindOfParcel, AThirdKindOfParcel]
# … later …
parceltype = random.choice(parcels)
parcel = parceltype()
allSprites.add(parcel)
You probably want to give it a location, and display something about its name and location, and so on, but I think you know how to do all that.
Quick and dirty is a list of items and then use random.choice from the random module.