I am making a pygame game where you control a spaceship and fire bullets to hit the enemies. As of right now, I am trying to make an enemy appear on the screen. Not making it move yet. However, when I ran my following code, Nothing but the spaceship appeared. The spaceship also was able to move and fire bullets.
This is my current code:
import pygame
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((800, 500))
screen.fill((255, 255, 255))
class Spaceship(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("C:/eqodqfe/spaceship.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.rect.center = (self.x, self.y)
class Bullet(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("C:/eqodqfe/bullet.png")
self.image = pygame.transform.scale(self.image, (100, 100))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.y -= 1
self.rect.center = (self.x, self.y)
if self.y < 0:
self.kill()
class Enemy(Spaceship):
def __init__(self, s, x, y):
Spaceship.__init__(self, s, x, y)
self.image = pygame.image.load("C:/eqodqfe/enemy.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
spaceship = Spaceship(screen, 400, 400)
enemy = Enemy(screen, 100, 100)
bullets = pygame.sprite.Group()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == MOUSEBUTTONDOWN:
bullet = Bullet(screen, spaceship.x, spaceship.y - 20)
bullets.add(bullet)
bullets.update()
key = pygame.key.get_pressed()
if key[pygame.K_a]:
spaceship.x -= 0.5
elif key[pygame.K_d]:
spaceship.x += 0.5
elif key[pygame.K_w]:
spaceship.y -= 0.5
elif key[pygame.K_s]:
spaceship.y += 0.5
spaceship.update()
screen.blit(enemy.image, enemy.rect)
enemy.update()
screen.fill((255, 255, 255))
screen.blit(spaceship.image, spaceship.rect)
bullets.draw(screen)
pygame.display.update()
What is wrong?
You have to draw the enemy after drawing the background. If you draw the enemy before the background, the background will hide the enemy:
running = True
while running:
# [...]
# screen.blit(enemy.image, enemy.rect) <-- DELETE
enemy.update()
screen.fill((255, 255, 255))
screen.blit(enemy.image, enemy.rect) # <-- INSERT
screen.blit(spaceship.image, spaceship.rect)
bullets.draw(screen)
pygame.display.update()
Related
I get the error message 'Enemy' object has no attribute '_Sprite__g' and I have no idea how to use the sprite groups. I'm trying to get them to spawn randomly across the x-axis only.
import pygame, os, random
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(object):
def __init__(self,x,y,width,height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
def draw(self,SCREEN):
SCREEN.blit(self.image, (self.x,self.y))
class B():
def __init__(self,x,y,radius, color):
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
def draw(self,SCREEN):
pygame.draw.circle(SCREEN, self.color, (self.x,self.y),self.radius)
class Enemy(pygame.sprite.Sprite):
def __init__(self):
self.image = pygame.Surface((20,20))
self.x = random.randrange (0,400)
self.y = 500
self.speed = random.randrange(1,3)
def draw (self,SCREEN):
SCREEN.blit(self.image,(self.x,self.y))
player = Player(x, y, width, height)
bullets = []
enemies = pygame.sprite.Group()
# Main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for bullet in bullets:
if bullet.x < 450 and bullet.x >0:
bullet.x += bullet.vel
else:
bullets.pop(bullets.index(bullet))
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
if len(bullets)< 5:
bullets.append(B(round(player.x + player.width //2), round(player.y + player.height//2),3, (0,0,0)))
if keys[pygame.K_w] and player.y > 30 - player.width - player.vel:
player.y -= player.vel
if keys[pygame.K_s] and player.y < 500 - player.width - player.vel:
player.y += player.vel
SCREEN.fill((190, 232, 220))
player.draw(SCREEN)
for bullet in bullets:
bullet.draw(SCREEN)
for i in range (8):
e = Enemy()
enemies.add(e)
pygame.display.update()
pygame.quit()
the obects need to be derives from pygame.sprite.Sprite. The base class needs to be initialized as well. Use super() to delegate to the base class constructor. e.g.:
class Player(object):
def __init__(self,x,y,width,height):
super().__init__()
# [...]
pygame.sprite.Group.draw() and pygame.sprite.Group.update() are methods which are provided by pygame.sprite.Group.
The former delegates the to the update method of the contained pygame.sprite.Sprites - you have to implement the method. See pygame.sprite.Group.update():
Calls the update() method on all Sprites in the Group [...]
The later uses the image and rect attributes of the contained pygame.sprite.Sprites to draw the objects - you have to ensure that the pygame.sprite.Sprites have the required attributes. See pygame.sprite.Group.draw():
Draws the contained Sprites to the Surface argument. This uses the Sprite.image attribute for the source surface, and Sprite.rect. [...]
Therefore the Sprite class must have the attributes .rect and .image. However you don't need the draw method:
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
Create a transparent pygame.Surface with the SRCALPHA flag and draw a circle on it:
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
Add pygame.sprite.Groups for all sprites. add() the player, the enemies and bullets to the Groups:
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
for i in range (8):
e = Enemy()
enemies.add(e)
all_sprites.add(e)
Draw the Sprites in the all_sprites Group with pygame.sprite.Group.draw. Remove a Sprite (form all Groups) with kill:
while running:
# [...]
for bullet in bullets:
if 0 < bullet.rect.y < 500:
bullet.rect.y -= bullet.vel
else:
bullet.kill()
# [...]
all_sprites.draw(SCREEN)
Use the keyboard event instead of pygame.key.get_pressed() to fire a bullet. See How do I stop more than 1 bullet firing at once?:
The collision of the enemies and bullets can be detected with pygame.sprite.groupcollide(). When the doKill arguments are set True, the sprites will be automatically removed:
pygame.sprite.groupcollide(bullets, enemies, True, True)
Complete example:
import pygame, os, random
pygame.init()
FPS=60
SCREEN = pygame.display.set_mode((400,500))
pygame.display.set_caption('caption')
x=50
y=450
vel = 3
width = 20
height = 20
class Player(pygame.sprite.Sprite):
def __init__(self,x,y,width,height):
super().__init__()
self.vel = 3
self.image = pygame.Surface((width, height))
self.image.fill((0,0,0))
self.rect = self.image.get_rect(topleft = (x, y))
class B(pygame.sprite.Sprite):
def __init__(self,x,y,radius, color):
super().__init__()
self.x = x
self.y = y
self.color = color
self.radius = radius
self.vel = vel
self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
pygame.draw.circle(self.image, self.color, (self.radius, self.radius), self.radius)
self.rect = self.image.get_rect(center = (self.x, self.y))
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((20,20))
self.image.fill((255, 0, 0))
y = random.randrange (0, 480)
x = 400
self.rect = self.image.get_rect(topleft = (x, y))
self.speed = random.randrange(1,3)
player = Player(x, y, width, height)
enemies = pygame.sprite.Group()
bullets = pygame.sprite.Group()
all_sprites = pygame.sprite.Group()
all_sprites.add(player)
# Main loop
running = True
clock = pygame.time.Clock()
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and len(bullets) < 5:
bullet = B(player.rect.centerx, player.rect.centery, 3, (0,0,0))
bullets.add(bullet)
all_sprites.add(bullet)
if len(enemies) < 8:
e = Enemy()
enemies.add(e)
all_sprites.add(e)
for bullet in bullets:
if bullet.rect.right < 500:
bullet.rect.x += bullet.vel
else:
bullet.kill()
for enemy in enemies:
if enemy.rect.right > 0:
enemy.rect.x -= enemy.speed
else:
enemy.kill()
pygame.sprite.groupcollide(bullets, enemies, True, True)
keys = pygame.key.get_pressed()
if keys[pygame.K_w] and player.rect.top > player.vel:
player.rect.y -= player.vel
if keys[pygame.K_s] and player.rect.bottom < 500 - player.vel:
player.rect.y += player.vel
SCREEN.fill((190, 232, 220))
all_sprites.draw(SCREEN)
pygame.display.update()
pygame.quit()
Per the documentation:
"When subclassing the Sprite, be sure to call the base initializer before adding the Sprite to Groups."
So the first two lines of Enemy __init__() should be:
def __init__(self):
pygame.sprite.Sprite.__init__(self)
You also need to set a rect for the enemy:
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
I am making a spaceship game where you control a spaceship and fire bullets at the enemies. I am now trying to make a game over background show when the player and any enemy collide, but when I ran the game, the game over background never showed!
This is my current code (Some parts omitted or replaced by --snip--):
class Spaceship(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("spaceship.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.rect.center = (self.x, self.y)
class Bullet(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("bullet.png")
self.image = pygame.transform.scale(self.image, (100, 100))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.y -= 5
self.rect.center = (self.x, self.y)
if self.y < 0:
self.kill()
class Enemy(pygame.sprite.Sprite):
def __init__(self, s, x, y, t):
pygame.sprite.Sprite.__init__(self)
self.type = t
self.screen, self.x, self.y = s, x, y
self.image = pygame.image.load("enemy.png")
self.image = pygame.transform.scale(self.image, (235, 215))
self.rect = self.image.get_rect()
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
self.score_given = get_enemy_given_score()[self.type]
def update(self):
if self.y < 0:
self.kill()
self.y += 3
self.rect.center = (self.x, self.y)
class GameOverBackground(pygame.sprite.Sprite):
def __init__(self, s, x, y, size=(100, 100)):
pygame.sprite.Sprite.__init__(self)
self.screen, self.x, self.y = s, x, y
self.size = size
self.image = pygame.image.load("Game_Over.jpg")
self.image = pygame.transform.scale(self.image, self.size)
self.rect = self.image.get_rect()
def blitme(self):
self.screen.blit(self.image, self.rect)
bg = GameOverBackground(screen, 0, 0)
spaceship = Spaceship(screen, 400, 400)
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
clock = pygame.time.Clock()
enemy_interval = 2000 # It's in milliseconds
enemy_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_event, enemy_interval)
score = 0
font = pygame.font.SysFont("Arial", 30)
textsurface = font.render("Score: {:,}".format(score), True, (0, 0, 0))
spaceship_collided = False
running = True
while running:
--snip--
screen.fill((255, 255, 255)) # DO NOT DRAW ANYTHING IN FRONT OF THIS LINE, I'M WARNING YOU
bullets.update()
key = pygame.key.get_pressed()
amount = 5
if key[pygame.K_a]:
spaceship.x -= amount
--snip--
spaceship.update()
if not spaceship_collided:
screen.blit(spaceship.image, spaceship.rect)
if spaceship_collided is False:
bullets.draw(screen)
enemies.draw(screen)
for i in enemies:
i.update()
if pygame.sprite.spritecollide(i, bullets, True):
score += i.score_given
i.kill()
if score >= 99999:
score = 99999
textsurface = font.render("Score: {:,}".format(score), True, (0, 0, 0))
screen.blit(textsurface, (590, 0))
if pygame.sprite.spritecollide(spaceship, enemies, dokill=True):
spaceship_collided = True
bg.blitme()
pygame.display.update()
clock.tick(60)
Can anybody help me?
The condition pygame.sprite.spritecollide(spaceship, enemies, dokill=True): os only fulfilled in a single frame. If you want to permanently display the game over screen, you need to draw it depending on the spaceship_collided :
running = True
while running:
# [...]
if pygame.sprite.spritecollide(spaceship, enemies, dokill=True):
spaceship_collided = True
if spaceship_collided:
bg.blitme()
pygame.display.update()
clock.tick(60)
This question already has an answer here:
Trying to delay a specific function for spawning enemy after a certain amount of time
(1 answer)
Closed 1 year ago.
I am making a spaceship game where you control a spaceship and fire bullets to defeat enemies. I have already accomplished the goal where enemies spawn on top of the screen. The problem is, Hundreds of thousands of enemies spawn on top of the screen. I tried using the sleep function from the time module, but that didn't work. Instead, the game crashed right when I ran it! Can anybody help me?
This is my current code:
import pygame
from pygame.locals import *
from random import randint
from time import sleep
pygame.init()
screen = pygame.display.set_mode((800, 500))
screen.fill((255, 255, 255))
class Spaceship(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("C:/eqodqfe/spaceship.png")
self.image = pygame.transform.scale(self.image, (175, 175))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.rect.center = (self.x, self.y)
class Bullet(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen = s
self.x, self.y = x, y
self.image = pygame.image.load("C:/eqodqfe/bullet.png")
self.image = pygame.transform.scale(self.image, (100, 100))
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.y -= 5
self.rect.center = (self.x, self.y)
if self.y < 0:
self.kill()
class Enemy(pygame.sprite.Sprite):
def __init__(self, s, x, y):
pygame.sprite.Sprite.__init__(self)
self.screen, self.x, self.y = s, x, y
self.image = pygame.image.load("C:/eqodqfe/enemy.png")
self.image = pygame.transform.scale(self.image, (240, 210))
self.rect = self.image.get_rect()
self.rect = self.image.get_rect()
self.rect.center = (self.x, self.y)
def update(self):
self.rect.center = (self.x, self.y)
spaceship = Spaceship(screen, 400, 400)
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == MOUSEBUTTONDOWN:
bullet = Bullet(screen, spaceship.x, spaceship.y - 20)
bullets.add(bullet)
bullets.update()
key = pygame.key.get_pressed()
amount = 5
if key[pygame.K_a]:
spaceship.x -= amount
elif key[pygame.K_d]:
spaceship.x += amount
elif key[pygame.K_w]:
spaceship.y -= amount
elif key[pygame.K_s]:
spaceship.y += amount
spaceship.update()
screen.fill((255, 255, 255))
screen.blit(spaceship.image, spaceship.rect)
enemy = Enemy(screen, randint(-200, 800), 0)
enemies.add(enemy)
sleep(5)
bullets.draw(screen)
enemies.draw(screen)
pygame.display.update()
clock.tick(60)
Use a timer event to spawn enemies.
In pygame exists a timer event. Use pygame.time.set_timer() to repeatedly create a USEREVENT in the event queue. The time has to be set in milliseconds. e.g.:
enemy_interval = 1000 # 1000 milliseconds == 1 seconds
enemy_event = pygame.USEREVENT + 1
pygame.time.set_timer(enemy_event, enemy_interval)
Create a new enemy when the event occurs:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == MOUSEBUTTONDOWN:
bullet = Bullet(screen, spaceship.x, spaceship.y - 20)
bullets.add(bullet)
if event.type == enemy_event:
enemy = Enemy(screen, randint(-200, 800), 0)
enemies.add(enemy)
# [...]
# DELETE
# enemy = Enemy(screen, randint(-200, 800), 0)
# enemies.add(enemy)
# sleep(5)
# [...]
This question already has an answer here:
pygame.sprite.groupcollide() does not work when trying to implement collision in pygame [duplicate]
(1 answer)
Closed 2 years ago.
I made an enemy class and a player class for a pygame game and I'm trying to figure out how to detect collisions between them. I've tried a lot of different methods, and they don't work, because they need you to use a Rect object and I use a Surface object. Can you tell me what code to add to detect collisions between to Surface Objects? Here is my code:
import pygame
from pygame.locals import *
from sys import exit
import time
import random
pygame.init()
SCREEN_SIZE = (800, 600)
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((250, 250, 250))
screen.blit(background, (0, 0))
class Box(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self._1 = random.randint(10, 50)
self.image = pygame.Surface((self._1, self._1))
self.image.fill((random.randint(1, 255), random.randint(1, 255), random.randint(1, 255)))
self.rect = self.image.get_rect()
self.dx = random.randint(5, 15)
self.dy = random.randint(5, 15)
self.direction = self.dx, self.dy
def update(self):
pass
class Player(Box):
def __init__(self):
Box.__init__(self)
self.x = 400
self.y = 300
self.image = pygame.Surface((30, 30))
self.image.fill((0, 255, 0))
screen.fill((255, 255, 255))
self.rect.centerx = 400
self.rect.centery = 300
def update(self):
self.rect.centerx = self.x
self.rect.centery = self.y
class Enemy(Box):
def __init__(self):
Box.__init__(self)
self.image = pygame.Surface((30, 30))
self.image.fill((0, 255, 0))
self.image.fill((255, 0, 0))
def update(self):
self.dx, self.dy = self.direction
self.rect.centerx += self.dx
self.rect.centery += self.dy
if self.rect[0] >= 800 or self.rect[0] + self._1 <= 0:
self.direction = -self.dx, self.dy
if self.rect[1] >= 600 or self._1 + self.rect[1] <= 0:
self.direction = self.dx, -self.dy
allSprites = pygame.sprite.Group()
player = Player()
enemy1 = Enemy()
enemy2 = Enemy()
enemy3 = Enemy()
allSprites.add(enemy1)
allSprites.add(enemy2)
allSprites.add(enemy3)
allSprites.add(player)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_LEFT:
player.x -= 10
if event.key == K_RIGHT:
player.x += 10
if event.key == K_UP:
player.y -= 10
if event.key == K_DOWN:
player.y += 10
screen.fill((255, 255, 255))
allSprites.clear(screen, background)
allSprites.update()
allSprites.draw(screen)
pygame.display.flip()
time.sleep(50.0 / 1000.0)
Add the enemies to a pygame.sprite.Group (enemies) and detect if the Sprite player collides with an element from the Group enemies by pygame.sprite.spritecollide(). e.g.:
player = Player()
enemy1 = Enemy()
enemy2 = Enemy()
enemy3 = Enemy()
allSprites = pygame.sprite.Group()
allSprites.add([enemy1, enemy2, enemy3, player])
enemies = pygame.sprite.Group()
enemies.add([enemy1, enemy2, enemy3])
while True:
# [...]
allSprites.update()
if pygame.sprite.spritecollide(player, enemies, False):
print("collide")
# [...]
But note the .rect attributes of the objects Player and Enemy have just a size of 1x1. Ensure that the rectangles have the proper size:
class Player(Box):
def __init__(self):
Box.__init__(self)
self.x = 400
self.y = 300
self.image = pygame.Surface((30, 30))
self.image.fill((0, 255, 0))
screen.fill((255, 255, 255))
self.rect = self.image.get_rect(center=(400, 300)) # <---
class Enemy(Box):
def __init__(self):
Box.__init__(self)
self.image = pygame.Surface((30, 30))
self.rect = self.image.get_rect() # <---
self.image.fill((0, 255, 0))
self.image.fill((255, 0, 0))
Basically the rocket moves up and down, stops when it reaches the top or bottom and recognizes that the spacebar is being pressed. However the bullet won't shoot from the ship. I'm new to python and pygame. Anyways here is the code, thank you for any help!:
import pygame
import sys
from pygame.locals import*
bg_color = (0, 191, 255)
d_w = 1200
d_h= 800
class Rocket(object):
def __init__(self):
self.image = pygame.image.load('Rocket.bmp')
self.x = 0
self.y = d_h/2
def handle_keys(self):
key = pygame.key.get_pressed()
dist = 6.5
if key[pygame.K_UP]:
if self.y > 0:
self.y -= dist
elif key[pygame.K_DOWN]:
if self.y < 775:
self.y += dist
elif key[pygame.K_SPACE]:
Bullet.update(Bullet)
def draw(self, surface):
surface.blit(self.image, (self.x, self.y))
class Bullet(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface([2, 5])
self.image.fill(0, 0, 0)
self.rect = self.image.get_rect()
def update(self):
""" Move the bullet. """
self.image = pygame.Surface([2, 5])
self.image.fill((0, 0, 0))
self.rect = self.image.get_rect()
self.rect.x += 3
pygame.init()
screen = pygame.display.set_mode((d_w, d_h))
pygame.display.set_caption("Game Character")
Mario = pygame.image.load('Mario_Sprite.bmp')
rocket = Rocket()
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
rocket.handle_keys()
screen.fill(bg_color)
rocket.draw(screen)
pygame.display.update()
clock.tick(72)
Bullet.update(Bullet)
You're calling update statically. You need to create an instance of the class and then update that instance, as in:
bullet = Bullet()
...
bullet.update()