2011-01-06 86 views
7

Tôi đang tạo trò chơi trong đó các quả bóng bị trả lại xung quanh bên trong vòng tròn của vòng tròn lớn hơn nhiều. Vòng tròn lớn hơn không di chuyển.Python & Pygame: Va chạm với nội thất của vòng tròn

Dưới đây là đoạn code mà tôi hiện đang sử dụng cho các va chạm:

def collideCircle(circle, ball): 
    """Check for collision between a ball and a circle""" 
    dx = circle.x - ball.x 
    dy = circle.y - ball.y 

    distance = math.hypot(dx, dy) 

    if distance >= circle.size + ball.size: 
     # We don't need to change anything about the circle, just the ball 
     tangent = math.atan2(dy, dx) 
     ball.angle = 2 * tangent - ball.angle 
     ball.speed *= elasticity + 0.251 

     angle = 0.5 * math.pi + tangent 
     ball.x -= math.sin(angle) 
     ball.y += math.cos(angle) 

Nó được dựa trên những hướng dẫn tuyệt vời của Peter Collingridge over here.

Đối tượng hình tròn và bóng là cả hai lớp, với (x, y), bán kính, góc và tốc độ.

Tôi gặp hai vấn đề với phương pháp này, tuy nhiên:

  1. bóng bị trả từ (những gì tôi nghi ngờ) là "điểm neo" của nó, mà có vẻ là ở góc trên cùng bên phải của vòng tròn.
  2. Khi va chạm với đáy 5% của vòng tròn, không trả lại đủ cao và do đó "chìm" ra khỏi màn hình. Tôi đoán rằng điều này là bởi vì các thư bị trả lại là không đủ cao để di chuyển quả bóng trên của nó (không chính xác đặt) "điểm neo"?

Đã xem xét các giải pháp khả thi đã có ở đây, đáng chú ý là "Phát hiện va chạm vòng tròn nhanh", mặc dù trong Java đang sử dụng cùng một phương pháp, tất cả đều đối phó với các va chạm bên ngoài, trong khi tôi đang nhìn vào một quả bóng xung quanh bên trong một vòng tròn.

Đây cũng là định nghĩa lớp của Ball() và Circle():

class Ball(): 
    def __init__(self, (x,y), size): 
     """Setting up the new instance""" 
     self.x = x 
     self.y = y 
     self.size = size 
     self.colour = (0,128,255) 
     self.thickness = 0 
     self.speed = 0.01 
     self.angle = math.pi/2 

    def display(self): 
     """Draw the ball""" 
     pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness) 

    def move(self): 
     """Move the ball according to angle and speed""" 
     self.x += math.sin(self.angle) * self.speed 
     self.y -= math.cos(self.angle) * self.speed 
     (self.angle, self.speed) = addVectors((self.angle, self.speed), gravity) 
     self.speed *= drag 

class Circle(): 
    def __init__(self, (x,y), size): 
     """Set up the new instance of the Circle class""" 
     self.x = x 
     self.y = y 
     self.size = size 
     self.colour = (236, 236, 236) 
     self.thickness = 0 
     self.angle = 0 # Needed for collision... 
     self.speed = 0 # detection against balls 

    def display(self): 
     """Draw the circle""" 
     pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness 

Cảm ơn trước, Nathan

Trả lời

12

Tôi rất vui vì bạn thích hướng dẫn của tôi. Tôi thích biến thể của bạn, nó thực sự nên đơn giản hơn.

Trước tiên, tôi nghĩ rằng bạn cần thay đổi thử nghiệm va chạm để:

if distance >= circle.size - ball.size: 

Bởi vì càng lớn thì kích thước bóng, nhỏ hơn khoảng cách giữa trung tâm và trung tâm của vòng tròn có thể được. Điều này sẽ làm cho quả bóng nảy vào đúng nơi (bên trong vòng tròn).

Sau đó, tôi nghĩ bạn chỉ cần trao đổi các dấu hiệu cho x và y và mọi thứ sẽ hoạt động.

ball.x += math.sin(angle) 
ball.y -= math.cos(angle) 

Để di chuyển bóng bằng khoảng cách chính xác bạn có thể tính toán sự chồng chéo:

overlap = math.hypot(dx, dy) - (circle.size - ball.size) 

if overlap >= 0: 
    tangent = math.atan2(dy, dx) 
    ball.angle = 2 * tangent - ball.angle 
    ball.speed *= elasticity 

    angle = 0.5 * math.pi + tangent 
    ball.x += math.sin(angle)*overlap 
    ball.y -= math.cos(angle)*overlap 

Chúc may mắn

+0

Trục X sẽ không được xác định bởi cosin của góc và trục Y bằng sin? Hay tôi đã học sai? : X – JCM

+0

Tôi nghĩ rằng bạn đúng rằng đó là cách tiêu chuẩn để xác định mọi thứ, nhưng miễn là bạn nhất quán nó không thực sự tạo ra bất kỳ sự khác biệt nào. Rõ ràng nếu bạn xoay mọi thứ bằng 90 độ, điều đó sẽ không ảnh hưởng đến cách mọi thứ bị trả lại (giả sử trọng lực cũng thay đổi). –

+0

@PeterCollingridge, bài viết của bạn là * tuyệt vời *!Giải pháp thanh lịch, phong cách pythonic, congrats .. và cảm ơn! – MestreLion

2

Hầu hết các gói đồ họa sử dụng trên bên trái như khởi đầu cho việc vẽ mã. Bạn rất có thể muốn 2 bộ tọa độ, một trong những bạn va chạm/di chuyển/vv và của một người để vẽ (x-bán kính, y-bán kính).

Ngoài ra, không suy nghĩ quá nhiều, nên kiểm tra giao lộ là distance + ball.size >= circle.size? Khoảng cách quả bóng từ trung tâm cộng với bán kính của nó phải nhỏ hơn bán kính của vòng tròn, nếu tôi hiểu thiết lập chính xác.

12

Nếu không trả lời câu hỏi của bạn, tôi muốn nhận xét về chiến lược triển khai của bạn và đề xuất phương pháp tiếp cận mới. Bạn đại diện cho vận tốc của quả bóng theo dạng tọa độ cực, như ball.angleball.speed.

Tôi nghĩ rằng điều này sẽ không thuận tiện cho bạn. Ví dụ, trong mã va chạm của bạn, bạn kết thúc gọi atan2 để biến véc tơ (dx, dy) thành một góc, và sau đó bạn gọi sincos để biến góc trở lại thành véc tơ một lần nữa. Vì vậy, trừ khi bạn có yêu cầu cụ thể đòi hỏi tọa độ cực, tôi khuyên bạn nên làm những gì mà mọi người khác làm, cụ thể là đại diện vận tốc của quả bóng trong tọa độ Descartes là vectơ (vx, vy).

Tôi cũng khuyên bạn nên thay đổi cách tiếp cận vật lý từ một static một ("là đối tượng A hiện đang va chạm với đối tượng B?") cho một động một (" sẽ đối tượng A va chạm với đối tượng B trong bước chuyển động kế tiếp của nó? "). Trong hệ thống vật lý tĩnh, bạn thường kết thúc với các đối tượng giao nhau ở cuối bước di chuyển, và sau đó bạn phải tìm ra cách tốt nhất để có được chúng để tách một lần nữa, đó là khó khăn để có được quyền.

Nếu bạn làm cả hai, nó là đơn giản để trả bóng mà không cần bất kỳ lượng giác.

Bước 1 Chuyển đổi vòng tròn/vòng tròn va chạm vào va chạm điểm/vòng tròn sử dụng Minkowski addition:

Original problem at left shows small circle moving inside a large circle. Transformed problem at right shows point moving in circle whose radius is the difference between the radii of the circles in the original problem.

Bước 2. Xem xét phân đoạn thời gian trong đó bóng bắt đầu tại p = (px, py) và di chuyển theo v = (vx, vy). Nó có giao nhau với vòng tròn không? Bạn có thể sử dụng standard line segment/circle test cho điều này ngoại trừ ý nghĩa của thử nghiệm được đảo ngược.

Bước 3. Tìm điểm va chạm c = (cx, cy). Quả bóng nảy ra khỏi vòng tròn theo cách tương tự như nó sẽ bật ra khỏi dòng t ốp với vòng tròn tại thời điểm này. Đối với một vòng tròn tập trung ở gốc, vector tiếp tuyến chỉ là (−cy, cx) và tôi chắc chắn bạn có thể tìm ra cách tính toán vòng tròn đó cho các vòng kết nối khác.

Figure described above

See this answer cho làm thế nào để tính toán con đường mới của bóng dựa trên hệ số ma sát và bồi thường.

Bước 4. Đừng quên rằng quả bóng vẫn có thể có khoảng cách để di chuyển dọc theo vectơ mới w. Nếu bước thời gian đủ lớn hoặc vận tốc đủ cao nó có thể va chạm lại trong cùng một đoạn thời gian.

+0

Mặc dù đây không phải là những gì tôi đang tìm kiếm, nhờ đống! Tôi đang nhìn vào nó. – nchpmn

Các vấn đề liên quan