2 डी आइसोमेट्रिक: स्क्रीन से टाइल निर्देशांक


9

मैं एक आइसोमेट्रिक 2 डी गेम लिख रहा हूं और मुझे यह पता लगाने में कठिनाई हो रही है कि कर्सर किस टाइल पर है। यहाँ एक ड्राइंग है:

जहाँ xs और y स्क्रीन निर्देशांक (पिक्सेल) हैं, xt और yt टाइल निर्देशांक हैं, क्रमशः W और H टाइल की चौड़ाई और पिक्सेल में टाइल की ऊँचाई हैं। निर्देशांक के लिए मेरा अंकन (y, x) है जो भ्रमित हो सकता है, इसके बारे में खेद है।

सबसे अच्छा मैं यह पता लगा सकता है कि यह है:

int xtemp = xs / (W / 2);
int ytemp = ys / (H / 2);
int xt = (xs - ys) / 2;
int yt = ytemp + xt;

यह लगभग सही प्रतीत होता है, लेकिन मुझे एक बहुत ही अभेद्य परिणाम दे रहा है, जिससे कुछ टाइलों का चयन करना मुश्किल हो जाता है, या कभी-कभी यह एक टाइल का चयन करता है, जिस पर मैं क्लिक करने की कोशिश कर रहा हूं। मुझे समझ नहीं आ रहा है कि मैं क्यों चाहूँगा और अगर कोई मुझे इसके पीछे के तर्क को समझने में मदद कर सकता है।

धन्यवाद!

जवाबों:


2

सटीक उपाय के लिए, हम निम्नलिखित पर विचार कर सकते हैं:

आइए पहले आइ और जे वैक्टर (isometricMap [i, j] के रूप में) या स्क्रीन पर yt और xt के रूप में स्क्रीन के स्पेस, x और y द्वारा निर्धारित स्क्रीन स्पेस के अनुसार, निर्देशांक को बदलने के तरीके पर विचार करें। मान लें कि आपकी स्क्रीन स्पेस सरलता के लिए आइसोमेट्रिक स्पेस के साथ मूल में संरेखित है।

ट्रांसफॉर्म करने का एक तरीका यह है कि आप पहले एक रोटेशन करें, फिर y या x- एक्सिस को स्केल करें। अपने yt और xt से मेल खाने के लिए आवश्यक मान प्राप्त करने के लिए मैं यहाँ मौके पर नहीं आ सकता। आप ऐसा करने के लिए एक मैट्रिक्स बना सकते हैं या नहीं और फिर रिवर्स मैट्रिक्स का उपयोग कर सकते हैं, लेकिन रिवर्स ऑपरेशन मूल रूप से आप क्या चाहते हैं।

मान को रिवर्स में स्केल करें और फिर मान प्राप्त करने के लिए पीछे की ओर घुमाएं और नीचे की ओर गोल करें।

मुझे लगता है कि इसके अन्य तरीके हैं, लेकिन अभी यह मेरे लिए सबसे उचित लगता है।


अरे। मैं इस पोस्ट को इतनी बार संशोधित कर रहा हूं और मुझे लगता है कि मैं अपनी बात को बड़े करीने से नहीं कह सकता क्योंकि मैं वैसे भी करूंगा। मुझे सोने की ज़रूरत है।
टोनी

1
धन्यवाद, मैट्रीस निश्चित रूप से यहां सबसे अच्छा समाधान है। मेरे पास अब लगभग कुछ काम है!
असिक

4

मुझे एक खेल के लिए यही समस्या थी जो मैं लिख रहा था। मैं कल्पना करता हूं कि यह समस्या अलग-अलग होगी कि आपने आइसोमेट्रिक सिस्टम को कैसे लागू किया, लेकिन मैं बताऊंगा कि मैंने समस्या को कैसे हल किया।

मैंने पहली बार अपने टाइल_ऑटो_स्क्रीन फंक्शन के साथ शुरुआत की। (मुझे लगता है कि आप पहली जगह में टाइल को सही स्थान पर कैसे रख रहे हैं।) इस फ़ंक्शन में स्क्रीन_x और स्क्रीन_y की गणना करने के लिए एक समीकरण है। मेरा ऐसा दिख रहा था (अजगर):

def map_to_screen(self, point):
    x = (SCREEN_WIDTH + (point.y - point.x) * TILE_WIDTH) / 2
    y = (SCREEN_HEIGHT + (point.y + point.x) * TILE_HEIGHT) / 2
    return (x, y)

मैंने उन दो समीकरणों को लिया और उन्हें रैखिक समीकरणों की प्रणाली में शामिल किया। आपके द्वारा चुने गए किसी भी तरीके में समीकरणों की इस प्रणाली को हल करें। (मैंने एक rref पद्धति का उपयोग किया। इसके अलावा, कुछ रेखांकन कैलकुलेटर इस समस्या को हल कर सकते हैं।)

अंतिम समीकरण इस तरह दिखे:

# constants for quick calculating (only process once)
DOUBLED_TILE_AREA = 2 * TILE_HEIGHT * TILE_WIDTH
S2M_CONST_X = -SCREEN_HEIGHT * TILE_WIDTH + SCREEN_WIDTH * TILE_HEIGHT
S2M_CONST_Y = -SCREEN_HEIGHT * TILE_WIDTH - SCREEN_WIDTH * TILE_HEIGHT

def screen_to_map(self, point):
    # the "+ TILE_HEIGHT/2" adjusts for the render offset since I
    # anchor my sprites from the center of the tile
    point = (point.x * TILE_HEIGHT, (point.y + TILE_HEIGHT/2) * TILE_WIDTH)
    x = (2 * (point.y - point.x) + self.S2M_CONST_X) / self.DOUBLED_TILE_AREA
    y = (2 * (point.x + point.y) + self.S2M_CONST_Y) / self.DOUBLED_TILE_AREA
    return (x, y)

जैसा कि आप देख सकते हैं, यह शुरुआती समीकरण की तरह सरल नहीं है। लेकिन यह मेरे द्वारा बनाए गए खेल के लिए अच्छी तरह से काम करता है। रैखिक बीजगणित के लिए अच्छाई का धन्यवाद!

अपडेट करें

विभिन्न ऑपरेटरों के साथ एक साधारण बिंदु वर्ग लिखने के बाद, मैंने इस उत्तर को सरल बनाया:

# constants for quickly calculating screen_to_iso
TILE_AREA = TILE_HEIGHT * TILE_WIDTH
S2I_CONST_X = -SCREEN_CENTER.y * TILE_WIDTH + SCREEN_CENTER.x * TILE_HEIGHT
S2I_CONST_Y = -SCREEN_CENTER.y * TILE_WIDTH - SCREEN_CENTER.x * TILE_HEIGHT

def screen_to_iso(p):
    ''' Converts a screen point (px) into a level point (tile) '''
    # the "y + TILE_HEIGHT/2" is because we anchor tiles by center, not bottom
    p = Point(p.x * TILE_HEIGHT, (p.y + TILE_HEIGHT/2) * TILE_WIDTH)
    return Point(int((p.y - p.x + S2I_CONST_X) / TILE_AREA),
                 int((p.y + p.x + S2I_CONST_Y) / TILE_AREA))

def iso_to_screen(p):
    ''' Converts a level point (tile) into a screen point (px) '''
    return SCREEN_CENTER + Point((p.y - p.x) * TILE_WIDTH / 2,
                                 (p.y + p.x) * TILE_HEIGHT / 2)

हां, दो रैखिक समीकरणों की एक प्रणाली को भी काम करना चाहिए। यह देखते हुए कि हमारे पास दो वैक्टर हैं जो समानांतर नहीं हैं, आपको yt और xt की यूनिट वैक्टर का उपयोग करके विमान पर कोई भी बिंदु प्राप्त करने में सक्षम होना चाहिए। हालांकि मुझे लगता है कि आपका कार्यान्वयन थोड़ा संकुचित है और मैं इसे मान्य करने के लिए परेशान करने वाला नहीं हूं।
टोनी

2

आप एक अच्छे समन्वय प्रणाली का उपयोग कर रहे हैं। यदि आप कंपित स्तंभों का उपयोग करते हैं तो चीजें बहुत पेचीदा हो जाती हैं।

इस समस्या के बारे में सोचने का एक तरीका यह है कि आपके पास (xt, yt) को (xs, ys) मोड़ने का एक कार्य है। मैं ठाणे के उत्तर का पालन करूंगा और इसे कॉल करूंगा map_to_screen

आप इस फ़ंक्शन का व्युत्क्रम चाहते हैं । हम इसे कॉल कर सकते हैं screen_to_map। फंक्शन व्युत्क्रम में ये गुण होते हैं:

map_to_screen(screen_to_map(xs, ys)) == (xs, ys)
screen_to_map(map_to_screen(xt, yt)) == (xt, yt)

उन दोनों को इकाई परीक्षण के लिए अच्छी चीजें हैं जब आपके पास दोनों फ़ंक्शन लिखे जाते हैं। आप उलटा कैसे लिखते हैं? सभी कार्यों में उलटा नहीं होता है, लेकिन इस मामले में:

  1. यदि आपने इसे एक अनुवाद के बाद एक रोटेशन के रूप में लिखा है, तो उलटा उलटा अनुवाद (नकारात्मक डीएक्स, डाई) है इसके बाद उलटा रोटेशन (नकारात्मक कोण) है।
  2. यदि आपने इसे एक मैट्रिक्स के रूप में गुणा किया है, तो व्युत्क्रम मैट्रिक्स का व्युत्क्रम गुणा है।
  3. यदि आपने इसे (xt, yt) के संदर्भ में बीजगणितीय समीकरणों को परिभाषित करने (xs, ys) के रूप में लिखा है, तो व्युत्क्रम उन (xt, yt) दिए गए (xs, ys) समीकरणों को हल करके पाया जाता है।

परीक्षण करना सुनिश्चित करें कि उलटा + मूल फ़ंक्शन आपके द्वारा शुरू किए गए उत्तर को वापस दे। यदि आप + TILE_HEIGHT/2रेंडर ऑफ़सेट निकालते हैं तो ठाणे के दोनों परीक्षण पास हो जाते हैं । जब मैंने बीजगणित हल किया, तो मैं आया:

x = (2*xs - SCREEN_WIDTH) / TILE_WIDTH
y = (2*ys - SCREEN_HEIGHT) / TILE_HEIGHT
yt =  (y + x) / 2
xt =  (y - x) / 2

मेरा मानना ​​है कि ठाणे के समान ही है screen_to_map

फ़ंक्शन माउस निर्देशांक को फ़्लोट्स में बदल देगा; floorउन्हें पूर्णांक टाइल निर्देशांक में बदलने के लिए उपयोग करें।


1
धन्यवाद! मैंने एक परिवर्तन मैट्रिक्स का उपयोग करके समाप्त किया, ताकि उलटा लिखना तुच्छ हो, यानी यह सिर्फ मैट्रिक्स है। इन्वर्ट ()। इसके अलावा यह कोडिंग की एक अधिक घोषणात्मक शैली की ओर जाता है (Matrix.Translate () * Matrix.Scale () * Matrix.Rotate () समीकरणों के एक समूह के बजाय)। शायद यह थोड़ा धीमा है, लेकिन यह एक मुद्दा नहीं होना चाहिए।
असिक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.