0

This simulates a 2-D game which displays a man walking and shooting projectiles

import pygame

pygame.init()

win = pygame.display.set_mode((500, 480))
pygame.display.set_caption('Legend of Zorro')

walkRight = [pygame.image.load('Game/R1.png'), pygame.image.load('Game/R2.png'), pygame.image.load('Game/R3.png'),
             pygame.image.load(
                 'Game/R4.png'), pygame.image.load('Game/R5.png'), pygame.image.load('Game/R6.png'),
             pygame.image.load('Game/R7.png'), pygame.image.load(
        'Game/R8.png'), pygame.image.load('Game/R9.png')]
walkLeft = [pygame.image.load('Game/L1.png'), pygame.image.load('Game/L2.png'), pygame.image.load('Game/L3.png'),
            pygame.image.load(
                'Game/L4.png'), pygame.image.load('Game/L5.png'), pygame.image.load('Game/L6.png'),
            pygame.image.load('Game/L7.png'), pygame.image.load(
        'Game/L8.png'), pygame.image.load('Game/L9.png')]
bg = pygame.image.load('Game/bg.jpg')
char = pygame.image.load('Game/standing.png')

clock = pygame.time.Clock()
framerate = 45

This is the player class which simulates the main character's functions

class Player(object):
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 10
        self.isJump = False
        self.jumpCount = 10
        self.left = True
        self.right = False
        self.walkCount = 0
        self.standing = True

    def draw(self, win):
        if self.walkCount + 1 >= 27:
            self.walkCount = 0

        if not self.standing:

            if self.left:
                win.blit(walkLeft[self.walkCount // 3], (self.x, self.y))
                self.walkCount += 1
            elif self.right:
                win.blit(walkRight[self.walkCount // 3], (self.x, self.y))
                self.walkCount += 1
        else:
            if self.right:
                win.blit(walkRight[0], (self.x, self.y))
            else:
                win.blit(walkLeft[0], (self.x, self.y))

I believe the issue lies in this portion of the code

class projectile(object):
    def __init__(self, x, y, radius, colour, facing):
        self.x = x
        self.y = y
        self.radius = radius
        self.colour = colour
        self.facing = facing
        self.vel = 8 * facing

    def draw(self, win):
        pygame.draw.circle(win, self.colour, (self.x, self.y), self.radius)

Until this point

def redrawGameWindow():
    win.blit(bg, (0, 0))
    man.draw(win)
    for bullet in bullets:
        bullet.draw(win)

    pygame.display.update()


man = Player(300, 410, 64, 64)
bullets = []

This is the While Loop

run = True
while run:
    clock.tick(framerate)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

I also have a theory that by remove the bullets when they reach the end, the screen is not able to refresh before the bullet is removed from the array. But why does it happen only when the projectiles are shot to the right?

    for bullet in bullets:
        if 500 > bullet.x > 0:
            bullet.x += bullet.vel
        else:
            bullets.remove(bullet)
            break

The following is the keys to indicate the movements

    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE]:
        if man.left:
            facing = -1
        else:
            facing = 1

        if len(bullets) < 1:
            bullets.append(
                projectile(round(man.x + man.width // 2), round(man.y + man.height // 2), 6, (0, 0, 0), facing))

    if keys[pygame.K_LEFT] and man.x > man.vel:
        man.x -= man.vel
        man.left = True
        man.right = False
        man.standing = False
    elif keys[pygame.K_RIGHT] and man.x < 500 - man.width - man.vel:
        man.x += man.vel
        man.right = True
        man.left = False
        man.standing = False

    else:
        man.standing = True
        man.walkCount = 0

    if not man.isJump:
        if keys[pygame.K_UP]:
            man.isJump = True
            man.walkCount = 0
    else:
        if man.jumpCount >= -10:
            neg = 1
            if man.jumpCount < 0:
                neg = -1
            man.y -= (man.jumpCount ** 2) * 0.5 * neg
            man.jumpCount -= 1
        else:
            man.isJump = False
            man.jumpCount = 10

    redrawGameWindow()

pygame.quit()

EDIT #1

Removed break function - No improvement

The break function was actually something I had added at an earlier stage of the code and forgot to remove. Even after removal however, the flickering remains. I want to stress one point I did not mention in the original post. While the flickering seems to only happen on the left side of the window AND only happens when the bullet collides with the left side of the window, there are random instances where the flickering DOES NOT occur! So part of me wonders if this issue is attributable to something other than my code!!

  • Hello! Please read this so we can help you better https://stackoverflow.com/help/minimal-reproducible-example – Ake Mar 27 '23 at 19:37
  • Why are you breaking when one bullet is removed? That means the rest of the bullets aren't getting updated properly. If you do update them all and remove them, you should also reversely iterate over the bullets to make sure you aren't skipping elements while iterating. – B Remmelzwaal Mar 27 '23 at 19:40

1 Answers1

2

Do not break the loop when you remove a bullet, but run through all the bullets. If you omit some bullets in the loop that moves the bullets, it may cause a noticeable interruption in the motion of the bullets. Presumably, the break is intended to prevent an exception. Traverse a shallow copy of the list of bullets (bullets[:]) instead of breaking the loop. (Also see How to remove items from a list while iterating?).

for bullet in bullets[:]:
    if 500 > bullet.x > 0:
        bullet.x += bullet.vel
    else:
        bullets.remove(bullet)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Do you think that removing items from lists like this is less efficient Vs say, simply marking the `bullet` as "off screen" (idle) and then not updating it further. Then when a new bullet is needed, find an idle bullet and re-setting it? I guess you're still iterating through all the idle bullets every time. – Kingsley Mar 27 '23 at 22:48
  • Thank you for replying good sir. The break function was actually something I had added at an earlier stage of the code and forgot to remove. Even after removal however, the flickering remains. I want to stress one point I did not mention in the original post. While the flickering seems to only happen on the left side of the window AND only happens when the bullet collides with the left side of the window, there are random instances where the flickering DOES NOT occur! So part of me wonders if this issue is attributable to something other than my code!! – Crazy MANE41 Mar 28 '23 at 02:36