1

我正在尝试使用 Zelle graphics.py 让我的圆圈从我的矩形中反弹。一旦圆圈从矩形反弹,我希望它继续随机移动。到目前为止,这是我的代码,它正在工作!我也知道,从技术上讲,每个圆形图形都可以使用适合圆形的最小正方形的点来进行碰撞,但我在这样做时遇到了麻烦。

from graphics import *
import random

def delay(d):
    for i in range(d):
        for i in range(50):
            pass
#-------------------------------------------------
def main():


    win=GraphWin("Moving Circle",500,400)
    win.setBackground('white')
    pt= Point(100,200)
    cir=Circle(pt,30)
    #changes the color of the circle for each game
    r = random.randrange(256)
    b = random.randrange(256)
    g = random.randrange(256)
    color = color_rgb(r, g, b)
    cir.setFill(color)
    cir.draw(win)
#rectangle
    rec = Rectangle(Point(450,450), Point(275, 425))
    rec.draw(win)
    rec.setFill('black')
#-------------------------------------------------
    pt5 = Point(250,30)
    instruct1=Text(pt5, "click multiple times to start(rectangle can take multiple clicks to move)")
    instruct1.setTextColor('black')
    instruct1.draw(win)


#-------------------------------------------------
    p=cir.getCenter()
    p2=win.getMouse()

    dx=1
    dy=1

    keepGoing=True

    while keepGoing:
        d = 100
        delay(d)
        cir.move(dx,dy)
        p=cir.getCenter()
        p2=win.checkMouse()
        instruct1.setText("")


#rectanlge
        isClicked= win.checkMouse()
        if isClicked:
            rp = isClicked
            rc = rec.getCenter()
            rdx = rp.getX() - rc.getX()
            rdy = rp.getY() - rc.getY()
            rec.move(rdx,rdy)

#circle
        if((p.getX()-30)<=0.0) or ((p.getX()+30)>=500):
            dx= -dx

        if((p.getY()-30)<=0.0) or ((p.getY()+30)>=400):
            dy=-dy
        p3=win.checkMouse()



main()
4

1 回答 1

1

我知道从技术上讲,每个圆形图形都可以使用围绕圆形的最小可能正方形的点来进行碰撞

我在玩另一种想法——我们可以考虑在矩形周围画一个圆圈,而不是在圆圈周围画一个正方形。对我来说,问题是我们不仅需要检测碰撞,还需要知道从哪个方向离开另一个物体。这不仅仅是TrueFalse而是一种(dx, dy)结果。

显然,矩形周围的圆太粗糙了,但是假设它是由许多较小的圆组成的矩形,我们测量圆心到圆心的距离来检测命中:

在此处输入图像描述

仅在中心(绿色)矩形圆上命中意味着反转大圆的垂直方向。击中末端(红色)圆圈意味着反转大圆圈的水平方向。我们可以检测到这两种命中并完全反转大圆圈。

考虑到上述内容,这是我对您的代码的返工——我还修复了您的多次单击问题并进行了许多样式更改:

from random import randrange
from graphics import *

WIDTH, HEIGHT = 500, 400

RADIUS = 30

def delay(d):
    for _ in range(d):
        for _ in range(50):
            pass

def distance(p1, p2):
    return ((p2.getX() - p1.getX()) ** 2 + (p2.getY() - p1.getY()) ** 2) ** 0.5

def intersects(circle, rectangle):

    dx, dy = 1, 1  # no change

    center = circle.getCenter()

    rectangle_radius = (rectangle.p2.getY() - rectangle.p1.getY()) / 2
    rectangle_width = rectangle.p2.getX() - rectangle.p1.getX()

    y = rectangle.getCenter().getY()

    for x in range(int(rectangle_radius * 2), int(rectangle_width - rectangle_radius * 2) + 1, int(rectangle_radius)):
        if distance(center, Point(rectangle.p1.getX() + x, y)) <= rectangle_radius + RADIUS:
            dy = -dy  # reverse vertical
            break

    if distance(center, Point(rectangle.p1.getX() + rectangle_radius, y)) <= rectangle_radius + RADIUS:
            dx = -dx  # reverse horizontal
    elif distance(center, Point(rectangle.p2.getX() - rectangle_radius, y)) <= rectangle_radius + RADIUS:
            dx = -dx  # reverse horizontal

    return (dx, dy)

def main():
    win = GraphWin("Moving Circle", WIDTH, HEIGHT)

    circle = Circle(Point(WIDTH / 5, HEIGHT / 2), RADIUS)

    # change the color of the circle for each game
    color = color_rgb(randrange(256), randrange(256), randrange(256))
    circle.setFill(color)

    circle.draw(win)

    # rectangle
    rectangle = Rectangle(Point(275, 425), Point(450, 450))  # off screen
    rectangle.setFill('black')
    rectangle.draw(win)

    dx, dy = 1, 1

    while True:
        delay(100)
        circle.move(dx, dy)

        # rectangle
        isClicked = win.checkMouse()

        if isClicked:
            point = isClicked
            center = rectangle.getCenter()
            rectangle.move(point.getX() - center.getX(), point.getY() - center.getY())

        # circle
        center = circle.getCenter()

        if (center.getX() - RADIUS) <= 0.0 or (center.getX() + RADIUS) >= WIDTH:
            dx = -dx

        if (center.getY() - RADIUS) <= 0.0 or (center.getY() + RADIUS) >= HEIGHT:
            dy = -dy

        # collision bounce

        x, y = intersects(circle, rectangle)
        dx *= x
        dy *= y

main()

不完美,但可以玩一些,可能会插入更好的intersects()实现。

于 2017-09-28T18:12:16.453 回答