简体   繁体   English

Zelle graphics.py中的碰撞

[英]Collisions in Zelle graphics.py

I am trying to make my circle bounce off of my rectangle using Zelle graphics.py. 我正在尝试使用Zelle graphics.py使我的圆跳出矩形。 Once the circle bounces off of the rectangle I wanted it to keep moving randomly. 圆从矩形反弹回来后,我希望它继续随机移动。 Here is my code so far, and it's working! 到目前为止,这是我的代码,并且可以正常工作! Also I know that each circle graphics technically can use the points of the smallest possible square that would fit around the circle to do the collision but I'm having trouble with doing that. 我也知道,每个圆形图形在技术上都可以使用适合圆形的最小正方形的点进行碰撞,但是这样做很麻烦。

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()

I know that each circle graphics technically can use the points of the smallest possible square that would fir around the circle to do the collision 我知道每个圆形图形在技术上都可以使用可能会绕圆形旋转的最小正方形的点进行碰撞

I'm playing with an alternate idea -- we could consider a circle around the rectangle instead of a square around the circle. 我正在考虑一种替代方法-我们可以考虑在矩形周围使用一个圆圈,而不是在该圆圈周围使用一个正方形。 The issue for me is that we not only need to detect collision, but come out with a sense of which way to move away from the other object. 对我来说,问题在于我们不仅需要检测碰撞,而且还能以某种方式远离其他物体。 It's not just True and False but rather a (dx, dy) type of result. 这不只是TrueFalse ,而是一个(dx, dy)类型的结果。

Obviously, a circle around the rectangle is too crude, but suppose it were lots of smaller circles making up the rectangle and we measure circle center to center distance to detect a hit: 显然,矩形周围的一个圆太粗糙了,但是假设它是由许多较小的圆组成的矩形,我们测量圆的中心到中心的距离以检测到命中:

在此处输入图片说明

A hit on just a central (green) rectangle circle means reverse the vertical direction of the big circle. 仅击中中心(绿色)矩形圆圈就意味着反转大圆圈的垂直方向。 A hit on just the end (red) circle means reverse the horizontal direction of the big circle. 在最后一个圆(红色)上命中表示反转大圆的水平方向。 And we can detect both kinds of hits and reverse the big circle completely. 而且我们可以检测到两种命中并完全扭转大圆圈。

Here's my rework of your code with the above in mind -- I also fixed your multiple clicking issue and made lots of style changes: 考虑到以上几点,这是我对代码的重做-我还解决了多次单击的问题,并进行了许多样式更改:

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()

Not perfect, but something to play around with, possibly plugging in a better intersects() implementation. 不是很完美,但是有一些需要解决的问题,可能会插入更好的intersects()实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM