गैर-पूर्णांक गति मान - ऐसा करने के लिए एक क्लीनर तरीका है?


21

अक्सर मैं एक पिक्सेल-आधारित गेम में अपने चरित्र को आगे बढ़ाने के लिए गति मान जैसे 2.5 का उपयोग करना चाहता हूं। टकराव का पता लगाना आम तौर पर अधिक कठिन होगा यदि मैं ऐसा करता हूं, हालांकि। इसलिए मैं कुछ इस तरह से कर रहा हूं:

moveX(2);
if (ticks % 2 == 0) { // or if (moveTime % 2 == 0)
    moveX(1);
}

मुझे हर बार अंदर लिखना पड़ता है कि मुझे क्या लिखना है, क्या चरित्र को गैर-पूर्णांक गति मानों के साथ स्थानांतरित करने का एक क्लीनर तरीका है या क्या मैं हमेशा के लिए ऐसा करना बंद कर दूंगा?


11
क्या आपने अपनी पूर्णांक इकाई को छोटा बनाने का विचार किया है (उदाहरण के लिए एक प्रदर्शन इकाई का १ / १० वां भाग) तो २.५ का अनुवाद २५ है, और आप इसे अभी भी सभी जाँचों के लिए पूर्णांक के रूप में मान सकते हैं और प्रत्येक फ्रेम का लगातार इलाज कर सकते हैं।
DMGregory

6
आप Bresenham लाइन एल्गोरिथ्म को अपनाने पर विचार कर सकते हैं जिसे केवल पूर्णांक का उपयोग करके लागू किया जा सकता है।
n0rd

1
यह आमतौर पर पुराने 8bit कंसोल पर किया जाता है। उदाहरणों के लिए इस तरह के लेख देखें कि कैसे तय बिंदु विधियों के साथ सबपिक्सल
लुकास

जवाबों:


13

Bresenham

पुराने समय में, जब लोग रेखाओं और वृत्तों को खींचने के लिए अपने स्वयं के मूल वीडियो रूटीन लिख रहे थे, तब उसके लिए ब्रेसेनहैम लाइन एल्गोरिथ्म का उपयोग करना अनसुना नहीं था।

ब्रेसेनहैम इस समस्या को हल करता है: आप स्क्रीन पर एक रेखा खींचना चाहते हैं जो dxक्षैतिज दिशा में पिक्सल ले जाती है जबकि एक ही समय dyमें ऊर्ध्वाधर दिशा में पिक्सेल फैलाते हैं। लाइनों के लिए एक अंतर्निहित "फ्लोटी" चरित्र है; यहां तक ​​कि अगर आपके पास पूर्णांक पिक्सेल हैं, तो आप तर्कसंगत झुकाव के साथ समाप्त होते हैं।

एल्गोरिथ्म को हालांकि तेज होना चाहिए, जिसका अर्थ है कि यह पूर्णांक अंकगणित का उपयोग कर सकता है; और यह भी बिना किसी गुणा या भाग के, केवल जोड़ और घटाव के बिना दूर हो जाता है।

आप अपने मामले के लिए इसे अनुकूलित कर सकते हैं:

  • आपकी "x दिशा" (ब्रेसेनहैम एल्गोरिथ्म के संदर्भ में) आपकी घड़ी है।
  • आपकी "y दिशा" वह मूल्य है जिसे आप बढ़ाना चाहते हैं (यानी, आपके चरित्र की स्थिति - सावधान, यह वास्तव में आपके प्रेत का "y" नहीं है या स्क्रीन पर जो भी हो, अधिक अमूर्त मूल्य)

"x / y" यहां स्क्रीन पर स्थान नहीं है, लेकिन समय में आपके आयामों में से एक है। जाहिर है, अगर आपका स्प्राइट स्क्रीन के पार एक अनियंत्रित दिशा में चल रहा है, तो आपके पास कई ब्रेसेनहैम अलग से चलेंगे, 2 डी के लिए, 3 डी के लिए 3।

उदाहरण

मान लीजिए कि आप अपने चरित्र को 0 से 25 तक एक साधारण आंदोलन में अपने एक अक्ष के साथ स्थानांतरित करना चाहते हैं। जैसा कि यह गति 2.5 के साथ आगे बढ़ रहा है, यह 10 फ्रेम में वहां उत्पन्न होगा।

यह (0,0) से (10,25) तक "रेखा खींचना" के समान है। ब्रेसेनहैम की लाइन एल्गोरिटम को पकड़ो और इसे चलने दो। यदि आप इसे सही करते हैं (और जब आप इसका अध्ययन करते हैं, तो यह बहुत जल्दी स्पष्ट हो जाएगा कि आप इसे कैसे सही करते हैं), तो यह आपके लिए (0,0), (1,2), (2) के लिए 11 "अंक" उत्पन्न करेगा। 5), (3,7), (4,10) ... (10,25)।

अनुकूलन पर संकेत

यदि आप उस एल्गोरिथ्म को गूगल करते हैं और कुछ कोड पाते हैं (विकिपीडिया पर एक बहुत बड़ी संधि है), तो कुछ चीजें हैं जिन्हें आपको देखने की आवश्यकता है:

  • यह स्पष्ट रूप से dxऔर सभी प्रकार के लिए काम करता है dy। आप एक विशिष्ट मामले में रुचि रखते हैं (हालांकि, आपके पास कभी नहीं होगा dx=0)।
  • हमेशा की तरह कार्यान्वयन, स्क्रीन पर चतुर्थ भाग में कई अलग अलग मामलों होगा इस पर निर्भर करते dxहैं और dyसकारात्मक, नकारात्मक रहे हैं, और यह भी कि क्या abs(dx)>abs(dy)है या नहीं। आप निश्चित रूप से यहां जो भी आपकी आवश्यकता है उसे उठाएं। आपको विशेष रूप से यह सुनिश्चित करना होगा कि जो दिशा 1हर टिक से बढ़ी है वह हमेशा आपकी "घड़ी" दिशा है।

यदि आप इन सरलीकरणों को लागू करते हैं, तो परिणाम वास्तव में बहुत सरल होगा, और किसी भी वास्तविक से पूरी तरह छुटकारा पा लेंगे।


1
यह स्वीकृत उत्तर होना चाहिए। 80 के दशक में C64 पर प्रोग्राम्ड गेम्स और 90 के दशक में पीसी पर फ्रैक्चर होने के बाद, मैं अभी भी फ्लोटिंग पॉइंट का उपयोग करने से कतराता हूं जहां भी मैं इससे बच सकता हूं। या निश्चित रूप से, आज के प्रोसेसर में एफपीयू सर्वव्यापी के साथ, प्रदर्शन तर्क ज्यादातर लूट है, लेकिन फ़्लोटिंग अंक अंकगणित को अभी भी बहुत अधिक ट्रांजिस्टर की आवश्यकता है, अधिक शक्ति ड्राइंग, और कई प्रोसेसर उपयोग में नहीं होने पर अपने FPUs को पूरी तरह से बंद कर देंगे। तो फ्लोटिंग पॉइंट से बचने से आपके मोबाइल उपयोगकर्ता आपको इतनी जल्दी अपनी बैटरी खाली न करने के लिए धन्यवाद देंगे।
गुंटराम ब्लोह

@GuntramBlohm फिक्स्ड प्वाइंट का उपयोग करते समय स्वीकृत उत्तर पूरी तरह से ठीक काम करता है, हालांकि मुझे लगता है कि यह करने का एक अच्छा तरीका है। आप निश्चित बिंदु संख्याओं के बारे में कैसा महसूस करते हैं?
leetNightshade

यह पता चलने के बाद स्वीकार किए गए उत्तर में बदल गया कि उन्होंने 8-बिट और 16-बिट दिनों में यह कैसे किया।
संचयकर्ता

26

वास्तव में आप जो चाहते हैं, उसे करने का एक शानदार तरीका है।

एक floatवेग के अलावा, आपको एक दूसरे floatचर की आवश्यकता होगी जिसमें वास्तविक वेग और गोल वेग के बीच अंतर होगा । इस अंतर को तब वेग के साथ जोड़ दिया जाता है।

#include <iostream>
#include <cmath>

int main()
{
    int pos = 10; 
    float vel = 0.3, vel_lag = 0;

    for (int i = 0; i < 20; i++)   
    {
        float real_vel = vel + vel_lag;
        int int_vel = std::lround(real_vel);
        vel_lag = real_vel - int_vel;

        std::cout << pos << ' ';
        pos += int_vel;
    }
}

आउटपुट:

10 10 11 11 11 12 12 12 12 13 13 14 14 14 15 15 15 15 16


5
आप वेग और स्थिति के लिए फ्लोट (या फ़िक्सपॉइंट) का उपयोग करके इस समाधान को क्यों पसंद करते हैं और केवल अंत में पूरे पूर्णांकों को स्थिति को गोल कर रहे हैं?
कोडइन्चोस

@CodesInChaos मैं उस एक पर अपने समाधान को पसंद नहीं करता। जब मैं यह जवाब लिख रहा था तो मुझे इसके बारे में पता नहीं था।
होलीब्लैकैट

16

टक्कर और रेंडरिंग के लिए मूवमेंट और पूर्णांक मानों के लिए फ्लोटिंग वैल्यू का उपयोग करें।

यहाँ एक उदाहरण है:

class Character {
    float position;
public:
    void move(float delta) {
        this->position += delta;
    }
    int getPosition() const {
        return lround(this->position);
    }
};

जब आप चलते हैं तो आप उपयोग करते हैं move()जो भिन्नात्मक पदों को जमा करता है। लेकिन टकराव और प्रतिपादन getPosition()फ़ंक्शन का उपयोग करके अभिन्न पदों से निपट सकते हैं ।


ध्यान दें कि नेटवर्क गेम के मामले में, विश्व सिमुलेशन के लिए फ्लोटिंग पॉइंट प्रकारों का उपयोग करना मुश्किल हो सकता है। उदाहरण देखें gafferongames.com/networking-for-game-programmers/…
लियोरी

यदि आप एक निश्चित बिंदु वर्ग है जो फ्लोट के लिए ड्रॉप-इन प्रतिस्थापन की तरह काम करता है, तो क्या यह ज्यादातर उन मुद्दों को हल नहीं करता है?
leetNightshade

@leetNightshade: कार्यान्वयन पर निर्भर करता है।
लियोरी

1
मैं कहूंगा कि समस्या व्यवहार में मौजूद नहीं है, क्या आधुनिक नेटवर्क वाले गेम चलाने में सक्षम हार्डवेयर में IEEE 754 फ़्लोट्स नहीं हैं ???
सोपेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.