2017-02-07 20 views
2

Я только что проверил here, чтобы убедиться, что этот вопрос был разрешен, и кажется, что это так вот я иду:объектов Circle регистр столкновения, но они не касаются

Я в настоящее время делаю 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('') 

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

Когда мой код работает, я вижу постоянные восклицательные знаки, появляющиеся в оболочке, несмотря на то, что круги не сталкиваются. Чем это вызвано? Возможно, что-то в моем расчете расстояния неверно?


Полный код:

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

Он всегда сталкивается с самими собой. –

+0

'sqrt' стоит дорого. Сравните 'distance_squared' с' self.radius ** 2 + c.radius ** 2 –

+0

@PeterWood Итак, удалите функцию sqrt и используйте квадратные значения? –

ответ

5

Короче говоря: круг сталкивается с самим собой. Причина в том, что список 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)) 
      #...
+1

спасибо! Я думаю, что самосознание будет полезно запомнить в будущем. –