I have a sprite which shoots bullets. Sometimes bullets also shoot out of invisible shooters.
The switch from opponent to shooter mid-program works but when I want the bullets to shoot in a certain way, with delays between each shot, the bullets seem to become a single line (the purple thing in the image is the bullets):
The mechanic works when it's the opponent shooting, but not when it's the invisible square.
Why is this happening? Is there a small bug I need to fix?
Here's my code:
import pygame
import time
import itertools
import os
pygame.init()
SCREENWIDTH = 1000
SCREENHEIGHT = 650
screen = pygame.display.set_mode([SCREENWIDTH, SCREENHEIGHT])
screen.fill((255, 123, 67))
pygame.draw.rect(screen, (230, 179, 204), (0, 50, 1000, 650), 0)
background = screen.copy()
clock = pygame.time.Clock()
stageon = True
class Spell:
def __init__(self, bullet, pattern, speed, loop, tick_delay):
self.bullet = bullet
self.pattern = pattern
self.speed = speed
self.loop = loop
self.tick_delay = tick_delay
class Shooter(pygame.sprite.Sprite):
def __init__(self, spell, pos, *groups):
super().__init__(*groups)
self.image = pygame.image.load("Sprites/transparent.jpg")
self.rect = self.image.get_rect(topleft=(pos))
self.pos = pygame.Vector2(pos)
self.start_time = pygame.time.get_ticks()
self.currentspell = spell
self.speed = 3
self.ticks = 1000
def update(self):
time_gone = pygame.time.get_ticks() - self.start_time
if self.currentspell is not None and time_gone > self.currentspell.tick_delay:
self.start_time = pygame.time.get_ticks()
for bullet in self.currentspell.pattern:
if bullet[0] <= time_gone:
Bullet(self.rect.center, bullet[1], self.currentspell.bullet, sprites, bullets)
self.currentspell.loop -= 1
if self.currentspell.loop <= 0:
self.currentspell = None
self.kill()
class Opponent(pygame.sprite.Sprite):
def __init__(self, sprite, sequence, *groups):
super().__init__(*groups)
self.image = sprite
self.rect = self.image.get_rect(topleft=(425, 30))
self.pos = pygame.Vector2(self.rect.topleft)
self.start_time = pygame.time.get_ticks()
self.sequence = sequence
self.spellno = 0
self.currentspell = sequence[self.spellno]
self.speed = 3
self.ticks = 1000
self.shooters = 0
def update(self):
time_gone = pygame.time.get_ticks() - self.start_time
if type(self.currentspell) != Spell:
Shooter(self.currentspell[0], self.currentspell[1], sprites)
self.shooters += 1
if self.shooters != 0:
return
else:
if self.currentspell is not None and time_gone > self.currentspell.tick_delay:
self.start_time = pygame.time.get_ticks()
for bullet in self.currentspell.pattern:
if bullet[0] <= time_gone:
Bullet(self.rect.center, bullet[1], self.currentspell.bullet, sprites, bullets)
self.currentspell.loop -= 1
if self.currentspell.loop <= 0:
self.spellno += 1
if self.spellno >= len(self.sequence):
self.currentspell = None
else:
self.currentspell = self.sequence[self.spellno]
sprites = pygame.sprite.Group()
class Bullet(pygame.sprite.Sprite):
def __init__(self, pos, direction, image, *groups):
super().__init__(*groups)
self.image = image
self.rect = self.image.get_rect(topleft=pos)
self.direction = direction
self.pos = pygame.Vector2(self.rect.topleft)
def update(self):
self.pos += self.direction
self.rect.topleft = (self.pos.x, self.pos.y)
if not screen.get_rect().colliderect(self.rect):
self.kill()
bullets = pygame.sprite.Group()
opponentgroup = pygame.sprite.Group()
img4 = pygame.image.load("Sprites/utd.png")
ut1 = Spell(pygame.image.load("Sprites/purple-glowey.png"),((0, pygame.Vector2(-1, 1) * 4),
(0, pygame.Vector2(-0.5, 1) * 4.5),
(0, pygame.Vector2(0, 1) * 5),
(0, pygame.Vector2(0.5, 1) * 4.5),
(0, pygame.Vector2(1, 1) * 4),),4, 1, 400)
ut2 = Spell(pygame.image.load("Sprites/purple-glowey.png"),((0, pygame.Vector2(1, 0) * 5),),4, 8, 400)
op_spells = [ut1, (ut2, (10, 395))]
OP = Opponent(img4, op_spells, opponentgroup)
sprites.add(OP)
def main():
while stageon:
for events in pygame.event.get():
if events.type == pygame.QUIT or stageon == False:
time.sleep(1)
pygame.quit()
return
sprites.update()
screen.blit(background, (0, 0))
sprites.draw(screen)
pygame.display.update()
clock.tick(100)
if stageon == False:
return
if __name__ == '__main__':
main()
You problem is this the update
function of the Opponent
class:
def update(self):
time_gone = pygame.time.get_ticks() - self.start_time
if type(self.currentspell) != Spell:
Shooter(self.currentspell[0], self.currentspell[1], sprites)
self.shooters += 1
...
You use the list op_spells = [ut1, (ut2, (10, 395))]
, and as you can see, the second element is not an instance of Spell
. So the if
condition if type(self.currentspell) != Spell
will be True
and a new Shooter
instance will be created.
But the creation of the Shooter
instace happens every frame, so you create an infinite number of Shooter
instances, which in turn create an infinite number of Bullet
instances.
You could change your update
function to this:
def update(self):
time_gone = pygame.time.get_ticks() - self.start_time
if self.currentspell is not None:
spell = self.currentspell if type(self.currentspell) == Spell else self.currentspell[0]
shooterpos = None if type(self.currentspell) == Spell else self.currentspell[1]
if time_gone > spell.tick_delay:
if shooterpos:
# we have a position, so create a shooter
Shooter(spell, shooterpos, sprites)
else:
# we don't have a position, so create the Bullets ourself
self.start_time = pygame.time.get_ticks()
for bullet in spell.pattern:
if bullet[0] <= time_gone:
Bullet(self.rect.center, bullet[1], spell.bullet, sprites, bullets)
spell.loop -= 1
# if we have a position or the spell loop is done, go to the next spell
if shooterpos or spell.loop <= 0:
self.spellno += 1
if self.spellno >= len(self.sequence):
self.currentspell = None
else:
self.currentspell = self.sequence[self.spellno]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With