0

I was trying to create a function that will load an image and move the image downwards while loading another image and still moving with the same speed as the first. But I don't know how to do it, all I can do for now is to load the next image when the y coordinate of the first is at 500

def aliens():
    s = 0
    i = "345678"
    c = 1
    b = int("".join(random.sample(i, c)))
    h = 1
    while h < 2:
        while s <= b:
            alien = pygame.image.load("ali.jpg")
            alien = pygame.transform.scale(alien, (100, 100))
            pos = "0123456789"
            l = 3
            x = int("".join(random.sample(pos, l)))
            y = 0
            if x > 500:
                h = 3
            crash = False
            s +=1
            while not crash :
                scn.blit(alien, (x, y))
                y +=2
                pygame.display.flip()
                if y > 500:
                  crash = True
            
Kingsley
  • 14,398
  • 5
  • 31
  • 53
Lord vic
  • 21
  • 2
  • 3
    This is generally implemented through classes. You define an aliens [class](https://docs.python.org/3/tutorial/classes.html) and then create as many instances as you need. PyGame has a [sprite](https://www.pygame.org/docs/ref/sprite.html) class that you should subclass as it will make things *much* easier in the long run. – import random Aug 28 '22 at 22:47
  • 1
    Or if you don't want to use classes, make a list item to hold the vital statistics of your `Alien`, then have a list of lists. Loop through each item in the list, moving/adjusting it every frame. But PyGame sprite objects are the *best* way to do this. – Kingsley Aug 29 '22 at 01:14

1 Answers1

1

The core of your problem is the fact that you are trying to do too many things in the same function. Try to follow the SRP (Single Responsability Principle).

Personnally I would use OOP (Object Oriented Programming) here but I don't know if you are familar with the concept, so first let's stick to the basics.


Here is how I would separate things up, if I wasn't allowed to use OOP:

First I would define two constants:

ALIEN_SIZE = 100
ALIEN_IMG = pg.image.load("green_square.png").convert()
ALIEN_IMG = pg.transform.scale(ALIEN_IMG, (ALIEN_SIZE, ALIEN_SIZE))

Since you are always using the same values, there is no need to load your image all the time. Loading your image just once will have a very positive impact on game's performances.

(Note that I used a diffrent image since you did not provide the image you use but feel free to put the link to your image back)


Then I would define an alien list:
aliens = []

I don't know how you plan to spawn aliens in your project ? For this example I used a custom event with a timer:

# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)

# This function handles all pygame events
def handle_evt():
    for evt in pg.event.get():
        if evt.type == pg.QUIT:
            exit()
        
        if evt.type == SPAWN_ALIEN:
            spawn_alien()

# This function spawns an alien
def spawn_alien():
    pos = [rd.randint(0, screen.get_width() - ALIEN_SIZE), 0]
    aliens.append(pos)

To make aliens move, I use a update() function:
# update aliens position and check if they leave the screen
def update():
    for alien in aliens:
        move_alien(alien)
        if out_of_screen(alien):
            kill_alien(alien)

# This function update alien's y position
def move_alien(alien):
    alien[1]+=1

# This function remove the given alien from the aliens list
def kill_alien(alien):
    aliens.remove(alien)

# This function returns True if the given position is outside screen's boundries
def out_of_screen(pos):
    x, y = pos
    if x < 0 or x > screen.get_width():
        return True
    elif y < 0 or y > screen.get_height():
        return True
    return False

Finally to render things :

def draw():
    # Clear screen
    screen.fill((0,0,0))

    # Draw aliens
    for alien in aliens:
        screen.blit(ALIEN_IMG, alien)

Here is the full code, so you can see how everything is interacting :

# General imports
import pygame as pg
import random as rd
import sys

# Init
pg.init()

# Vars & consts
screen = pg.display.set_mode((500, 500))
pg.display.set_caption("Example")
FPS = 60
clock = pg.time.Clock()

ALIEN_SIZE = 100
ALIEN_IMG = pg.image.load("green_square.png").convert()
ALIEN_IMG = pg.transform.scale(ALIEN_IMG, (ALIEN_SIZE, ALIEN_SIZE))

# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)

# Main functions
def update():
    for alien in aliens:
        move_alien(alien)
        if out_of_screen(alien):
            kill_alien(alien)

def draw():
    # Clear screen
    screen.fill((0,0,0))

    # Draw aliens
    for alien in aliens:
        screen.blit(ALIEN_IMG, alien)

def handle_evt():
    for evt in pg.event.get():
        if evt.type == pg.QUIT:
            exit()
        
        if evt.type == SPAWN_ALIEN:
            spawn_alien()

def exit():
    pg.quit()
    sys.exit()

# Other functions
def spawn_alien():
    pos = [rd.randint(0, screen.get_width() - ALIEN_SIZE), 0]
    aliens.append(pos)

def move_alien(alien):
    alien[1]+=1

def kill_alien(alien):
    aliens.remove(alien)

def out_of_screen(pos):
    x, y = pos
    if x < 0 or x > screen.get_width():
        return True
    elif y < 0 or y > screen.get_height():
        return True
    return False

# Main loop
if __name__ == '__main__':
    aliens = []
    spawn_alien()

    while True:
        handle_evt()
        update()
        draw()
        clock.tick(FPS)
        pg.display.flip()

And just in case, here is an OOP approach :

# General imports
import pygame as pg
import random as rd
import sys

# Init
pg.init()

# Vars
screen = pg.display.set_mode((500, 500))
pg.display.set_caption("Example")
FPS = 60
clock = pg.time.Clock()

# Class
class Alien():
    LIST = []
    SIZE = 100
    IMG = pg.image.load("green_square.png").convert()
    IMG = pg.transform.scale(IMG, (SIZE, SIZE))

    def __init__(self, screen_width):
        self.img = Alien.IMG
        self.pos = (rd.randint(0, screen_width - Alien.SIZE), 0)

        # Add alien to the list
        Alien.LIST.append(self)
    
    def move(self):
        x, y = self.pos
        self.pos = (x, y+1)
    
    def has_crashed(self, boundries):
        x, y = self.pos
        if x < 0 or x > boundries[0]:
            return True
        elif y < 0 or y > boundries[1]:
            return True
        return False
    
    def kill(self):
        Alien.LIST.remove(self)

# Custom event
SPAWN_ALIEN = pg.USEREVENT
pg.time.set_timer(SPAWN_ALIEN, 2000)

# Main functions
def update():
    for alien in Alien.LIST:
        alien.move()
        if alien.has_crashed(screen.get_size()):
            alien.kill()

def draw():
    # Clear screen
    screen.fill((0,0,0))

    # Draw aliens
    for alien in Alien.LIST:
        screen.blit(alien.img, alien.pos)

def handle_evt():
    for evt in pg.event.get():
        if evt.type == pg.QUIT:
            exit()
        
        if evt.type == SPAWN_ALIEN:
            spawn_alien()

def exit():
    pg.quit()
    sys.exit()

# Other functions
def spawn_alien():
    Alien(screen.get_width())

# Main loop
if __name__ == '__main__':
    while True:
        handle_evt()
        update()
        draw()
        clock.tick(FPS)
        pg.display.flip()

I hope all those informations can help you solve your problem. It's hard to know if this, really is the behavior you wanted for your aliens. That's because your variables names are not exactly explicit. One letter variable names are rarely a good idea. But anyway even if you need them to move a little diffrently, you can take inspiration of this code organization.

Have fun !

Anto
  • 267
  • 1
  • 11