【问题标题】:Circle objects register a collision, but they are not touching圆形对象记录了碰撞,但它们没有接触
【发布时间】:2017-02-08 04:30:40
【问题描述】:

我刚刚检查了here 以确保这个问题是允许的,而且似乎是这样,我开始了:

我目前正在制作一个 2D 物理引擎作为一个小项目。我有一个名为circle 的类,它具有半径、旋转、位置和速度等属性:

class circle():
    def __init__(self, radius = 10, r = 0.0, x = 0, y = 0, Vr = 0, Vx = 0, Vy = 0):

        self.radius = radius

        self.r = r
        self.x = x
        self.y = y

        self.Vr = Vr
        self.Vx = Vx
        self.Vy = Vy

该类有一个名为CheckCollisions()的方法,该方法检查其中心与另一个圆的中心之间的距离是否小于它们的半径之和:

def CheckCollisions(self):
    for c in circles:
        distance = math.sqrt((c.x - self.x)*(c.x - self.x) + (c.y - self.y)*(c.y - self.y))
        if distance < self.radius + c.radius:
            print('!')
        else:
            print('')

这个想法是,在检测到碰撞时,可以将力作为矢量施加到每个对象上,作为对碰撞的响应。

当我的代码运行时,我看到 shell 中不断出现感叹号,尽管圆圈没有碰撞。这是什么原因造成的?也许我计算的距离不正确?


完整代码:

import pygame, random, math
from pygame.locals import*

# set up pygame window
(width, height) = (1000, 800)
screen = pygame.display.set_mode((width,height))
pygame.display.set_caption('Impulse Physics v0.1 BETA')

pen = pygame.image.load('Pen.png').convert()
background = (0, 0, 0)

class circle():
    def __init__(self, radius = 10, r = 0.0, x = 0, y = 0, Vr = 0, Vx = 0, Vy = 0):

        self.radius = radius

        # position and rotation
        self.r = r
        self.x = x
        self.y = y

        # velocity
        self.Vr = Vr
        self.Vx = Vx
        self.Vy = Vy

    def CheckCollisions(self):
        for c in circles:
            # use pythagoras to find direct distance between centres
            distance = math.sqrt((c.x - self.x)*(c.x - self.x) + (c.y - self.y)*(c.y - self.y))
            if distance < self.radius + c.radius:
                print('!')
            else:
                print('')

    def Move(self):
        # apply slight "air resistance"
        self.Vx = self.Vx * 0.9999
        # gravity. REMEMBER y axis is inverted in pygame!
        self.Vy = self.Vy + 0.15

        # move object
        self.x = self.x + self.Vx
        self.y = self.y + self.Vy
        self.r = self.r + self.Vr

        self.CheckCollisions()

        # check if colliding with the sides of the window
        if self.y + self.radius > height:
            self.Vy = self.Vy * -0.98
            self.y = self.y + self.Vy

        if (self.x + self.radius > width) or (self.x - self.radius < 0):
            self.Vx = self.Vx * -0.98
            self.x = self.x + self.Vx

    def Render(self):
        penX = self.x
        penY = self.y
        penR = self.r
        screen.blit(pen, (penX, penY))

        # draw the radius of the circle
        for counter in range(self.radius):
            penX = self.x + (math.sin(penR) * counter)
            penY = self.y - (math.cos(penR) * counter)
            screen.blit(pen, (penX, penY))

        # draw the circumference of the circle
        for counter in range(self.radius * 20):
            penR = counter * (360 / self.radius * 20)
            penX = self.x + (math.sin(penR) * self.radius)
            penY = self.y + (math.cos(penR) * self.radius)
            screen.blit(pen, (penX, penY))

circles = []

#create objects here

c1 = circle(100, 0, 400, 400, 0.1, 4)
circles.append(c1)

c2 = circle(50, 0, 50, 50, 0.08, 10)
circles.append(c2)

c3 = circle(10, 0, 300, 200, 0.02, -3)
circles.append(c3)

running = True
while running:
    screen.fill(background)
    for obj in circles:
        obj.Move()
        obj.Render()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    pygame.display.flip()

pygame.quit()

【问题讨论】:

  • 它总是和自己发生碰撞。
  • sqrt 很贵。比较 distance_squaredself.radius**2 + c.radius**2
  • @PeterWood 所以,删除 sqrt 函数并使用平方值?
  • @AricFowler 你怎么看?
  • self.radius**2 + c.radius**2 是错误的。使用(self.radius + c.radius) ** 2

标签: python pygame game-physics


【解决方案1】:

简而言之:一个圆与自身相撞。原因很简单,circles 列表包含 [c1,c2,c3],因此会针对圈子本身进行检查。

现在对于c1,您检查是否存在碰撞,因此它会遍历circles,它检查的第一件事是它是否与自身发生碰撞(因为c1 是第一个列表中的元素)。显然它确实如此(您的测试看起来距离是否小于圆半径的总和,但距离为零)。如果没有一个圆圈发生碰撞,则会出现三个感叹号(每个圆圈一个)。

您可以通过先执行引用相等检查来解决此错误:

def CheckCollisions(self):
    for c in circles:
        if c is not self:
            distance = math.sqrt((c.x - self.x)*(c.x - self.x) + (c.y - self.y)*(c.y - self.y))
            #...

【讨论】:

  • 谢谢!我认为,自我碰撞在未来将很有用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多