2011-01-06 16 views
7

मैं एक ऐसा गेम बना रहा हूं जिसमें गेंद के आसपास के अंदर उछालती है। बड़ा सर्कल हिलता नहीं है।पायथन और पायगम: सर्कल के इंटीरियर के साथ बॉल टकराव

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) 

यह पीटर Collingridge over here द्वारा अद्भुत ट्यूटोरियल पर आधारित है:

यहाँ कोड है कि मैं वर्तमान में इन टक्करों के लिए उपयोग कर रहा हूँ है।

सर्कल और बॉल ऑब्जेक्ट्स दोनों कक्षाएं हैं (x, y), त्रिज्या, कोण और गति के साथ।

मैं इस विधि के साथ दो समस्याओं, हालांकि हो रहा है:

  1. गेंद से बाउंस (मैं क्या संदेह है) ने अपने "लंगर बिंदु" है, जो वृत्त के ऊपरी दाएं कोने में हो रहा है है।
  2. सर्कल के नीचे 5% के साथ टकराने के दौरान, स्क्रीन के बाहर पर्याप्त उच्च उछाल और इसलिए "सिंक" में विफल रहता है। मुझे लगता है कि ऐसा इसलिए है क्योंकि यह उछाल गेंद को अपने (गलत तरीके से रखा गया) "एंकर पॉइंट" से ऊपर ले जाने के लिए पर्याप्त नहीं है?

संभवतः यहां पर संभावित समाधानों को देखते हुए, विशेष रूप से "फास्ट सर्कल टकराव का पता लगाने" [लिंक स्पैम लिंक सीमा के कारण हटा दिया गया], जो जावा में एक ही विधि का उपयोग कर रहा है, ये सभी बाहरी टकरावों से निपटते हैं, जबकि मैं एक सर्कल के इंटीरियर के चारों ओर एक गेंद उछाल देख रहा हूँ।

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 

अग्रिम धन्यवाद, नाथन

उत्तर

12

मुझे खुशी है कि आपको मेरा ट्यूटोरियल पसंद आया। मुझे आपकी विविधता पसंद है, यह वास्तव में सरल होना चाहिए।

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

क्योंकि बड़ा गेंद आकार, छोटे इसके केंद्र और चक्र के केंद्र के बीच की दूरी हो सकता है:

सबसे पहले, मैं तुम्हें करने के लिए टक्कर के लिए परीक्षण को बदलने की जरूरत है। यह गेंदों को सही जगह (सर्कल के अंदर) पर उछाल देना चाहिए।

तब मुझे लगता है कि आपको केवल एक्स और वाई के संकेतों को स्वैप करने की आवश्यकता है और सब कुछ काम करना चाहिए।

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

सही दूरी के अनुसार गेंद को स्थानांतरित करने के लिए आप ओवरलैप गणना कर सकते हैं:

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 

गुड लक

+0

एक्स अक्ष को कोण के कोसाइन और साइन द्वारा वाई अक्ष द्वारा परिभाषित नहीं किया जाएगा? या मैंने गलत सीखा? : एक्स – JCM

+0

मुझे लगता है कि आप सही हैं कि चीजों को परिभाषित करने का यह मानक तरीका है, लेकिन जब तक आप लगातार हैं, यह वास्तव में कोई फर्क नहीं पड़ता है। स्पष्ट रूप से यदि आप 90 डिग्री से सब कुछ घुमाते हैं, तो इससे प्रभावित नहीं होना चाहिए कि चीजें कैसे उछालती हैं (गुरुत्वाकर्षण मानते हुए भी बदलते हैं)। –

+0

@ पीटरकॉलिंग्रिज, आपके लेख * अद्भुत * हैं!सुरुचिपूर्ण समाधान, पायथन शैली, बधाई .. और धन्यवाद! – MestreLion

2

अधिकांश ग्राफिक्स संकुल ऊपरी-बाएँ कोड ड्राइंग के लिए शुरुआत के रूप में उपयोग करें:

यहाँ भी वर्ग()) गेंद की परिभाषा और सर्किल (है। आप संभवतः निर्देशांक के 2 सेट चाहते हैं, आप किसी के साथ टकराते हैं/स्थानांतरित होते हैं और एक ड्राइंग (एक्स-त्रिज्या, वाई-त्रिज्या) के लिए होता है।

इसके अलावा, इसके बारे में बहुत कुछ सोचा बिना, चौराहे की जांच distance + ball.size >= circle.size होनी चाहिए? अगर मैं सही ढंग से सेटअप को समझता हूं तो गेंदें केंद्र से दूरी और इसके त्रिज्या सर्कल के त्रिज्या से कम होनी चाहिए।

12

अपने प्रश्न का उत्तर दिए बिना, मैं आपकी कार्यान्वयन रणनीति पर टिप्पणी करना चाहता हूं और एक नए दृष्टिकोण की सिफारिश करना चाहता हूं। आप ध्रुवीय समन्वय रूप में गेंद की वेग का प्रतिनिधित्व करते हैं, ball.angle और ball.speed के रूप में।

मुझे लगता है कि यह आपके लिए आम तौर पर असुविधाजनक होगा। उदाहरण के लिए, आपके टकराव कोड में आप वेक्टर (dx, dy) को कोण में बदलने के लिए atan2 पर कॉल करना समाप्त कर देते हैं, और उसके बाद कोण को फिर से वेक्टर में फिर से चालू करने के लिए sin और cos पर कॉल करें। (साथ ही, क्या आप कभी भी अपने कोड को तीन आयामों में सामान्य करने की कोशिश कर सकते हैं, आप अपने आप को दर्द की दुनिया में पाएंगे।) इसलिए, जब तक आपके पास विशेष आवश्यकताएं नहीं होतीं जो ध्रुवीय निर्देशांक की आवश्यकता होती है, तो मैं अनुशंसा करता हूं कि आप जो कुछ भी करते हैं, उसका प्रतिनिधित्व करें कार्टेशियन में गेंद की गति वेक्टर के रूप में निर्देशित करती है (vx, vy)।

मैं आपके भौतिकी दृष्टिकोण को स्थिर से बदलना भी अनुशंसा करता हूं ("ऑब्जेक्ट ए वर्तमान में ऑब्जेक्ट बी के साथ टकरा रहा है?") गतिशील एक (" ऑब्जेक्ट बी के साथ अपने अगले आंदोलन चरण के दौरान एक टक्कर ऑब्जेक्ट करेगा? ")। एक स्थिर भौतिकी प्रणाली में आप अक्सर एक आंदोलन चरण के अंत में एक दूसरे को छेड़छाड़ करने वाली वस्तुओं के साथ समाप्त होते हैं, और फिर आप उन्हें फिर से अलग करने के लिए प्राप्त करने के लिए सबसे अच्छा तरीका है, जो सही पाने के लिए कठिन है यह पता लगाने की आप इन दोनों करते हैं, यह किसी भी त्रिकोणमिति के बिना गेंद बाउंस करने के लिए सरल है।

चरण 1 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.

चरण 2. एक समय खंड जिसमें गेंद वी = (VX, vy) द्वारा पी = (px, py) और चाल पर शुरू होता है पर विचार करें। क्या यह सर्कल से छेड़छाड़ करता है? इसके लिए आप standard line segment/circle test का उपयोग कर सकते हैं सिवाय इसके कि परीक्षण की भावना उलट दी गई है।

चरण 3. टकराव का बिंदु सी = (सीएक्स, साइ) खोजें। गेंद सर्कल से उसी तरह उछालती है क्योंकि यह इस बिंदु पर सर्कल में टी टेंगेंट को उछाल देगी। उत्पत्ति पर केंद्रित एक सर्कल के लिए, टेंगेंट वेक्टर बस (-सी, सीएक्स) है और मुझे यकीन है कि आप इसे अन्य मंडलियों के लिए गणना करने के तरीके के बारे में सुनिश्चित कर सकते हैं।

Figure described above

कैसे गेंद घर्षण और बहाली के गुणांक के आधार पर की नई पथ की गणना करने के लिए See this answer

चरण 4. यह न भूलें कि गेंद को अभी भी नए वेक्टर डब्ल्यू के साथ स्थानांतरित करने के लिए कुछ दूरी हो सकती है। यदि समय कदम काफी बड़ा है या वेग काफी अधिक है तो यह उसी समय सेगमेंट के दौरान फिर से टकरा सकता है।

+0

हालांकि यह नहीं था मैं के लिए, धन्यवाद ढेर क्या देख रहा था! मैं इसमें देख रहा हूँ – nchpmn

संबंधित मुद्दे