Ball hat ein statisches movement

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Lengeta
User
Beiträge: 6
Registriert: Freitag 19. März 2021, 12:14

Hey Leute,
Ich versuche gerade ein Pong ähnliches spiel zu programmieren und bin dabei auf das Problem gestoßen, dass der Ball exakt den selben weg nimmt und so das spiel natürlich extrem langweilig ist.
Ich hab auch kein gutes Pong tutorial gefunden, wo der Ball eine realistische Logik hat.
Habt ihr irgendeine idee, wie ich den Ball besser schreiben kann?

Code: Alles auswählen

import pygame
import random
import time

# colors
red = (255, 0, 0)
green = (0, 255, 0)
blue = (0, 0, 255)
white = (255, 255, 255)
black = (0, 0, 0)
light_gray = (200, 200, 200)
dark_gray = (50, 50, 50)
blood = (102, 0, 0)
colors = [red, green, black, blue, white, light_gray]

# constants
FPS = 60

class Game():
    def __init__(self):
        # general settings
        pygame.init()
        clock = pygame.time.Clock()
        self.player_speed = 0
        self.ball_speed_x = 4 * random.choice((1, -1))
        self.ball_speed_y = 4
        self.score = 0
        self.game_over = False

        # window settings
        self.width = 400
        self.height = 800
        self.screen = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption("bounce em all")

        # game rectangles
        self.player = pygame.Rect(self.width / 2 - 20, 760, 40, 10)
        self.ball = pygame.Rect(self.width / 2, 50, 10, 10)
        self.left_border = pygame.Rect(0, 0, 10, self.height)
        self.right_border = pygame.Rect(self.width - 10, 0, 10, self.height)
        self.upper_border = pygame.Rect(0, 0, self.width, 10)

        # game loop
        running = True
        while running:
            # input handling
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False

                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_RIGHT:
                        self.player_speed += 7
                    if event.key == pygame.K_LEFT:
                        self.player_speed -= 7

                if event.type == pygame.KEYUP:
                    if event.key == pygame.K_RIGHT:
                        self.player_speed -= 7
                    if event.key == pygame.K_LEFT:
                        self.player_speed += 7

            # commands
            self.player_movement()
            self.ball_movement()

            # visuals
            self.screen.fill(white)
            pygame.draw.rect(self.screen, red, self.player)
            pygame.draw.rect(self.screen, dark_gray, self.left_border)
            pygame.draw.rect(self.screen, dark_gray, self.right_border)
            pygame.draw.rect(self.screen, dark_gray, self.upper_border)
            pygame.draw.ellipse(self.screen, blue, self.ball)

            # update and time
            self.print_score()
            if self.game_over == True:
                self.print_game_over()
            pygame.display.flip()
            clock.tick(FPS)

    # functions
    def player_movement(self):
        self.player.x += self.player_speed
        if self.player.left <= 10:
            self.player.left = 10
        if self.player.right >= self.width - 10:
            self.player.right = self.width - 10

    def ball_movement(self):
        self.ball.x += self.ball_speed_x
        self.ball.y += self.ball_speed_y

        # ball borders
        if self.ball.colliderect(self.player):
            self.ball_speed_y *= -1
            self.score += 1
        elif self.ball.colliderect(self.upper_border):
            self.ball_speed_y *= -1
        elif self.ball.colliderect(self.right_border):
            self.ball_speed_x *= -1
        elif self.ball.colliderect(self.left_border):
            self.ball_speed_x *= -1
        elif self.ball.y >= self.height:
            self.game_over = True
        # if ball left do ... of right ... and so on and so forth

    def print_game_over(self):
        go_font = pygame.font.Font("Youmurdererbb-pwoK.otf", 70)
        go_text = go_font.render("Game Over", False, blood)
        self.screen.blit(go_text, (80, 330))

    def print_score(self):
        score_font = pygame.font.Font("freesansbold.ttf", 17)
        score_text = score_font.render("Score: " + str(self.score), True, black)
        self.screen.blit(score_text, (14, 14))


game = Game()
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@Lengeta,

Hiermit

Code: Alles auswählen

self.ball_speed_x = 4 * random.choice((1, -1))
gibt es nur zwei mögliche Fälle: -4 und 4

Bei

Code: Alles auswählen

self.ball_speed_x = random.randint(-4, 4)
bekommst du wenigsten *alle* Werte zwischen -4 und 4.

Außerdem könnte man die Position von Spieler und Ball bei der Kollision vergleichen und die horizontale Geschwindigkeit des Ball vergrößern, wenn der Ball nicht zentral auf den Schläger auftrifft.

Code: Alles auswählen

# ball borders
if self.ball.colliderect(self.player):
    if abs(self.ball.centerx - self.player.centerx) > 5: # horizontale Verschibung zwischen Ball und Player mehr als 5 Pixel
        self.ball_speed_x *= 2   # Dann horizontale Geschwindigkeit des Balls verdoppeln
    self.ball_speed_y *= -1
    self.score += 1
  
Übrigens, die while-Schleife sollte nicht in der __init__ sondern in einer eigenen Methode angelegt sein.
Lengeta
User
Beiträge: 6
Registriert: Freitag 19. März 2021, 12:14

@rogerb:
Danke das mit der while schleife merk ich mir, aber warum sollte die nicht in die _init_ Methode?
DAs problem mit

Code: Alles auswählen

self.ball_speed_x = random.randint(-4, 4)
ist das die Geschwindigkeit sich dadurch auch ändert und der ball bewegt sich trotzdem noch vorhersagbar nur, hat er jetzt ein paar variationen.
In einem durchlauf hat er leider trotzdem noch das selbe Bewegungsmuster
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Dann musst du eben bei jedem Abprallvorgang wieder eine neue Geschwindigkeit zufällig bestimmen. Etwas realistischer ist im Zweifel nur eine kleine Änderung, damit die Grundrichtung erhalten bleibt.
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Danke das mit der while schleife merk ich mir, aber warum sollte die nicht in die _init_ Methode?
Die init-Methode wird automatisch aufgerufen wenn aus der Klasse ein Objekt erzeugt wird. Dabei dient die init-Methode dazu Instanz-Attribute zu initialisieren.
game = Game()

"game" ist das Objekt welches aus dem Bauplan der Klasse "Game" erstellt wurde. Das "game" Objekt wird erst erstellt nachdem die init-Methode abgearbeitet wurde. Da du dort eine Endlosschleife hast, passiert das aber erst wenn der Benutzer das Programm schließt.
In diesem Fall hat das keine Nachteile. In den meisten anderen Fällen für die man Klassen verwendet, aber schon. Daher sollte man das von Anfang an sauber programmieren.

Die while-Schleife könnte man in einer "run" Methode unterbringen und dann so verwenden:

Code: Alles auswählen

game = Game()
game.run()
In einem durchlauf hat er leider trotzdem noch das selbe Bewegungsmuster
Dafür hatte ich ja vorgeschlagen, beim seitlichen Treffen des Schlägers die horizontale Geschwindigkeit zu erhöhen.
Eine gewissen Berechenbarkeit ist ja auch gewünscht, sonst wird es ein reines Zufallsspiel.

Um es noch spannender zu machen kann man nach einer gewissen Zeit einen zweiten Ball ins Spiel bringen. Oder man kann auch weitere Hindernisse ins Spielfeld bauen an denen der Ball abprallt.
Die können dann wie beim klassischen Breakout zerstört werden, oder sie könnten durch den Impuls des Balls einfach verschoben werden.
Antworten