为什么我的Pong游戏中的命中框和碰撞无法正常工作?

时间:2016-05-19 02:15:40

标签: python tkinter

我有两个问题需要帮助修复。一个是当Pong球击中左侧或右侧的中间时 - 它猛烈地抽搐直到桨在它上面移动。它应该做的是,它应该向外反弹并远离墙壁,而不是猛烈地抽搐。

第二个问题与桨的击中框有关。现在,如果Pong球击中桨的中间,它的行为与预期的一样,但如果它击中顶部边缘或底部边缘,它会使球相位通过。

我想知道是否有人可以帮助我确定这些问题发生的原因,以及如何纠正这些问题。

from tkinter import *
import random
from math import *
##MAIN GAME PART##
window = Tk()
canvas = Canvas(window,width=400,height=400)
canvas.pack()
sideX = -1
sideY = 0
##FUNCTIONS##
def movePaddles(event):
    key=event.keysym
    if key == 'Up':
         canvas.move(PaddleTwo,0,-10)
    elif key == 'Down':
        canvas.move(PaddleTwo,0,10)
    if key == 'w':
        canvas.move(PaddleOne,0,-10)
    elif key == 's':
        canvas.move(PaddleOne,0,10)

def distance(target1,target2):
    target1coords = canvas.coords(target1)
    target2coords = canvas.coords(target2)
    x1 = (target1coords[0] + target1coords[2] ) / 2
    y1 = (target1coords[1] + target1coords[3] ) / 2
    x2 = (target2coords[0] + target2coords[2])  / 2
    y2 = (target2coords[1] + target2coords[3]) / 2
    d = sqrt( (x2-x1)** 2 + (y2-y1)** 2)
    return d

def checkCollisions():
    global sideX
    global sideY
    for e in PaddleList:
        if distance(PingPongBall,e) < 20:
            if e == 1:
                sideX = 1
                sideY = random.randint(0,1)
            elif e == 2:
                sideX = -1
                sideY = random.randint(0,1)
        canvas.move(PingPongBall,sideX,sideY)
def moveBall():
    ##Found no other way of changing these variables without global##
    global sideY
    global sideX
    for e in BallList:
        xcor = canvas.coords(e)[0]
        ycor = canvas.coords(e)[1]
        if xcor >= 400: ##Right side of screen
            if sideY == -1:
                sideY = 1
                sideX = 1
            elif sideY == 1:
                sideY = -1
                sideX = -1
            elif sideX == 1:
                sideX = -1
        if xcor <= 0: ##Left side of screen
            if sideY == -1:
                sideY = 1
                sideX = 1
            elif sideY == 1:
                sideY = -1
                sideX = -1
            elif sideX == -1:
                sideX = 1
        if ycor >= 400: ##Top of screen
            if sideY == -1:
                sideY = 1
            elif sideY == 1:
                sideY = -1
        if ycor <= 0: ##Bottom of screen
            if sideY == -1:
                sideY = 1
            elif sideY == 1:
                sideY = -1
##SET UP TIMER AKA INFINITE LOOP WITHOUT LAG##
timeLeft = 1
##PADDLES AND OTHER STUFF##       
PaddleOne = canvas.create_rectangle(10 ,150 ,25 ,250 ,fill='blue')
PaddleTwo = canvas.create_rectangle(400,150 ,385 ,250 ,fill='blue')
PingPongBall = canvas.create_rectangle(200, 200, 210 ,210 ,fill='red')
PaddleList = [PaddleOne,PaddleTwo]
BallList = [PingPongBall]
Target = PaddleList[0]
##KEY BINDINGS##
canvas.bind_all('<Key>',movePaddles)
##INFINITE LOOP##
while timeLeft > 0:
    checkCollisions()
    moveBall()
    window.update()

1 个答案:

答案 0 :(得分:0)

考虑这种控制结构:

if xcor >= 400: ##Right side of screen
    if sideY == -1:
        sideY = 1
        sideX = 1
    elif sideY == 1:
        sideY = -1
        sideX = -1
    elif sideX == 1:
        sideX = -1

让我们来看看可能的场景:

球在上升时击中右墙(sideY == -1)

  1. sideY为-1,因此将sideY设置为1,将sideX设置为1
  2. 将一个像素向右移动(进一步向墙壁移动),向下移动一个像素
  3. sideY现在为1,因此将sideY设置为-1,将sideX设置为-1
  4. 向左移动一个像素(仍然在墙上)并向上移动一个像素
  5. 返回步骤1.因为xcor>=400仍为True。
  6. 这将解释你的毛刺行为,当球接触球时它会被覆盖(我会在片刻解释一下),但实际上你的条件应该是这样的:

        if xcor >= 400: ##Right side of screen
            #make it go left
            sideX = -1
        if xcor <= 0: ##Left side of screen
            #make it go right
            sideX = 1
        if ycor >= 400: ##Bottom of screen
            #make it go up
            sideY = -1
        if ycor <= 0: ##Top of screen
            #make it go down
            sideY = 1
    

    至于你的hitbox,你只是检查从球的中心到球拍中心的距离是否小于20:

    if distance(PingPongBall,e) < 20:
    

    这只占桨的中间40%左右,这不是你想要的,你想知道它们是否重叠可以通过使用in来完成运算符,.find_overlapping方法和.bbox方法(这两种方法都是described here

    def is_overlapping(tag1,tag2):
        return tag1 in canvas.find_overlapping(*canvas.bbox(tag2))
    

    然后您可以通过以下方式检查球拍是否接触球:

    if is_overlapping(PingPongBall,e):