भूत फिर से खेलना - भंडारण और समय


11

मैं एक कार रेस गेम पर काम कर रहा हूं और पिछले दौड़ को फिर से खेलने के लिए एक भूत प्रेत को लागू किया है। मैं एक भौतिकी इंजन का उपयोग करता हूं और बहुत पढ़ने के बाद मैं इस निष्कर्ष पर पहुंचा हूं कि रीप्ले के लिए भूत डेटा को संग्रहीत करने का सबसे अच्छा तरीका कार की स्थिति और रोटेशन को दिए गए समय बिंदुओं पर रिकॉर्ड करना होगा, जैसा कि यहां वर्णित उदाहरण के लिए: https: // gamedev। stackexchange.com/a/8380/26261

लेकिन रीप्ले के दौरान उन समय-बिंदुओं को खोजने का एक अच्छा तरीका क्या होगा? एक उदाहरण इस डेटा के साथ एक रिकॉर्ड होगा:

time: +3.19932 (seconds since race start)
position:  180,40 (position at that time)
rotation: 30.4 (rotation at that time)

लेकिन मुझे इसके साथ कई समस्याएं हैं:

  1. जब मैं पुनरावृत्ति करता हूं, तो यह संभावना नहीं है कि मैं 3.19932 पर फिर से सटीक समय-बिंदु पर पहुंचता हूं - अधिक संभावना है, मेरे पास 3.1 के आसपास का समय-बिंदु होगा और निकटतम मिलान रिकॉर्ड ढूंढना होगा। प्रक्षेप करते समय, ऊपर और नीचे भी निकटतम मिलान। यह बहुत अक्षम और समय लगता है?

  2. किस सूची संरचना में मैं बाद के रिप्ले के लिए इन रिकॉर्ड्स को स्टोर कर सकता था? एक सरणी? क्या इसका मतलब यह नहीं है कि एक निश्चित समय से मेल खाने वाले रिकॉर्ड के लिए खोज का समय दौड़ से अधिक लंबा होगा?

  3. टाइमपॉइंट के लिए मुझे किस आवृत्ति का उपयोग करना चाहिए? प्रत्येक फ्रेम का अनुमान होता है-मैं अनुमान लगाता हूं, बल्कि मुझे हर nth फ्रेम को बचाना चाहिए और बीच-बीच में रोकना चाहिए, जिससे स्टोरेज प्रश्न 2 हो जाते हैं। और भी मुश्किल।

तो क्या यह विचार भी सही दृष्टिकोण है? यदि हाँ, तो मैं कुशलता से डेटा को कैसे स्टोर और पुनर्प्राप्त कर सकता हूं? कृपया ध्यान दें कि मैं आमतौर पर उपरोक्त डेटा संरचना का उपयोग करके जाना चाहता हूं, न कि निर्धारक गेमस्टेट्स और रिकॉर्डिंग उपयोगकर्ता इनपुट आदि।

किसी भी मदद के लिए धन्यवाद!

संपादित करें: मुझे एहसास है कि मुझे अपने द्वारा उपयोग किए जाने वाले वातावरण का वर्णन करना चाहिए: iPhone के लिए Cocos2D। एक विधि है update:(ccTime)delta। आदर्श रूप से, इस विधि को प्रत्येक 1/60 सेकंड कहा जाएगा, लेकिन इसकी कोई गारंटी नहीं है - deltaक्या अंतिम युग्मक के बाद से वास्तविक समय बीत चुका है और 1/60 से बहुत अधिक या कम हो सकता है। यह इस पद्धति में है जहां मैं वर्तमान गेमस्टेट को संग्रहीत करना चाहूंगा।


2
बहुत बढ़िया सवाल। जैसा कि यह पता चलता है, एक सटीक रिप्ले पहले की तुलना में अधिक जटिल है, और मैं यह देखने के लिए उत्सुक हूं कि लोग यहां क्या समाधान लेकर आए हैं।
क्रिश्चियन

जवाबों:


8

क्या इसका मतलब यह नहीं है कि एक निश्चित समय से मेल खाने वाले रिकॉर्ड के लिए खोज का समय दौड़ से अधिक लंबा होगा?

नहीं :)

मान लें कि आप इसे एक सरणी के रूप में संग्रहीत करते हैं (ध्यान दें कि स्नैपशॉट कालानुक्रमिक क्रम में हैं, लेकिन समान रूप से नहीं हैं):

snapshots = [
    {time: 0.0, position: {x,y,z}},
    {time: 0.41,    position: {x,y,z}},
    {time: 0.57,    position: {x,y,z}},
    {time: 1.10,    position: {x,y,z}},
    {time: 1.67,    position: {x,y,z}},
    {time: 2.05,    position: {x,y,z}},
    {time: 3.24,    position: {x,y,z}},
    {time: 3.86,    position: {x,y,z}},
    {time: 3.91,    position: {x,y,z}},
    {time: 5.42,    position: {x,y,z}},
    ...]

फिर, जब रिप्ले / गेम शुरू होता है, तो आपको सरणी से पहला और दूसरा तत्व मिलता है:

nextIdx = 1
previousSnapshot = snapshots[nextIdx-1]
nextSnapshot = snapshots[nextIdx]

फिर प्रत्येक फ्रेम में ( currentTimeइस नए गेम में वर्तमान समय है):

if currentTime > nextSnapshot.time
    nextIdx++
    previousSnapshot = snapshots[nextIdx-1]
    nextSnapshot = snapshots[nextIdx]

# Do your magic here, e.g.:
snapshotPairGap = nextSnapshot.time - previousSnapshot.time
ratio = (currentTime - previousSnapshot.time) / snapshotPairGap
ghostPosition = {
    x: previousSnapshot.position.x + ratio*(nextSnapshot.position.x - previousSnapshot.position.x)
    y: previousSnapshot.position.y + ratio*(nextSnapshot.position.y - previousSnapshot.position.y)
    z: previousSnapshot.position.z + ratio*(nextSnapshot.position.z - previousSnapshot.position.z)
}

बेशक, यह कुछ गणनाओं को कैशिंग करके अनुकूलित किया जा सकता है। सरणी के माध्यम से कोई खोज नहीं है, बस विशिष्ट सूचकांकों को देख रहे हैं।


हाँ! मुझे इसे बाद में आज़माना है, लेकिन ऐसा लगता है कि मैं क्या देख रहा था। धन्यवाद!!
marimba

15

यह बहुत कठिन नहीं है। आप अपने डेटा को समय पर (अधिक, बेहतर) मनमाने बिंदुओं पर संग्रहीत कर सकते हैं, और आप उस टाइमस्टैम्प पर आधारित डेटा के मूल्यों को प्रक्षेपित कर सकते हैं जिसे आप देख रहे हैं और दो निकटतम रिकॉर्ड किए गए टाइमस्टैम्प्स जैसे डेटा:

N | Time | Position | Rotation
1 | 0.05 | 1, 1, 1  | 0
2 | 0.15 | 1, 2, 1  | 0
3 | 0.25 | 1, 3, 2  | 30

अब कल्पना करें कि आप 0.10 समय पर स्थिति और रोटेशन प्राप्त करना चाहते हैं। चूँकि 0.10 अंक '1' (जिसका अर्थ 0.05 समय) और '2' है (जिसका अर्थ 0.15 समय है) के बीच है, आपको इनको इंटरपोल करने की आवश्यकता है।

timestamp = 0.10
factor = (timestamp - Time[1]) / (Time[2] - Time[1])
position = Lerp(Position[1], Position[2], factor)
rotation = Lerp(Rotation[1], Rotation[2], factor)

Lerpसिर्फ रैखिक प्रक्षेप है

तो चलो कुछ उदाहरणों (*) के साथ अंतराल को भरें।

N | Time  | Position    | Rotation
1 | 0.05  | 1, 1,    1  | 0
* | 0.075 | 1, 1.25, 1  | 0
* | 0.10  | 1, 1.5,  1  | 0
2 | 0.15  | 1, 2,    1  | 0
* | 0.20  | 1, 2.5,  2  | 15
3 | 0.25  | 1, 3,    2  | 30

HTH।


5
+1। इंटरपोलेशन यहां सरल और प्रभावी उत्तर है। यह सच हो सकता है कि जब वाहन मुड़ रहे हों तो क्यूबिक इंटरपोलेशन थोड़ा बेहतर परिणाम दे सकता है लेकिन यदि अंतराल काफी छोटा है तो रैखिक अच्छा काम करेगा।
काइलोटन

यह दिखाने के लिए धन्यवाद कि प्रक्षेप कैसे करें! यह मेरे खेल के लिए बहुत उपयोगी होगा। लेकिन मान लीजिए कि मैं 41.15 समय पर पुनः प्राप्त करना चाहूंगा, यह सरणी के अंदर गहरा है। क्या आप तब तक पूरे सरणी में खोज करना शुरू कर देंगे जब तक कि आपको रिकॉर्ड नहीं मिला> 41.15?
मरिंबा

1
एक साधारण रेखीय खोज आपके लिए काम कर सकती है, लेकिन बाइनरी खोज बेहतर होती है, जब आपके पास एक क्रमबद्ध सरणी होती है: en.wikipedia.org/wiki/Binary_search_algorithm
Marcin Seredynski
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.