Odbijanie piłeczki

0

Cześć,
na wstępie chciałbym zaznaczyć, że jestem początkującym programistą Pythona, więc nie bijcie, jeśli popełniłem jakieś błędy w kodzie, to proszę o konstruktywną krytykę i porady, a nie wiadro pomyj na twarz.
Chciałbym dodać do własności odbijanej piłki, taką, która sprawi, że w zależności od tego, jak blisko krawędzi znajduje się piłka przy odbiciu, to proporcjonalnie szybciej będzie leciała w górę (jeśli znajduje się na górnej połowie prostokąta), lub w dół (jeśli znajduje się na dolnej części prostokąta), konkretnie chodzi o metodę move klasy Ball. Proszę o jakieś propozycje.

# zaimportowanie modułu pygame
import pygame

# tworzenie okienka
pygame.init()
win = pygame.display.set_mode((500, 500))

# funkcja clock do ustawienia ilości FPS
clock = pygame.time.Clock()

# załadowanie obrazu tła
bg = pygame.image.load("bg.jpg")


class Rectangle(object):
    """Tworzy obiekt prostokąta w okienku"""
    def __init__(self, x, y, width, height, vel):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = vel
        self.up = False
        self.down = False

    def draw(self, window):
        """Rysuje prostokąt"""
        pygame.draw.rect(window, (255, 0, 0), (self.x, self.y, self.width, self.height))

    def move(self):
        """Umożliwia zmianę położenia prostokąta w okienku"""
        self.keys = pygame.key.get_pressed()
        if self.keys[pygame.K_UP] and self.y >= 0:
            self.y -= self.vel
        elif self.keys[pygame.K_DOWN] and self.y <= 500 - self.height:
            self.y += self.vel


class Ball(object):
    """Tworzy obiekt piłki w okienku"""
    def __init__(self, x, y, facing, vel):
        self.x = x
        self.y = y
        self.facing = facing
        self.vel = vel
        self.move_up = False
        self.move_down = False

    def draw(self, window):
        """Rysuje piłkę w okienku"""
        pygame.draw.circle(window, (0, 255, 0), (self.x, self.y), 10)

    def move(self):
        """Umożliwa zmianę położenia piłki"""
        self.x += self.vel * self.facing
        # Seria warunków sprawdząjących, czy piłka dotkyka prostokąta
        if player.x + player.width + 10 >= self.x:
            if self.y in range(player.y, player.y + player.height):

                # Warunki sprawdzające na której połowie prostokąta znajduje się piłka
                if self.y in range(player.y, player.y + player.height//2 - 10):
                    self.move_up = True
                    self.move_down = False
                elif self.y in range(player.y + player.height//2, player.y + player.height + 10):
                    self.move_down = True
                    self.move_up = False
                self.facing = self.facing * -1
#        print(player.y, player.y + player.height)

        # Ustalenie wartości wznoszenia i opadania
        if self.move_up:
            self.y -= 1
        elif self.move_down:
            self.y += 1
        else:
            self.y += 0

        # Tworzenie ścian w okienku
        if self.x >= 500:
            self.facing = self.facing * -1
        elif self.y >= 500:
            self.move_down = False
            self.move_up = True
        elif self.y <= 0:
            self.move_up = False
            self.move_down = True


def redraw_game_window():
    """Odświeża obraz okienka"""
    win.blit(bg, (-350, -200))
    player.draw(win)
    ball.draw(win)
    pygame.display.update()


# utworzenie obiektu player na podstawie klasy Rectangle
player = Rectangle(20, 220, 20, 100, 5)
ball = Ball(250, 250, -1, 6)

# pętla główna
run = True
while run:
    clock.tick(60)
    # zamyka okienko po naciśnięciu przycisku zamkknięcia
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    player.move()
    ball.move()
    redraw_game_window()

1

Może dobrze jest wziąć jakąś funkcję np. parabolę i zakres od x dla y=x^2, ustawić jako zakres szerokości tego prostokąta i jak np. im bardziej oddalony tym bardziej proporcjonalna siłą będzie.

krzywymi beziera można sobie ustawić taką krzywą, która będzie idealnie reprezentowała wartości, które idealnie będą odwzorowywać siłę w zależności od położenia , w normalnym pongu jeszcze się dodaje prędkość poruszania platformy, która odbija.

3

Tak na szybko: funkcja move powinna robić dokładnie to co sugeruje nazwa funkcji: zmieniać położenie piłki. Dlatego kod sprawdzający czy piłka dotyka prostokąta powinien być w innej funkcji (np. isTouchingRect). Funkcja ta może być zdefiniowana w Rectangle.

Zamiast zmiennych move_up, move_down użyj jednej zmiennej z wartością domyślną 0. W takim wypadku funkcja move wygląda tak:

    def move(self):
        """Umożliwa zmianę położenia piłki"""
        self.x += self.vel * self.facing
        # Seria warunków sprawdząjących, czy piłka dotkyka prostokąta
        if player.x + player.width + 10 >= self.x:
            if self.y in range(player.y, player.y + player.height):
 
                # Warunki sprawdzające na której połowie prostokąta znajduje się piłka
                if self.y in range(player.y, player.y + player.height//2 - 10):
                    self.move_y = -1
                elif self.y in range(player.y + player.height//2, player.y + player.height + 10):
                    self.move_y = 1
                else:
                  self.move_y = 0
                self.facing = self.facing * -1
#        print(player.y, player.y + player.height)
 
        # Ustalenie wartości wznoszenia i opadania
        self.y += self.move_y
 
        # Tworzenie ścian w okienku
        if self.x >= 500:
            self.facing = self.facing * -1
        elif self.y >= 500:
            self.move_y = -1
        elif self.y <= 0:
           self.move_y = 1

Przy odbiciu od ścian możesz zwiększyć prędkość piłeczki self.vel (która będzie maleć z każdym kolejnym wywołaniem move aż to min wartości np. 1). I teraz jeżeli chcesz uzależnić zwiększenie prędkości piłeczki od tego jak blisko krawędzi Rectangle jest wystarczy przypisać self.vel = (player.height//2 - player.y) * some_const dla górnej połowy i analogicznie self.vel = (player.y - player.height//2) * some_const dla drugiej krawędzi (o ile kolejność zmiennych nie pomylłem, + dobierz some_const).

Bardziej zaawansowana gra wymaga obliczeń kąta i aktualizację pozycji x i y względem kąta piłeczki i prędkości

1 użytkowników online, w tym zalogowanych: 0, gości: 1