@Tobi234: Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Kommentare sollen dem Leser einen Mehrwert über den Code geben. Faustregel: Kommentare beschreiben nicht *was* der Code macht, denn das steht da bereits als Code, sondern warum er das macht. Sofern das nicht offensichtlich ist. Offensichtlich ist in aller Regel auch was in der Dokumentation von Python und den verwendeten Bibliotheken steht.
Kommentare die beschreiben was eine Funktion macht, wären besser Docstrings.
Alles was eine Funktion oder Methode ausser Konstanten benötigt, wird als Argument(e) übergeben. `draw_ball()` braucht also `screen` als Argument, denn der veränderliche Bildschirm(inhalt) ist keine Konstante.
`new_ball` wird definiert, aber nirgends verwendet.
Der Test ob der Ball angeklickt wurde, steht unnötigerweise zweimal im Code.
Das zusammenstückeln von Zeichenketten und Werten mittels ``+`` und `str()` ist eher BASIC als Python. Dafür gibt es die `format()`-Methode auf Zeichenketten und f-Zeichenkettenliterale.
Für jeden Frame das `Font`-Objekt immer wieder neu erstellen macht keinen Sinn.
Zwischenstand (ungetestet):
Code: Alles auswählen
#!/usr/bin/env python3
import random
import sys
import pygame
from pygame.locals import *
WIDTH, HEIGHT = 1920, 1080
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
BALL_RADIUS = 18
BALL_SPEED = 2
GAME_DURATION = 60_000 # in milliseconds.
def draw_ball(screen, x, y):
pygame.draw.circle(screen, WHITE, (x, y), BALL_RADIUS)
def create_new_ball():
return (
random.randint(BALL_RADIUS, WIDTH - BALL_RADIUS),
random.randint(BALL_RADIUS, HEIGHT - BALL_RADIUS),
)
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT), FULLSCREEN)
pygame.display.set_caption("Ball Explosion Game")
font = pygame.font.SysFont("Arial", 30)
punch_sound = pygame.mixer.Sound("/home/nala/Downloads/punch-2-123106.mp3")
hits = 0
start_time = pygame.time.get_ticks()
ball_x, ball_y = create_new_ball()
direction_x = random.choice([-1, 1])
direction_y = random.choice([-1, 1])
ball_clicked = False
running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif (
event.type == MOUSEBUTTONDOWN
and event.button == 1
and not ball_clicked
):
mouse_x, mouse_y = pygame.mouse.get_pos()
#
# Check if click is inside the ball
#
if (
(mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2
) <= BALL_RADIUS**2:
hits += 1
ball_clicked = True
punch_sound.play()
screen.fill(BLACK)
if not ball_clicked:
draw_ball(screen, ball_x, ball_y)
ball_x += BALL_SPEED * direction_x
ball_y += BALL_SPEED * direction_y
#
# Check if ball hits the wall and change direction
#
if ball_x <= BALL_RADIUS or ball_x >= WIDTH - BALL_RADIUS:
direction_x *= -1
if ball_y <= BALL_RADIUS or ball_y >= HEIGHT - BALL_RADIUS:
direction_y *= -1
current_time = pygame.time.get_ticks()
if current_time - start_time >= GAME_DURATION:
running = False
else:
ball_x, ball_y = create_new_ball()
ball_clicked = False
screen.blit(font.render(f"Hits: {hits}", True, RED), (50, 50))
screen.blit(
font.render(
f"Time: {(GAME_DURATION - (current_time - start_time)) // 1000}",
True,
RED,
),
(WIDTH - 200, 50),
)
pygame.display.update()
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
Es würde Sinn machen die Geschwindigkeit zu begrenzen in der die Hauptschleife läuft. Pygame hat da ein `Clock`-Objekt für.
Und ein sinnvoller nächster Schritt wäre es den Ball in einem Objekt zusammenzufassen, und mal zu schauen welche Werkzeuge Pygame für Kollisionstests bereits stellt.