Hi, ich befasse mich gerade mit pygame und habe auch schon einfache Dinge realisiert. Hier komme ich aber nicht weiter. Ich möchte ein ganz einfaches Spiel erstellen im Vollbildmodus. Es soll sich ein kleiner weißer Ball zufällig über den schwarzen Bildschirm bewegen. Wenn der Ball über den touchscreen berührt wird soll er verschwinden und ein neuer Ball soll an zufälliger Stelle entstehen mit der gleichen Funktion. Wer nach 1 Minute die meisten Treffer hat wird im Highscore festgehalten. Je länger der ball nicht getroffen wird je schneller soll er werden.
Meine Versuche sind bisher alle fehlgeschlagen. Entweder der Ball zittert nur oder er bewegt sich nur in einem Radius von wenigen cm. Der Touchscreen wird auch nicht erkannt, es funktioniert nur mit der Maus. Den touchscreen habe ich aber schon mit einem anderen Spiel zum laufen bekommen.
Wer kann mir helfen auf die Sprünge zu kommen? Wo kann ich mich einlesen um das Problem zu lösen oder wer hat hilfreiche Hinweise für mich?
Tausend Dank
Bewegender kreis
Ich habe es tatsächlich zum laufen bekommen und der touchscreen funktioniert auch. Nur bewegt sich der Kreis immer gerade durch den Monitor und nicht zufällig wie eine Schlange oder Biene. Der Ball sollte die Geschwindigkeit langsam steigern wenn er nicht getroffen wird. Wie könnte ich das lösen?
import pygame
import sys
import random
from pygame.locals import *
# Initialize Pygame
pygame.init()
# Set up the screen
WIDTH, HEIGHT = 1920, 1080
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT), FULLSCREEN)
pygame.display.set_caption("Ball Explosion Game")
# Load the sound
punch_sound = pygame.mixer.Sound("/home/nala/Downloads/punch-2-123106.mp3")
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# Ball properties
BALL_RADIUS = 18
BALL_SPEED = 2
# Game variables
hits = 0
start_time = pygame.time.get_ticks()
game_duration = 60000 # 60 seconds
# Function to draw a ball
def draw_ball(x, y):
pygame.draw.circle(SCREEN, WHITE, (x, y), BALL_RADIUS)
# Function to create a new ball at a random position
def create_new_ball():
return random.randint(BALL_RADIUS, WIDTH - BALL_RADIUS), random.randint(BALL_RADIUS, HEIGHT - BALL_RADIUS)
# Main game loop
running = True
ball_x, ball_y = create_new_ball()
direction_x = random.choice([-1, 1])
direction_y = random.choice([-1, 1])
ball_clicked = False
new_ball = False
while running:
# Check for events
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1 and not ball_clicked: # Left mouse button clicked and no ball clicked
mouse_x, mouse_y = pygame.mouse.get_pos()
if ((mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2) <= BALL_RADIUS ** 2: # Check if click is inside the ball
hits += 1
ball_clicked = True
# Play the punch sound
punch_sound.play()
# Clear the screen
SCREEN.fill(BLACK)
if not ball_clicked:
# Draw the ball
draw_ball(ball_x, ball_y)
# Update ball position
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
# Check if the ball is clicked
mouse_click = pygame.mouse.get_pressed()
if mouse_click[0]: # Left mouse button clicked
if ((mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2) <= BALL_RADIUS ** 2: # Check if click is inside the ball
hits += 1
ball_clicked = True
# Play the punch sound
punch_sound.play()
# Check game duration
current_time = pygame.time.get_ticks()
if current_time - start_time >= game_duration:
running = False
else:
# Create a new ball
ball_x, ball_y = create_new_ball()
ball_clicked = False
# Display hits and time
pygame.font.init()
font = pygame.font.SysFont('Arial', 30)
hits_text = font.render("Hits: " + str(hits), True, RED)
time_text = font.render("Time: " + str((game_duration - (current_time - start_time)) // 1000), True, RED)
SCREEN.blit(hits_text, (50, 50))
SCREEN.blit(time_text, (WIDTH - 200, 50))
# Update the display
pygame.display.update()
# Quit Pygame
pygame.quit()
sys.exit()
import pygame
import sys
import random
from pygame.locals import *
# Initialize Pygame
pygame.init()
# Set up the screen
WIDTH, HEIGHT = 1920, 1080
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT), FULLSCREEN)
pygame.display.set_caption("Ball Explosion Game")
# Load the sound
punch_sound = pygame.mixer.Sound("/home/nala/Downloads/punch-2-123106.mp3")
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# Ball properties
BALL_RADIUS = 18
BALL_SPEED = 2
# Game variables
hits = 0
start_time = pygame.time.get_ticks()
game_duration = 60000 # 60 seconds
# Function to draw a ball
def draw_ball(x, y):
pygame.draw.circle(SCREEN, WHITE, (x, y), BALL_RADIUS)
# Function to create a new ball at a random position
def create_new_ball():
return random.randint(BALL_RADIUS, WIDTH - BALL_RADIUS), random.randint(BALL_RADIUS, HEIGHT - BALL_RADIUS)
# Main game loop
running = True
ball_x, ball_y = create_new_ball()
direction_x = random.choice([-1, 1])
direction_y = random.choice([-1, 1])
ball_clicked = False
new_ball = False
while running:
# Check for events
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1 and not ball_clicked: # Left mouse button clicked and no ball clicked
mouse_x, mouse_y = pygame.mouse.get_pos()
if ((mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2) <= BALL_RADIUS ** 2: # Check if click is inside the ball
hits += 1
ball_clicked = True
# Play the punch sound
punch_sound.play()
# Clear the screen
SCREEN.fill(BLACK)
if not ball_clicked:
# Draw the ball
draw_ball(ball_x, ball_y)
# Update ball position
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
# Check if the ball is clicked
mouse_click = pygame.mouse.get_pressed()
if mouse_click[0]: # Left mouse button clicked
if ((mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2) <= BALL_RADIUS ** 2: # Check if click is inside the ball
hits += 1
ball_clicked = True
# Play the punch sound
punch_sound.play()
# Check game duration
current_time = pygame.time.get_ticks()
if current_time - start_time >= game_duration:
running = False
else:
# Create a new ball
ball_x, ball_y = create_new_ball()
ball_clicked = False
# Display hits and time
pygame.font.init()
font = pygame.font.SysFont('Arial', 30)
hits_text = font.render("Hits: " + str(hits), True, RED)
time_text = font.render("Time: " + str((game_duration - (current_time - start_time)) // 1000), True, RED)
SCREEN.blit(hits_text, (50, 50))
SCREEN.blit(time_text, (WIDTH - 200, 50))
# Update the display
pygame.display.update()
# Quit Pygame
pygame.quit()
sys.exit()
Und hier derselbe Code mit Code-Tags:
Code: Alles auswählen
import pygame
import sys
import random
from pygame.locals import *
# Initialize Pygame
pygame.init()
# Set up the screen
WIDTH, HEIGHT = 1920, 1080
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT), FULLSCREEN)
pygame.display.set_caption("Ball Explosion Game")
# Load the sound
punch_sound = pygame.mixer.Sound("/home/nala/Downloads/punch-2-123106.mp3")
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
# Ball properties
BALL_RADIUS = 18
BALL_SPEED = 2
# Game variables
hits = 0
start_time = pygame.time.get_ticks()
game_duration = 60000 # 60 seconds
# Function to draw a ball
def draw_ball(x, y):
pygame.draw.circle(SCREEN, WHITE, (x, y), BALL_RADIUS)
# Function to create a new ball at a random position
def create_new_ball():
return random.randint(BALL_RADIUS, WIDTH - BALL_RADIUS), random.randint(BALL_RADIUS, HEIGHT - BALL_RADIUS)
# Main game loop
running = True
ball_x, ball_y = create_new_ball()
direction_x = random.choice([-1, 1])
direction_y = random.choice([-1, 1])
ball_clicked = False
new_ball = False
while running:
# Check for events
for event in pygame.event.get():
if event.type == QUIT:
running = False
elif event.type == MOUSEBUTTONDOWN:
if event.button == 1 and not ball_clicked: # Left mouse button clicked and no ball clicked
mouse_x, mouse_y = pygame.mouse.get_pos()
if ((mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2) <= BALL_RADIUS ** 2: # Check if click is inside the ball
hits += 1
ball_clicked = True
# Play the punch sound
punch_sound.play()
# Clear the screen
SCREEN.fill(BLACK)
if not ball_clicked:
# Draw the ball
draw_ball(ball_x, ball_y)
# Update ball position
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
# Check if the ball is clicked
mouse_click = pygame.mouse.get_pressed()
if mouse_click[0]: # Left mouse button clicked
if ((mouse_x - ball_x) ** 2 + (mouse_y - ball_y) ** 2) <= BALL_RADIUS ** 2: # Check if click is inside the ball
hits += 1
ball_clicked = True
# Play the punch sound
punch_sound.play()
# Check game duration
current_time = pygame.time.get_ticks()
if current_time - start_time >= game_duration:
running = False
else:
# Create a new ball
ball_x, ball_y = create_new_ball()
ball_clicked = False
# Display hits and time
pygame.font.init()
font = pygame.font.SysFont('Arial', 30)
hits_text = font.render("Hits: " + str(hits), True, RED)
time_text = font.render("Time: " + str((game_duration - (current_time - start_time)) // 1000), True, RED)
SCREEN.blit(hits_text, (50, 50))
SCREEN.blit(time_text, (WIDTH - 200, 50))
# Update the display
pygame.display.update()
# Quit Pygame
pygame.quit()
sys.exit()
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Nunja, du berechnest eben nur einmal eine Richtung, und dann titschst du einfach an den Raendern ab. Woher soll da eine Schlangenbewegung herkommen? Oder Biene oder so?
Wenn du sowas bauen willst, musst du etwas tiefer in die Trickkiste greifen, und zB den Richtungsvektor abhaengig vom Zufall regelmaessig um ein paar Grad in eine oder andere Richtung drehen. Oder sogar noch weiter gehen, und Zb einen Kreisradius auswuerfeln, und sich fuer ein paar Frames auf dem Bewegen (womit der Vektor also jeden Frame etwas anders ist). Etc. Da sind der Phantasie keine Grenzen gesetzt.
Wenn du sowas bauen willst, musst du etwas tiefer in die Trickkiste greifen, und zB den Richtungsvektor abhaengig vom Zufall regelmaessig um ein paar Grad in eine oder andere Richtung drehen. Oder sogar noch weiter gehen, und Zb einen Kreisradius auswuerfeln, und sich fuer ein paar Frames auf dem Bewegen (womit der Vektor also jeden Frame etwas anders ist). Etc. Da sind der Phantasie keine Grenzen gesetzt.
Hi Tobi,
schau dir mal diesen Youtube Channel und diese Playlist hier an: https://www.youtube.com/watch?v=70MQ-Fu ... gGXKUUsPOM
Hier ist das Online Buch dazu: https://natureofcode.com/
Der Code ist zwar in Processing, das ist Java ähnlich, ist aber ohne Probleme in andere Sprachen umsetzbar.
schau dir mal diesen Youtube Channel und diese Playlist hier an: https://www.youtube.com/watch?v=70MQ-Fu ... gGXKUUsPOM
Hier ist das Online Buch dazu: https://natureofcode.com/
Der Code ist zwar in Processing, das ist Java ähnlich, ist aber ohne Probleme in andere Sprachen umsetzbar.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
- __blackjack__
- User
- Beiträge: 13707
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@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):
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.
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()
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.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Hi, ich bin ein bisschen weiter gekommen und habe eine Bewegung hinbekommen, die ist aber nicht wirklich flüssig und bewegt sich auch nicht über den ganzen Bildschirm. Kann mir jemand helfen und sagen was man ändern könnte?
Wie kann man den Code darstellen dass er gut lesbar ist?
import pygame
import sys
import random
# Initialisierung von Pygame
pygame.init()
# Bildschirmgröße
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
# Hintergrund laden
background = pygame.image.load("/home/nala/Ballspiel/hintergrund.png")
background = pygame.transform.scale(background, (screen.get_width(), screen.get_height()))
# Biene laden und verkleinern
biene_original = pygame.image.load("/home/nala/Ballspiel/biene3.png").convert_alpha()
biene = pygame.transform.scale(biene_original, (int(biene_original.get_width() * 0.5), int(biene_original.get_height() * 0.5)))
bee_rect = biene.get_rect(center=(screen.get_width() // 2, screen.get_height() // 2)) # Startposition in der Mitte des Bildschirms
# Countdown-Bilder laden
countdown_images = [
pygame.image.load("/home/nala/Ballspiel/3.png").convert_alpha(),
pygame.image.load("/home/nala/Ballspiel/2.png").convert_alpha(),
pygame.image.load("/home/nala/Ballspiel/1.png").convert_alpha()
]
# Vektor für die Bewegung der Biene
bee_velocity = pygame.math.Vector2(0, 0)
# Sound laden
hit_sound = pygame.mixer.Sound("/home/nala/Ballspiel/hit.mp3")
# Font initialisieren
font = pygame.font.Font(None, 36)
# Spielzeit
game_time = 60 # 1 Minute in Sekunden
game_start_time = pygame.time.get_ticks()
# Klicks
clicks = 0
# Countdown Variable initialisieren
countdown_index = 0
countdown_duration = 1000 # 1 Sekunde pro Countdown
# Countdown zeigen
while countdown_index < len(countdown_images):
screen.blit(countdown_images[countdown_index], (screen.get_width() // 2 - countdown_images[countdown_index].get_width() // 2,
screen.get_height() // 2 - countdown_images[countdown_index].get_height() // 2))
pygame.display.flip()
pygame.time.wait(countdown_duration) # Wartezeit für jedes Bild im Countdown
countdown_index += 1
# Spiel-Schleife nach Countdown
running = True
clock = pygame.time.Clock()
while running:
# Ereignisse überprüfen
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# Wenn Mausklick innerhalb der Biene
if bee_rect.collidepoint(event.pos):
# Sound abspielen
hit_sound.play()
# Biene ausblenden
screen.blit(background, bee_rect, bee_rect)
pygame.display.flip()
# Neue zufällige Position setzen
bee_rect.center = (random.randint(0, screen.get_width()), random.randint(0, screen.get_height()))
# Klicks erhöhen
clicks += 1
# Spielzeit aktualisieren
current_time = pygame.time.get_ticks()
time_elapsed = (current_time - game_start_time) // 1000 # Umwandlung von Millisekunden in Sekunden
time_remaining = max(0, game_time - time_elapsed)
# Wenn die Spielzeit abgelaufen ist, Spiel beenden
if time_remaining <= 0:
running = False
# Zufälligen Vektor für die Bewegung der Biene wählen
random_direction = pygame.math.Vector2(random.uniform(-5, 5), random.uniform(-5, 5))
# Geschwindigkeit auf eine maximale Länge von 10 begrenzen
random_direction.scale_to_length(random.uniform(1, 10)) # Zufällige Geschwindigkeit zwischen 1 und 10
# Neue Geschwindigkeit setzen
bee_velocity = random_direction
# Biene bewegen
bee_rect.move_ip(bee_velocity)
# Wenn die Biene den Bildschirmrand erreicht, bringen Sie sie zurück
if bee_rect.left < 0 or bee_rect.right > screen.get_width() or bee_rect.top < 0 or bee_rect.bottom > screen.get_height():
bee_rect.center = (random.randint(0, screen.get_width()), random.randint(0, screen.get_height())) # Zufällige Startposition
# Hintergrund und Biene zeichnen
screen.blit(background, (0, 0))
screen.blit(biene, bee_rect)
# Spielzeit und Klicks anzeigen
time_text = font.render(f"Time: {time_remaining} seconds", True, (255, 255, 255))
click_text = font.render(f"Clicks: {clicks}", True, (255, 255, 255))
screen.blit(time_text, (screen.get_width() - time_text.get_width(), 0))
screen.blit(click_text, (0, 0))
# Bildschirm aktualisieren
pygame.display.flip()
# Begrenze die Bildrate auf 60 Frames pro Sekunde
clock.tick(60)
# Spielzeit und Klicks am Ende des Spiels anzeigen
end_time_text = font.render(f"Time: {time_remaining} seconds", True, (255, 255, 255))
end_click_text = font.render(f"Clicks: {clicks}", True, (255, 255, 255))
screen.blit(end_time_text, (screen.get_width() - end_time_text.get_width(), 0))
screen.blit(end_click_text, (0, 0))
# Biene Retry Bild anzeigen
screen.blit(biene_retry, biene_retry_rect)
pygame.display.flip()
# Warten auf Klick auf Biene Retry Bild
retry_clicked = False
while not retry_clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
retry_clicked = True
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and bee_retry_rect.collidepoint(event.pos):
retry_clicked = True
pygame.quit()
sys.exit()
Wie kann man den Code darstellen dass er gut lesbar ist?
import pygame
import sys
import random
# Initialisierung von Pygame
pygame.init()
# Bildschirmgröße
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
# Hintergrund laden
background = pygame.image.load("/home/nala/Ballspiel/hintergrund.png")
background = pygame.transform.scale(background, (screen.get_width(), screen.get_height()))
# Biene laden und verkleinern
biene_original = pygame.image.load("/home/nala/Ballspiel/biene3.png").convert_alpha()
biene = pygame.transform.scale(biene_original, (int(biene_original.get_width() * 0.5), int(biene_original.get_height() * 0.5)))
bee_rect = biene.get_rect(center=(screen.get_width() // 2, screen.get_height() // 2)) # Startposition in der Mitte des Bildschirms
# Countdown-Bilder laden
countdown_images = [
pygame.image.load("/home/nala/Ballspiel/3.png").convert_alpha(),
pygame.image.load("/home/nala/Ballspiel/2.png").convert_alpha(),
pygame.image.load("/home/nala/Ballspiel/1.png").convert_alpha()
]
# Vektor für die Bewegung der Biene
bee_velocity = pygame.math.Vector2(0, 0)
# Sound laden
hit_sound = pygame.mixer.Sound("/home/nala/Ballspiel/hit.mp3")
# Font initialisieren
font = pygame.font.Font(None, 36)
# Spielzeit
game_time = 60 # 1 Minute in Sekunden
game_start_time = pygame.time.get_ticks()
# Klicks
clicks = 0
# Countdown Variable initialisieren
countdown_index = 0
countdown_duration = 1000 # 1 Sekunde pro Countdown
# Countdown zeigen
while countdown_index < len(countdown_images):
screen.blit(countdown_images[countdown_index], (screen.get_width() // 2 - countdown_images[countdown_index].get_width() // 2,
screen.get_height() // 2 - countdown_images[countdown_index].get_height() // 2))
pygame.display.flip()
pygame.time.wait(countdown_duration) # Wartezeit für jedes Bild im Countdown
countdown_index += 1
# Spiel-Schleife nach Countdown
running = True
clock = pygame.time.Clock()
while running:
# Ereignisse überprüfen
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
# Wenn Mausklick innerhalb der Biene
if bee_rect.collidepoint(event.pos):
# Sound abspielen
hit_sound.play()
# Biene ausblenden
screen.blit(background, bee_rect, bee_rect)
pygame.display.flip()
# Neue zufällige Position setzen
bee_rect.center = (random.randint(0, screen.get_width()), random.randint(0, screen.get_height()))
# Klicks erhöhen
clicks += 1
# Spielzeit aktualisieren
current_time = pygame.time.get_ticks()
time_elapsed = (current_time - game_start_time) // 1000 # Umwandlung von Millisekunden in Sekunden
time_remaining = max(0, game_time - time_elapsed)
# Wenn die Spielzeit abgelaufen ist, Spiel beenden
if time_remaining <= 0:
running = False
# Zufälligen Vektor für die Bewegung der Biene wählen
random_direction = pygame.math.Vector2(random.uniform(-5, 5), random.uniform(-5, 5))
# Geschwindigkeit auf eine maximale Länge von 10 begrenzen
random_direction.scale_to_length(random.uniform(1, 10)) # Zufällige Geschwindigkeit zwischen 1 und 10
# Neue Geschwindigkeit setzen
bee_velocity = random_direction
# Biene bewegen
bee_rect.move_ip(bee_velocity)
# Wenn die Biene den Bildschirmrand erreicht, bringen Sie sie zurück
if bee_rect.left < 0 or bee_rect.right > screen.get_width() or bee_rect.top < 0 or bee_rect.bottom > screen.get_height():
bee_rect.center = (random.randint(0, screen.get_width()), random.randint(0, screen.get_height())) # Zufällige Startposition
# Hintergrund und Biene zeichnen
screen.blit(background, (0, 0))
screen.blit(biene, bee_rect)
# Spielzeit und Klicks anzeigen
time_text = font.render(f"Time: {time_remaining} seconds", True, (255, 255, 255))
click_text = font.render(f"Clicks: {clicks}", True, (255, 255, 255))
screen.blit(time_text, (screen.get_width() - time_text.get_width(), 0))
screen.blit(click_text, (0, 0))
# Bildschirm aktualisieren
pygame.display.flip()
# Begrenze die Bildrate auf 60 Frames pro Sekunde
clock.tick(60)
# Spielzeit und Klicks am Ende des Spiels anzeigen
end_time_text = font.render(f"Time: {time_remaining} seconds", True, (255, 255, 255))
end_click_text = font.render(f"Clicks: {clicks}", True, (255, 255, 255))
screen.blit(end_time_text, (screen.get_width() - end_time_text.get_width(), 0))
screen.blit(end_click_text, (0, 0))
# Biene Retry Bild anzeigen
screen.blit(biene_retry, biene_retry_rect)
pygame.display.flip()
# Warten auf Klick auf Biene Retry Bild
retry_clicked = False
while not retry_clicked:
for event in pygame.event.get():
if event.type == pygame.QUIT:
retry_clicked = True
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and bee_retry_rect.collidepoint(event.pos):
retry_clicked = True
pygame.quit()
sys.exit()
Für realistische Bewegungen muß man die Physik berücksichtigen. Ein Objekt bewegt sich gleichförmig in eine Richtung, so lange keine Kraft auf es einwirkt.
Konkret, Dein Objekt hat eine Position und eine Geschwindigkeit, die änderst die Geschwindigkeit abrupt, was aber nicht unrealistisch ist, daher die komischen Bewegungen.
Das einfachste Beispiel ist ein Ball, der nach unten gezogen wird.
Wenn er einen Anfangsort und eine Anfangsgeschwindigkeit hat, bewegt er sich auf einer Parabelbahn. Da es dafür genug Beispiele im Netz gibt, würde ich empfehlen, dass Du damit mal anfängst, um ein Gefühl für Physik zu bekommen.
Konkret, Dein Objekt hat eine Position und eine Geschwindigkeit, die änderst die Geschwindigkeit abrupt, was aber nicht unrealistisch ist, daher die komischen Bewegungen.
Das einfachste Beispiel ist ein Ball, der nach unten gezogen wird.
Wenn er einen Anfangsort und eine Anfangsgeschwindigkeit hat, bewegt er sich auf einer Parabelbahn. Da es dafür genug Beispiele im Netz gibt, würde ich empfehlen, dass Du damit mal anfängst, um ein Gefühl für Physik zu bekommen.
Ich halte Physik hier für möglich, aber nicht nötig. Am Ende wirkt eine Trägheit + Kraft nahezu identisch zu einem Tiefpassfilter. Oder einfach einer trägeren Steuerung. Zb indem man die gewählte Richtung nur im gewissen Rahmen nach links/rechts verändert. Spannender ist da schon die Frage nach der Abdeckung des Bildschirms. Ich würde da mit einer groben Heatmap arbeiten. Also eine Kachel-Aufteilung des Bildschirms, bei der man für jede Kachel einfach vermerkt, wie lange/of die Biene da drin war. Man wählt als Ziel eine der Kacheln mit der niedrigsten Belegung aus, und mischt immer einen Vektor in deren Richtung anteilig dazu. Sobald man da angekommen ist, kann man die Kachel zb “bestrafen”, also extra teuer machen. Und dann sucht man die nächste. Das ganze lässt sich viel variieren, zb kann man den Cursor des Users ebenfalls die Belegung erhöhen passen, und erreicht dadurch, das die Biene die Richtung eher vermeidet.
Zur Frage der Code Formatierung: das geht mit den Code-Tags, ist der </>-Knopf im vollständigen Editor.
Zur Frage der Code Formatierung: das geht mit den Code-Tags, ist der </>-Knopf im vollständigen Editor.
Ich habe mal eine Variante gecodet, die mir ganz gut gefaellt. Und die eine Mischung aus zufaelliger Bewegung mit einem gezielten Anflug eines Punktes zeigt. Wenn man den letzteren basierend auf der genannten Heatmap macht, dann sollte der gesamte Bereich des Bildschirmes abgedeckt werden.
Code: Alles auswählen
import pygame
import pathlib
import math
import numpy as np
import time
import random
BEE_PATH = pathlib.Path(__file__).parent / "atari-st-busy-bee.png"
assert BEE_PATH.exists()
class Bee:
# turn rate per second in degrees
MAXIMUM_TURN_RATE = 700
# pixels per second
MAX_SPEED = 200
PATTERN_LENGTH_BOUNDS = (.3, 1.5)
TARGET_POS_WEIGHT = 5.0
def __init__(self, pos=(200, 200)):
self._bee = pygame.image.load(str(BEE_PATH))
self.pos = np.array(pos, dtype=np.float_)
self._previous_pos = None
self.orientation = 0.0 # rad
# rotation change per second in rad
self._dw = 1.0
# orientation of the bee is upwards, so that's the
# directional speed component
self._speed = np.array((0.0, -self.MAX_SPEED))
self._until = time.monotonic()
self._target_pos = None
def update_target_pos(self, pos):
if pos is not None:
self._target_pos = np.array(pos, dtype=np.float_)
else:
self._target_pos = None
def update(self, dt):
if time.monotonic() >= self._until:
self._randomize_flight()
self.orientation += dt * self._dw
# the negation is needed to orientate leftwards,
# in accordance with the pygame.transform.rotate interpretation
# of that quantity.
c, s = np.cos(-self.orientation), np.sin(-self.orientation)
R = np.array(((c, -s), (s, c)))
dp = np.matmul(R, self._speed) * dt
if self._target_pos is not None:
tv = (self._target_pos - self.pos)
tv = tv / np.linalg.norm(tv) * self.TARGET_POS_WEIGHT
else:
tv = np.array((0.0, 0.0))
self._previous_pos = np.array(self.pos)
self.pos += dp + tv
@property
def flight_orientation(self):
if self._previous_pos is not None:
d = self.pos - self._previous_pos
# Negation and rotated coordinates account
# for the different coordinate systems
# in pixels vs atan2 being mathy
return -math.atan2(d[0], -d[1])
return 0.0
def _randomize_flight(self):
# for a few seconds
l, h = self.PATTERN_LENGTH_BOUNDS
self._until = time.monotonic() + random.random() * (h - l) + l
degrees = (random.random() - 0.5) * self.MAXIMUM_TURN_RATE
rad = degrees / 180.0 * math.pi
self._dw = rad
def blit(self, dest):
rotation = 180 * (-math.pi / 4 + self.flight_orientation) / math.pi
bee = pygame.transform.rotate(self._bee, rotation)
# Correct for the transform's resizing
# and place the center of the bee over
# the coordinate
w, h = bee.get_size()
ow, oh = self._bee.get_size()
diff = np.array((ow - w, oh - h))
pos = tuple(self.pos + diff / 2 - np.array((ow, oh)) / 2)
sw, sh = dest.get_size()
dest.blit(bee, (pos[0] % sw, pos[1] % sh))
def main():
pygame.init()
screen = pygame.display.set_mode([500, 500])
bee = Bee()
clock = pygame.time.Clock()
running = True
while running:
elapsed = clock.tick(30) * .001
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
screen.fill((255, 255, 255))
left, _, right = pygame.mouse.get_pressed(num_buttons=3)
if left:
bee.update_target_pos(pygame.mouse.get_pos())
elif right:
bee.update_target_pos(None)
bee.update(elapsed)
bee.blit(screen)
pygame.display.flip()
pygame.quit()
if __name__ == '__main__':
main()
- __blackjack__
- User
- Beiträge: 13707
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
Könnte sein, dass Du ein bisschen was manuell nachprogrammiert hast, was es schon als `pygame.Vector2` gibt.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer