Как заставить мяч отскочить от стены с помощью Pygame? - PullRequest
1 голос
/ 18 января 2020

Прежде чем критиковать меня за то, что я не гуглю или не занимаюсь исследованиями, прежде чем спросить, я провел исследования заранее, но безрезультатно.

Я пытаюсь создать игру Atari Breakout. Я в настоящее время застрял на части, чтобы заставить мяч отскакивать от стен. Я провел исследование по этому вопросу и нашел много блогов и видео на YouTube (а также Stackoverflow this и this ), в которых рассказывается о классе pygame vector2. Я также прочитал документацию по pygame на vector2, но не могу понять, как заставить это работать.

В настоящее время я пишу сценарий, чтобы мяч отскакивал от стен. В начале игроку предлагается нажать пробел, и мяч автоматически переместится в северо-восточном направлении. Он должен отскочить от верхней стены, когда он ударит его, но вместо этого он вошел внутрь Это мой подход:

import pygame
pygame.init()

screenWidth = 1200
screenHeight = 700

window = pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption('Atari Breakout')

class Circle():

    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
        self.vel_x = 1
        self.vel_y = 1


def check_hit():
    global hit
    if (((screenWidth-box.x)<=box.radius) or ((box.x)<=box.radius) or ((box.y)<=box.radius) or ((screenHeight-box.y)<=box.radius)):
        # meaning  hit either four walls
        if (((screenWidth-box.x)<=box.radius) or ((box.x)<=box.radius)):
            # hit right, left
            print('hit right, left')
            hit = True
        elif (((box.y)<=box.radius) or ((screenHeight-box.y)<=box.radius)):
            # hit top, bottom
            print('hit top, bottom')
            hit = True


# main loop
run = True
box = Circle(600,300,10)
hit = False
                                                  # (screenWidth-box.x)<=box.radius     hit right wall
while run:                                        # (box.x)<=box.radius                 hit left wall
                                                  # (box.y)<=box.radius                 hit top wall                        
    pygame.time.Clock().tick(60)                  # (screenHeight-box.y)<=box.radius    hit bottom wall

    for event in pygame.event.get():
        if event == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()

    if keys[pygame.K_SPACE] and (box.y)>box.radius:
        while True:
            box.y -= box.vel_y        
            box.x += box.vel_x

            window.fill((0,0,0))
            pygame.draw.circle(window, (44,176,55), (box.x, box.y), box.radius)
            pygame.display.update()

            check_hit()
            if hit == False:
                continue
            elif hit == True:
                break

        if (box.y)<=box.radius or (screenHeight-box.y)<=box.radius:
            # hit top, bottom
            box.vel_x *= 1
            box.vel_y *= -1
            print('changed')

            if (box.y)<=box.radius:
                # hit top
                print('hi')
                while True:
                    box.x += box.vel_x               # <-- myguess is this is the problem
                    box.y += box.vel_y


                    window.fill((0,0,0))
                    pygame.draw.circle(window, (44,176,55), (box.x, box.y), box.radius)
                    pygame.display.update()




        elif (screenWidth-box.x)<=box.radius or (box.x)<=box.radius:
            # hit right, left
            box.vel_x *= -1
            box.vel_y *= 1






    window.fill((0,0,0))
    pygame.draw.circle(window, (44,176,55), (box.x, box.y), box.radius)
    pygame.display.update()


    print('Where are you going')

pygame.quit()

Я думаю, проблема в том, где я отметил. Что здесь:

        if (box.y)<=box.radius or (screenHeight-box.y)<=box.radius:
            # hit top, bottom
            box.vel_x *= 1
            box.vel_y *= -1
            print('changed')

            if (box.y)<=box.radius:
                # hit top
                print('hi')
                while True:
                    box.x += box.vel_x               # <-- myguess is this is the problem
                    box.y += box.vel_y


                    window.fill((0,0,0))
                    pygame.draw.circle(window, (44,176,55), (box.x, box.y), box.radius)
                    pygame.display.update()

но я не знаю почему. Моя теория такова: мяч движется вверх, он ударяется о верхнюю стенку, check_hit() пробивает и делает hit = True, тогда vel_x и vel_y соответственно изменяются (если ударить по верхней стене, vel_x должен остаются неизменными, в то время как vel_y следует умножить на -1). Затем он сместится вниз, отсюда и «отскок» от верхней стены.

Примечание: на данный момент у меня работает только верхняя стена. Остальные три будут выполнены, когда я смогу выяснить, как сначала отскочить от верхней стены.

Можете ли вы помочь мне понять, в чем проблема? И если для такого рода операций требуется класс vector2, вы можете мне это объяснить или дать мне место для его изучения?

Спасибо.

1 Ответ

3 голосов
/ 18 января 2020

Проблема заключается в нескольких вложенных циклах. У вас есть приложение l oop, поэтому используйте его.
Постоянно перемещайте шар в l oop:

box.y -= box.vel_y        
box.x += box.vel_x

Определите область прямоугольника angular для шара с помощью pygame.Rect объект:

bounds = window.get_rect() # full screen

или

bounds = pygame.Rect(450, 200, 300, 200)  # rectangular region

Изменить направление движения, когда мяч достигнет границ:

if box.x - box.radius < bounds.left or box.x + box.radius > bounds.right:
    box.vel_x *= -1 
if box.y - box.radius < bounds.top or box.y + box.radius > bounds.bottom:
    box.vel_y *= -1 

См. Пример:

box = Circle(600,300,10)

run = True
start = False
clock = pygame.time.Clock()

while run:                     
    clock.tick(120)  

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_SPACE]:
        start = True

    bounds = pygame.Rect(450, 200, 300, 200)
    if start:
        box.y -= box.vel_y        
        box.x += box.vel_x

        if box.x - box.radius < bounds.left or box.x + box.radius > bounds.right:
            box.vel_x *= -1 
        if box.y - box.radius < bounds.top or box.y + box.radius > bounds.bottom:
            box.vel_y *= -1 

    window.fill((0,0,0))
    pygame.draw.rect(window, (255, 0, 0), bounds, 1)
    pygame.draw.circle(window, (44,176,55), (box.x, box.y), box.radius)
    pygame.display.update()
...