Seite 1 von 1

Problem/Code

Verfasst: Donnerstag 25. Juni 2020, 11:56
von Ali97
Hey, und zwar komme ich bei der aufgabe "Beschaffen Sie sich ein Bild für einen Stern und lassen Sie auf dem Bild-
schirm ein Raster von Sternen erscheinen. " ja ich weiß es hört sich nicht wirklich schwer an aber bin relative neu grad am coden
und zwar wen ich meinen code ausgebe gibt er mir ein Bild voller Sterne aber da bleibt überall platz zu der rechten Seiten und genau nach unten auch
Ich habe auch schon bei self.x dass plus weg gelassen damit es einfach am rand steht dabei ändert sich der ganze code

Code: Alles auswählen

import pygame
from pygame.sprite import Group
from settings import Settings
import game_functions as gf



def run_game():

    pygame.init()
    ai_settings = Settings()
    screen = pygame.display.set_mode((ai_settings.screen_width,
        ai_settings.screen_height))
    pygame.display.set_caption("Star")

    stars = Group()

    gf.create_grid(ai_settings, screen, stars)

    while True:
        gf.check_event()
        gf.update_screen(ai_settings, screen, stars)

run_game()
/code]

Dass Bild mit dem stern.

[code]import pygame
from pygame.sprite import Sprite

class Star(Sprite):
    """Create a star"""
    def __init__(self, ai_settings, screen):
        super(Star, self).__init__()
        self.screen = screen
        self.ai_settings = ai_settings

        self.image = pygame.image.load('images/star.bmp')
        self.rect = self.image.get_rect()

        
        self.rect.x = self.rect.width
        self.rect.y = self.rect.height

        self.x = float(self.rect.x)

            

    def blitme(self):
        """Show the star on the screen."""
        self.screen.blit(self.image, self.rect)
/code]

[code]import sys

Die game_fucntion

import pygame
from stars import Star

def check_event():
    """A function to respond end the game."""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

def update_screen(ai_settings, screen, stars):
    """A function to update the screen."""
    screen.fill(ai_settings.bg_color)
    stars.draw(screen)
    pygame.display.flip()


def get_number_stars(ai_settings, star_width):
    """Determine the number of the stars."""
    avaible_space_x = ai_settings.screen_width - 2 * star_width
    star_number_x = avaible_space_x // (2 * star_width)
    return star_number_x


def get_number_rows(ai_settings, star_height):
    """Determine the number of rows of aliens that fit on the screen."""
    avaible_space_y = ai_settings.screen_height + star_height
    number_rows_y = avaible_space_y // (2 * star_height)
    return number_rows_y

def create_star(ai_settings, screen, stars, star_number, row_number):
    """Create a star and set it to the place."""
    star = Star(ai_settings, screen)
    star_width = star.rect.width
    star.x = star_width + 2 * star_width * star_number
    star.rect.x = star.x
    star.rect.y = star.rect.height + 2 * star.rect.height * row_number
    stars.add(star)

def create_grid(ai_settings, screen, stars):
    """Create a rid of the stars."""
    star = Star(ai_settings, screen)
    star_number_x = get_number_stars(ai_settings, star.rect.width)
    number_rows_y = get_number_rows(ai_settings, star.rect.height)

    for star_number in range(star_number_x):
        for row_number in range(number_rows_y):
            create_star(ai_settings, screen, stars, star_number, row_number)
                        
/code]

Die settings 
[code]import pygame

class Settings():

    def __init__(self):
        """Initaliz the games settings."""
        self.screen_width = 1200
        self.screen_height = 800
        self.bg_color = (230, 230, 230)
        
/code]

Re: Problem/Code

Verfasst: Freitag 3. Juli 2020, 10:43
von __blackjack__
@Ali97: Also erst einmal ist das aufteilen auf vier Module nicht sinnvoll bei dem bisschen Code. Die `Star`-Klasse alleine in ein eigenes Modul zu stecken und ein Modul für Funktionen zu haben ist auch bei mehr Code keine wirklich gute Aufteilung. Ein Modul pro Klasse ist Java oder etwas in der Richtung, aber nicht Python.

Die `Settings`-Klasse ist auch eher „javaesque“. Wenn man ein Objekt mit Einstellungen in der Gegend herum reichen will, nimmt man in Python in der Regel ein Modul dafür, denn Module sind auch Objekte. Aber wie schon gesagt, macht das hier nicht wirklich Sinn das auf so viele Module zu verteilen und die Attribute von `Settings` wären halt einfach Konstanten.

Warum heisst das Exemplar von `Settings` überall `ai_settings`? Ich sehe da nichts mit künstlicher Intelligenz. Und selbst wenn, eine AI hätte beispielsweise keine Hintergrundfarbe als Einstellung.

Namen sollten keine kryptischen Abkürzungen enthalten. Wenn man `background_color` meint, sollte man nicht `bg_color` schreiben.

Ein `Star` verwendet das `ai_settings`-Attribut nirgends. Da die `blitme()`-Methode nicht verwendet wird, braucht ein `Star` auch keine Referenz auf `screen`. Das der Stern in seiner `__init__()` nicht am Ursprung bleibt, sondern um seine Höhe/Breite nach unten/rechts verschoben wird, macht auch nicht wirklich Sinn.

Und auch das `x`-Attribut macht keinen Sinn. Die `x`-Position steckt ja bereits im `rect`-Attribut. Das Attribut wird ja auch nicht wirklich verwendet. Dort wo es einen Wert zugewiesen bekommt, wird der gleiche Wert sofort danach an das `x`-Attribut vom `rect` zugewiesen. Diesen Zwischenschritt kann man sich auch einfach sparen. Mit `y` wird das ja auch direkt gemacht, warum bei `x` dann so indirekt/umständlich?

`super()` braucht man keine Argumente übergeben. Ich würde da aber auch komplett die Finger von lassen, denn das funktioniert sowieso nicht so wie es soll, denn dazu müssten alle Klassen in der Vererbungshierarchie `super()` verwenden — `pygame.sprite.Sprite` selbst, tut das aber nicht.

Bei den Namen `get_number_stars()` und `get_number_rows()` fehlt ein `_of_`, damit die Sinn ergeben. Bei `get_number_rows()` ist verwirrenderweise von Aliens die Rede‽ Die Funktionen machen auch nahezu das gleiche, nur mit anderen Werte und ich verstehe nicht so recht warum horizontal letztlich eine Sternenbreite frei bleiben soll, aber vertikal eine Sternenhöhe mehr Platz angenommen wird als tatsächlich auf dem Bildschirm zur Verfügung steht? Diese Information, und das die Anzahlen jeweils so berechnet werden, dass immer eine Sternenbreite/-höhe zwischen den Sternen freibleiben soll, würde in die Dokumentation der Funktionen gehören.

`check_event()` ist als Name falsch. Da wird weder (nur) etwas geprüft, noch ist das nur *ein* Ereignis was da verarbeitet wird. `process_events()` würde besser zu dem passen was die Funktion macht.

Das `sys.exit()` gehört da nicht rein. Die Funktion sollte man sowieso nur aufrufen wenn man dem Aufrufer mindestens potentiell einen anderen Rückgabecode als 0 liefern möchte. Und auch dann sollte das nicht in einer Funktion passieren von der man nicht erwartet, dass die einfach so den gesamten Prozess beendet.

Man muss nicht jede Funktion dokumentieren, insbesondere wenn der Name der Funktion genau das sagt was dann noch mal im Docstring steht. Wenn man nicht *mehr* zu sagen hat, kann man sich diese Wiederholung auch sparen, denn das bringt dem Leser nichts.

Dann landen wir ungefähr hier und ich verstehe Dein Problem nicht wirklich:

Code: Alles auswählen

#!/usr/bin/env python3
import pygame
from pygame.sprite import Group, Sprite

SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 800
BACKGROUND_COLOR = (230, 230, 230)
STAR_IMAGE_FILENAME = "images/star.bmp"


class Star(Sprite):
    def __init__(self, *groups):
        Sprite.__init__(self, *groups)
        #
        # TODO Seems to be a bit wasteful to load that image for each identical
        #   looking star.
        #
        self.image = pygame.image.load(STAR_IMAGE_FILENAME)
        self.rect = self.image.get_rect()


def process_events():
    """
    Process PyGame events.
    
    Returns `False` if the program should stop, `True` otherwise.
    """
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            return False
    return True


def update_screen(screen, stars):
    screen.fill(BACKGROUND_COLOR)
    stars.draw(screen)
    pygame.display.flip()


def get_stars_per_row(star_width):
    """
    Calculates the number of stars per row with one star width space between
    each star.
    """
    return (SCREEN_WIDTH - star_width) // (2 * star_width)


def get_number_of_rows(star_height):
    """
    Calculates the number of rows of stars with one star height space between
    the rows.
    """
    return (SCREEN_HEIGHT - star_height) // (2 * star_height)


def create_star(stars, star_number, row_number):
    """
    Creates a star, adds it to the `stars` group, and positions it on the grid.
    """
    star_rect = Star(stars).rect
    star_rect.x = star_rect.width + 2 * star_rect.width * star_number
    star_rect.y = star_rect.height + 2 * star_rect.height * row_number


def create_grid(stars):
    """
    Creates a grid of stars and adds them to the given `stars` group.
    """
    star_rect = Star().rect
    for star_number in range(get_stars_per_row(star_rect.width)):
        for row_number in range(get_number_of_rows(star_rect.height)):
            create_star(stars, star_number, row_number)


def main():
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    pygame.display.set_caption("Star")

    stars = Group()
    create_grid(stars)
    #
    # FIXME Burns a lot CPU time for static content.  Introduce a `pygame.Clock`
    #   to keep this loop sane.
    #
    while process_events():
        update_screen(screen, stars)

    pygame.quit()


if __name__ == "__main__":
    main()
Ich habe zwei Kommentare eingefügt. Einmal weil alle Sterne gleich aussehen, das Bild aber für jeden Stern neu geladen wird. Und dann verbrät das unnötig Rechenzeit weil die Hauptschleife ungebremst das immer gleiche statische Bild zeichnet so schnell wie der Rechner das eben kann. Das sollte man auf ein vernünftiges Mass drosseln.