Python Forum
how to get qualified objects in a list
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
how to get qualified objects in a list
#1
I'm trying to make a spaceship game and when it gets off screen I want to delete it

but I don't know how to get the objects that are off screen and the ones on-screen

I tried this but it doesn't work

stars = [for star in stars if star.rect.x > 800]
Reply
#2
nvm I fixed it but its still buggy

import pygame
import random

window = pygame.display.set_mode((800, 600))
mouse = pygame.mouse
clock = pygame.time.Clock()
keys = pygame.key.get_pressed()

class Player:
  def __init__(self):
    self = pygame.Surface((25, 25))
    self.rect = self.get_rect(center=(700, 300))
  def frame(self):
    if keys[pygame.K_SPACE] or mouse.get_pressed():
      self.rect -= 3
    else:
      self.rect += 3
    for rock in rocks:
      if rock.rect.colliderect(self.rect):
        pygame.quit()
        exit()
      
class Star:
  def __init__(self):
    self = pygame.Surface((10, 10))
    self.rect = self.get_rect(center=(0, random.randint(0, 590)))
  def frame(self):
    self.rect.x += 1
    if self.rect.x > 800:
      del self
      
class Rock:
  def __init__(self):
    self = pygame.Surface((20, 20))
    self.rect = self.get_rect(center=(0, random.randint(0, 590)))
  def frame(self):
    self.rect.x += 2
    if self.rect.x > 800:
      del self
   
player = Player()
    
stars = []
rocks = []
    
while True:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      pygame.quit()
      exit()
      
  for star in stars:
    if star.rect.x > 800:
      del star
  for rock in rocks:
    if rock.rect.x > 800:
      del rock
      
  if random.randint(1, 25):
    stars.append(Star())
  if random.randint(1, 100):
    rocks.append(Rock())
  for star in stars:
    star.frame()
    window.blit(star, star.rect)
  for rock in rocks:
    rock.frame()
    window.blit(rock, rock.rect)
  player.frame()
  window.blit(player, player.rect)
  
  pygame.display.flip()
  clock.tick(120)
Reply
#3
Some advices and fixes.
Don’t overwrite self. want to keep your object instance.

Update input state each frame.
Call pygame.key.get_pressed() and pygame.mouse.get_pressed() inside your main loop, not just once at startup.
To make the player “float” up/down, adjust self.rect.y, not the whole Rect.
import pygame
import random
import sys

pygame.init()
WIDTH, HEIGHT = 800, 600
window = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()

class Player:
    def __init__(self):
        # create an image and rect for this sprite
        self.image = pygame.Surface((25, 25))
        self.image.fill((255, 255, 255))
        self.rect = self.image.get_rect(center=(700, HEIGHT // 2))

    def update(self, keys, mouse_buttons):
        if keys[pygame.K_SPACE] or any(mouse_buttons):
            self.rect.y -= 3
        else:
            self.rect.y += 3
        # keep inside the window
        self.rect.y = max(0, min(self.rect.y, HEIGHT - self.rect.height))

    def draw(self, surface):
        surface.blit(self.image, self.rect)

class Star:
    def __init__(self):
        self.image = pygame.Surface((10, 10))
        self.image.fill((200, 200, 200))
        self.rect = self.image.get_rect(
            center=(0, random.randint(0, HEIGHT))
        )

    def update(self):
        self.rect.x += 1

    def draw(self, surface):
        surface.blit(self.image, self.rect)


class Rock:
    def __init__(self):
        self.image = pygame.Surface((20, 20))
        self.image.fill((100, 100, 100))
        self.rect = self.image.get_rect(
            center=(0, random.randint(0, HEIGHT))
        )

    def update(self):
        self.rect.x += 2

    def draw(self, surface):
        surface.blit(self.image, self.rect)

player = Player()
stars = []
rocks = []
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # Fix your random odds
    # if random.randint(1,25): is always true (randint never returns 0)
    # gives you a ~4% chance per frame, rather than 100%.
    keys = pygame.key.get_pressed()
    mouse_buttons = pygame.mouse.get_pressed()
    if random.randint(1, 25) == 1:
        stars.append(Star())
    if random.randint(1, 100) == 1:
        rocks.append(Rock())
    # Update
    player.update(keys, mouse_buttons)
    for s in stars:
        s.update()
    for r in rocks:
        r.update()
    # remove off‑screen stars/rocks
    stars = [s for s in stars if s.rect.x <= WIDTH]
    rocks = [r for r in rocks if r.rect.x <= WIDTH]
    # check collisions
    for rock in rocks:
        if rock.rect.colliderect(player.rect):
            pygame.quit()
            sys.exit()

    window.fill((0, 0, 0))
    for s in stars:
        s.draw(window)
    for r in rocks:
        r.draw(window)
    player.draw(window)
    pygame.display.flip()
    clock.tick(120)
Reply
#4
This is bad:
class Star:
  def __init__(self):
    self = pygame.Surface((10, 10))
    self.rect = self.get_rect(center=(0, random.randint(0, 590)))
self = pygame.Surface sets self to a Surface. When you do self.rect = self.get_rect() you are adding rect to the Surface, not the Star. This causes the code to crash when I run it. Surface must have slots instead of an attribute dictionary. You cannot add attributes to instances of a class that has slots.

If it did run, rect would be an attribute of the Surface, not Star. If you wanted to get the rect, you would have to ask the Surface. Unfortunately you don't have any way to reference the surface.

To fix those problems you could do this:
class Star(pygame.surface.Surface):
  def __init__(self):
    super().__init__((10, 10))
    self.rect = self.get_rect(center=(0, random.randint(0, 590)))
This makes a new kind of Surface that has a rect attribute. The subclass has an attribute dictionary, so it you can add a rect attribute to instances of Star.
This also fixes the problem of not having a reference to the Surface. Star is a subclass of Surface, so all Stars are also Surfaces.

Another way to write this is to make Star and aggregate class instead of a subclass. In this code Star HAS A surface instead of Star IS A surface. Written this way, Star remindes me of a Sprite.
class Star():
  def __init__(self):
    self.surface = pygame.surface.Surface((10, 10))
    self.rect = self.surface.get_rect()
    self.rect.center = (0, random.randint(0, 590)))
A sprite is a surface you can move around, just like Star. Unlike Star, pygame knows all about sprites and provides a lot of support that makes working with sprites easy. This is Star and Rock as sprites. In Sprite, the surface attribute is named "image". Usually the image is loaded from an image file, so a rock can look like a rock instead of a rectangle. Sprites should have an update() method that is called to move the sprite around. If you want to delete a sprite you kill() it.
class Star(pygame.sprite.Sprite):
    def __init__(self):
        self.image = pygame.Surface((10, 10))  # Replace with code that loads a star image
        self.rect = self.image.get_rect()
        self.rect.center = (0, random.randint(0, 590))

    def update(self):
        self.rect.x += 1
        if self.rect.x > 800:
          self.kill()
      

class Rock(pygame.sprite.Sprite):
    def __init__(self):
        self.image = pygame.Surface((10, 10))  # Replace with code that loads a rock image
        self.rect = self.image.get_rect()
        self.rect.center = (0, random.randint(0, 590))

    def update(self):
        self.rect.x += 2
        if self.rect.x > 800:
          self.kill()
The Rock and Star code is very similar, so you might want to make a superclass that does most of the work. In this code the Obstacle class does all the work. The Star and Rock classes just tell Obsacle how a Star or Rock looks and how fast it moves.
class Obstacles(pygame.sprite.Sprite):
    def __init__(self, window, size, speed, color):
        super().__init__()
        self.window = window
        self.image = pygame.Surface(size)
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.center = (0, random.randint(0, 590))
        self.speed = speed

    def update(self):
        self.rect.x += self.speed
        wide, high = self.window.get_size()
        if self.rect.x > wide:
            self.kill()


class Star(Obstacles):
    """A small, slow, yellow obstacle."""
    def __init__(self, window):
        super().__init__(window, (10, 10), 1, "yellow")


class Rock(Obstacles):
    """A big, fast, grey obstacle."""
    def __init__(self, window):
        super().__init__(window, (20, 20), 2, "grey")
This code doesn't do what you think:
  if random.randint(1, 25):
    stars.append(Star())
Maybe you want there to be a 1 in 25 chance of creating a Star? That code would look like this:
  if random.randint(1, 25) == 1:
    stars.append(Star())
Remember that I said pygame knows about sprites and makes it easier to program when you use sprites? Your collision and screen update code works, but it is easier if you let pygame do the work. In this code I put stars and rocks in a group and I let pygame do the updates and detect collisions.
def mainloop():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        # Move player and obstacles.
        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE] or any(mouse.get_pressed()):
            player.update(-3)
        else:
            player.update(3)
        obstacles.update()

        # Randomly add obstacles.
        if random.randint(1, 25) == 1:
            obstacles.add(Star(window))
        if random.randint(1, 100) == 1:
        obstacles.add(Rock(window))

        # check for collisions
        if pygame.sprite.spritecollide(player, obstacles, True):
            return

        # Update the display
        window.fill(0)
        player.draw(window)
        obstacles.draw(window)
        pygame.display.flip()
        clock.tick(40)
All the code. I modified the game play so the goal is to catch rocks and avoid stars. When the player catches the rock they consume it and grow 5% in size.
import pygame
import random


class Player(pygame.sprite.Sprite):
    def __init__(self, window):
        super().__init__()
        self.window = window
        self.image = pygame.Surface((25, 25))
        self.image.fill("Blue")
        self.rect = self.image.get_rect()
        self.rect.center = (700, 300)
 
    def grow(self):
        pos = self.rect.center
        self.image = pygame.transform.scale_by(self.image, 1.05)
        self.rect = self.image.get_rect()
        self.rect.center = pos

    def update(self, move):
        y = self.rect.y + move
        wide, high = self.window.get_size()
        if 0 <= y <= high - self.rect.height:
            self.rect.y = y
 
    def draw(self, window):
        window.blit(self.image, self.rect)
 
 
class Obstacles(pygame.sprite.Sprite):
    def __init__(self, window, size, speed, color):
        super().__init__()
        self.window = window
        self.image = pygame.Surface(size)
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.center = (0, random.randint(0, 590))
        self.speed = speed
 
    def update(self):
        self.rect.x += self.speed
        wide, high = self.window.get_size()
        if self.rect.x > wide:
            self.kill()
 
 
class Star(Obstacles):
    def __init__(self, window):
        super().__init__(window, (10, 10), 1, "yellow")
 
 
class Rock(Obstacles):
    def __init__(self, window):
        super().__init__(window, (20, 20), 2, "grey")
 

def play(window):
    mouse = pygame.mouse
    clock = pygame.time.Clock()
    player = Player(window)
    obstacles = pygame.sprite.Group()

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return
    
        # Move player and obstacles.
        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE] or any(mouse.get_pressed()):
            player.update(-3)
        else:
            player.update(3)
        obstacles.update()
 
        # Randomly add obsacles.
        if random.randint(1, 25) == 1:
            obstacles.add(Star(window))
        if random.randint(1, 100) == 1:
            obstacles.add(Rock(window))
    
        # check for collisions
        for object in pygame.sprite.spritecollide(player, obstacles, False):
            if isinstance(object, Rock):
                object.kill()
                player.grow()
            else:
                return
    
        # Update the display
        window.fill(0)
        player.draw(window)
        obstacles.draw(window)
        pygame.display.flip()
 
        clock.tick(40)

pygame.init()
window = pygame.display.set_mode((800, 600))
play(window)
pygame.quit()
Reply
#5
From your first post. Instead of this:
stars = [for star in stars if star.rect.x > 800]
do this
stars = [star for star in stars if star.rect.x > 800]
Which is just a short way of writing:
temp = []
for star in stars:
    if star.rect.x <= 800:
        temp.append(star)
stars = temp
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Creating list of lists, with objects from lists sgrinderud 7 3,082 Oct-01-2022, 07:15 PM
Last Post: Skaperen
Question Keyword to build list from list of objects? pfdjhfuys 3 2,617 Aug-06-2022, 11:39 PM
Last Post: Pedroski55
  How to store the resulting Doc objects into a list named A xinyulon 1 2,653 Mar-08-2022, 11:49 PM
Last Post: bowlofred
  Grouping and sum of a list of objects Otbredbaron 1 5,316 Oct-23-2021, 01:42 PM
Last Post: Gribouillis
  Passing List of Objects in Command Line Python usman 7 4,516 Sep-27-2020, 03:45 PM
Last Post: ndc85430
  How to create and define in one line a 2D list of class objects in Python T2ioTD 1 3,047 Aug-14-2020, 12:37 PM
Last Post: Yoriz
  Organizing list of objects by attribute scarney1988 3 3,229 Mar-11-2020, 03:55 PM
Last Post: scarney1988
  List of objects with sublist medatib531 4 3,290 Mar-01-2020, 06:16 PM
Last Post: buran
  Deleting from a list of objects buddih09 2 3,209 Nov-07-2018, 04:08 PM
Last Post: ichabod801
  finding similar objects in a list DRPR 4 133,464 Jun-22-2018, 10:05 AM
Last Post: volcano63

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020