HTML5 कैनवस पर चित्रित किए जाने वाले 2 डी सरणी में टेक्स्ट-मैप का प्रबंधन करना


46

तो, मैं सिर्फ मज़े के लिए एक HTML5 आरपीजी बना रहा हूं। नक्शा एक <canvas>(512px चौड़ाई, 352px ऊँचाई | 16 टाइलों के पार, 11 टाइलें ऊपर से नीचे) हैं। मैं जानना चाहता हूं कि क्या पेंट करने के लिए अधिक कुशल तरीका है <canvas>

यहाँ है कि मैं इसे अभी कैसे है।

टाइल्स को कैसे लोड किया जाता है और नक्शे पर चित्रित किया जाता है

Image()टुकड़े का उपयोग करके नक्शे को टाइल (32x32) द्वारा चित्रित किया जा रहा है । छवि फ़ाइलों को एक साधारण forलूप के माध्यम से लोड किया जाता है tiles[]और उपयोग करने पर PAINTED नामक एक सरणी में डाल दिया जाता है drawImage()

सबसे पहले, हम टाइल्स को लोड करते हैं ...

यहाँ छवि विवरण दर्ज करें

और यहां बताया गया है कि यह कैसे किया जा रहा है:

// SET UP THE & DRAW THE MAP TILES
tiles = [];
var loadedImagesCount = 0;
for (x = 0; x <= NUM_OF_TILES; x++) {
  var imageObj = new Image(); // new instance for each image
  imageObj.src = "js/tiles/t" + x + ".png";
  imageObj.onload = function () {
    console.log("Added tile ... " + loadedImagesCount);
    loadedImagesCount++;
    if (loadedImagesCount == NUM_OF_TILES) {
      // Onces all tiles are loaded ...
      // We paint the map
      for (y = 0; y <= 15; y++) {
        for (x = 0; x <= 10; x++) {
          theX = x * 32;
          theY = y * 32;
          context.drawImage(tiles[5], theY, theX, 32, 32);
        }
      }
    }
  };
  tiles.push(imageObj);
}

स्वाभाविक रूप से, जब कोई खिलाड़ी खेल शुरू करता है, तो वह उस नक्शे को लोड करता है जिसे वे आखिरी बार छोड़ते हैं। लेकिन यहाँ के लिए, यह एक अखिल घास का नक्शा है।

अभी, मानचित्र 2 डी सरणियों का उपयोग करते हैं। यहाँ एक उदाहरण का नक्शा है।

[[4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 1, 1, 1, 1], 
[1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 1, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 13, 13, 1, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 13, 13, 11, 11, 11, 13, 13, 13, 13, 13, 13, 13, 1], 
[13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 13, 13, 13, 13, 13, 1], 
[1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1]];

मुझे एक सरल ifसंरचना का उपयोग करके अलग-अलग नक्शे मिलते हैं । एक बार 2d सरणी ऊपर होने पर return, प्रत्येक सरणी में संबंधित संख्या Image()अंदर संग्रहीत के अनुसार चित्रित की जाएगी tile[]। तब drawImage()होते हैं और के अनुसार रंग होगा xऔर yऔर कई बार यह द्वारा 32सही पर पेंट करने के x-yसमन्वय।

एकाधिक मानचित्र स्विचिंग कैसे होती है

मेरे खेल के साथ, नक्शे पाँच बातें का ट्रैक रखने के लिए है: currentID, leftID, rightID, upID, और bottomID

  • currentID: आपके द्वारा बनाए गए नक्शे की वर्तमान आईडी।
  • बायाँ भाग:currentID वर्तमान मानचित्र के बायीं ओर से बाहर निकलने पर आपको किस आईडी को लोड करना है।
  • राइटआईडी:currentID वर्तमान मानचित्र के दाईं ओर से बाहर निकलने पर आपको किस आईडी को लोड करना है।
  • डाउनआईडी:currentID वर्तमान मानचित्र के निचले भाग से बाहर निकलने पर आपको किस आईडी को लोड करना है।
  • upID:currentID वर्तमान मानचित्र के शीर्ष पर बाहर निकलने पर आपको किस आईडी को लोड करना है।

टिप्पणी के लिए कुछ: या तो हैं leftID, rightID, upID, या bottomID, नहीं विशिष्ट हैं अर्थ यह है कि वे एक हैं 0। इसका मतलब है कि वे नक्शे के उस तरफ नहीं छोड़ सकते। यह केवल एक अदृश्य नाकाबंदी है।

इसलिए, एक बार जब कोई व्यक्ति नक्शे के एक हिस्से से बाहर निकलता है, तो इस पर निर्भर करता है कि वे कहाँ से बाहर निकले हैं ... उदाहरण के लिए यदि वे तल पर बाहर निकलते हैं, तो लोड bottomIDकी संख्या होगी mapऔर इस प्रकार नक्शे पर चित्रित किया जाएगा।

यहाँ एक प्रतिनिधित्व योग्य है। GIF की मदद से आप बेहतर कल्पना कर सकते हैं:

यहाँ छवि विवरण दर्ज करें

जैसा कि आप देख सकते हैं, जल्दी या बाद में, कई नक्शों के साथ मैं कई आईडी से निपटूंगा। और वह संभवतः थोड़ा भ्रमित और व्यस्त हो सकता है।

स्पष्ट पक्ष यह है कि यह एक समय में 176 टाइलें लोड करता है, एक छोटे से 512x352 कैनवास को ताज़ा करता है, और समय पर एक मानचित्र को संभालता है। यह माना जाता है कि कई मानचित्रों के साथ काम करते समय MAP आईडी, कई बार भ्रमित हो सकती है।

मेरा प्रश्न

  • क्या यह मानचित्रों (टाइलों के उपयोग को देखते हुए) को स्टोर करने का एक कुशल तरीका है, या नक्शे को संभालने का एक बेहतर तरीका है?

मैं एक विशाल नक्शे की तर्ज पर सोच रहा था। मानचित्र का आकार बड़ा है और यह सभी एक 2 डी सरणी है। हालाँकि, व्यूपोर्ट अभी भी 512x352 पिक्सेल का है।

यहाँ एक और है।

यहाँ छवि विवरण दर्ज करें

क्षमा करें यदि आप मेरी अंग्रेजी नहीं समझ सकते हैं। कृपया कुछ भी पूछें आपको समझने में परेशानी होगी। उम्मीद है, मैंने इसे स्पष्ट किया। धन्यवाद।


16
इस सवाल को ग्राफिक्स के साथ रखा गया है और सभी एक उत्थान के हकदार हैं। :)
टैपिओ जूल

जवाबों:


5

संपादित करें: बस देखा कि मेरा उत्तर आपके कोड पर आधारित था लेकिन वास्तव में आपके प्रश्न का उत्तर नहीं दिया। मैंने पुराने उत्तर को उस स्थिति में रखा जब आप उस जानकारी का उपयोग कर सकते हैं।

संपादन 2: मैंने मूल कोड के साथ 2 मुद्दे तय किए हैं: - अंत x और y की गणना में +1 जोड़ कोष्ठक के अंदर गलती से था, लेकिन इसे विभाजन के बाद जोड़ा जाना चाहिए। - मैं x और y मानों को मान्य करना भूल गया।

आप बस वर्तमान मानचित्र को स्मृति में रख सकते हैं और आसपास के मानचित्र लोड कर सकते हैं। एक ऐसी दुनिया की कल्पना करें जिसमें 5x5 आकार के एकल स्तरों के 2d सरणी हो। खिलाड़ी फील्ड 1 में शुरू होता है। जैसा कि शीर्ष और बाएं स्तर दुनिया के किनारे पर हैं, उन्हें लोड करने की आवश्यकता नहीं है। तो उस स्थिति में स्तर 1/1 सक्रिय है और स्तर 1/2 और 2/1 लोड किए गए हैं ... यदि खिलाड़ी अब दाईं ओर ले जाता है, तो सभी स्तर (आपके पास जाने के अलावा) अनलोड होते हैं और नए परिवेश होते हैं लदा हुआ। मीन्स स्तर 2/1 अब सक्रिय है, 1/1, 2/2 और 3/1 अब लोड किए गए हैं।

मुझे उम्मीद है कि यह आपको एक विचार देता है कि यह कैसे किया जा सकता है। लेकिन यह दृष्टिकोण बहुत अच्छा काम नहीं करेगा, जब खेल के दौरान हर स्तर को अनुकरण करना होगा। लेकिन अगर आप अप्रयुक्त स्तरों को फ्रीज कर सकते हैं तो यह ठीक काम करना चाहिए।

पुराना उत्तर:

स्तर का प्रतिपादन करते समय मैं क्या करता हूं (टाइल आधारित भी) यह देखने के लिए कि टाइल व्यूह से कौन सी वस्तुओं की गणना है और फिर मैं केवल उन टाइलों को प्रस्तुत करता हूं। जैसे कि आपके पास बड़े मानचित्र हो सकते हैं, लेकिन केवल स्क्रीन पर भाग को प्रस्तुत करना होगा।

//Mock values
//camera position x
//viewport.x = 233f;
//camera position y
//viewport.y = 100f;
//viewport.w = 640
//viewport.h = 480
//levelWidth = 10
//levelHeight = 15
//tilesize = 32;

//startX defines the starting index for the x axis.
// 7 = 233 / 32
int startX = viewport.x / tilesize;

//startY defines the starting index
// 3 = 100 / 32
int startY = viewport.y / tilesize;

//End index y
// 28 = (233 + 640) / 32 + 1
int endX = ((viewport.x + viewport.w) / tilesize) + 1;

//End index y
// 19 = (100 + 480) / 32 + 1
int endX = ((viewport.x + viewport.w) / tilesize) + 1;

//Validation
if(startX < 0) startX = 0;
if(startY < 0) startY = 0;
//endX is set to 9 here
if(endX >= levelWidth) endX = levelWidth - 1;
//endX is set to 14 here
if(endY >= levelHeight) endY = levelHeight - 1;

for(int y = startY; y < yEnd; y++)
    for(int x = startX; x < xEnd; x++)
          [...]

नोट: उपरोक्त कोड का परीक्षण नहीं किया गया है, लेकिन यह एक विचार देना चाहिए कि क्या करना है।

व्यूपोर्ट प्रतिनिधित्व के लिए एक मूल उदाहरण के बाद:

public class Viewport{
    public float x;
    public float y;
    public float w;
    public float h;
}

एक जावास्क्रिप्ट प्रतिनिधित्व की तरह दिखेगा

<script type="text/javascript">
//Declaration
//Constructor
var Viewport = function(xVal, yVal, wVal, hVal){
    this.x = xVal;
    this.y = yVal;
    this.w = wVal;
    this.h = hVal;
}
//Prototypes
Viewport.prototype.x = null;
Viewport.prototype.y = null;
Viewport.prototype.w = null;
Viewport.prototype.h = null;
Viewport.prototype.toString = function(){
    return ["Position: (", this.x, "/" + this.y + "), Size: (", this.w, "/", this.h, ")"].join("");
}

//Usage
var viewport = new Viewport(23, 111, 640, 480);
//Alerts "Position: (23/111), Size: (640/480)
alert(viewport.toString());
</script>

यदि आप मेरे कोड का उदाहरण लेते हैं, तो आपको सरल और फ़्लोट घोषणाओं को var से बदलना होगा। यह भी सुनिश्चित करें कि आप उन गणनाओं पर Math.floor का उपयोग करते हैं, जो समान व्यवहार प्राप्त करने के लिए, आंतरिक आधारित मानों को असाइन किए जाते हैं।

एक बात पर मैं विचार करूंगा (हालांकि मुझे यकीन नहीं है कि अगर यह जावास्क्रिप्ट में मायने रखता है) तो कई सिंगल फाइलों का उपयोग करने के बजाय सभी टाइल्स (या जितना संभव हो उतना) एक बड़ी बनावट में लगाना है।

यहां बताया गया है कि यह कैसे करना है: http://thiscouldbebetter.wordpress.com/2012/02/25/slicing-an-image-into-tiles-in-javascript/


बस स्पष्ट करने के लिए ... viewport.x को "531" के रूप में और viewport.y को "352" और टाइल्स को = "32" के रूप में लिया जाएगा। और ऐसा..?
टेस्ट

अगर आपका मतलब है कि कैमरे की स्थिति 531 है तो हां। मैंने ऊपर दिए गए कोड में कुछ टिप्पणियां जोड़ीं।
टॉम वैन ग्रीन

मैं जावास्क्रिप्ट का उपयोग कर रहा हूं ... मैं जावा हूं इसके समान है।
परीक्षण

हाँ, आपको बस एक js आधारित व्यूपोर्ट क्लास बनानी होगी (या आप सिर्फ 4 वैरिएबल x, y, w और h बना सकते हैं)। इसके अलावा, आपको उन गणनाओं को फर्श (Math.floor) पर सुनिश्चित करना होगा, जो कि अंतर मानों को सौंपे गए हैं। मैंने एक कोड उदाहरण जोड़ा, व्यूपोर्ट वर्ग कैसा दिखेगा। बस यह सुनिश्चित कर लें, कि आपने घोषणा को उपयोग से पहले रखा है।
टॉम वैन ग्रीन

सिर्फ यह कहते हुए कि आप डालते हैं 640, 480.. लेकिन यह 512, 352सही से काम कर सकता है ?
टेस्ट

3

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

पूरे मानचित्र को एक बड़े सरणी के रूप में संग्रहीत करें। वहाँ कोई मतलब नहीं नक्शे और सबमैप, साथ ही संभावित उप-उप-नक्शे (यदि आप भवनों में प्रवेश कर रहे हैं, उदाहरण के लिए)। आप इसे वैसे भी लोड कर रहे हैं और यह सब कुछ अच्छा और सरल रखता है।

एक ही बार में सभी मानचित्र प्रस्तुत करें। एक ऑफ-स्क्रीन कैनवास है जिसे आप मैप को रेंडर करते हैं और फिर अपने गेम में इसका उपयोग करते हैं। यह पृष्ठ आपको दिखाता है कि इसे एक साधारण जावास्क्रिप्ट फ़ंक्शन के साथ कैसे किया जाता है:

var renderToCanvas = function (width, height, renderFunction) {
  var buffer = document.createElement('canvas');
  buffer.width = width;
  buffer.height = height;
  renderFunction(buffer.getContext('2d'));
  return buffer;
};

यह मानकर चल रहा है कि आपका नक्शा बहुत कुछ बदलने वाला नहीं है। यदि आप उप-नक्शे को (उदाहरण के लिए, किसी भवन के अंदर) रेंडर करना चाहते हैं, तो आप उसे केवल एक कैनवस के लिए भी प्रस्तुत करते हैं और फिर उसे शीर्ष पर आकर्षित करते हैं। यहां एक उदाहरण दिया गया है कि आप अपने नक्शे को प्रस्तुत करने के लिए इसका उपयोग कैसे कर सकते हैं:

var map = renderToCanvas( map_width*32, map_height*32, renderMap );

var MapSizeX = 512;
var MapSizeY = 352;

var draw = function(canvas, mapCentreX, mapCentreY) {
  var context = canvas.getContext('2d');

  var minX = playerX - MapSizeX/2;
  var minY = playerY - MapSizeY/2;

  context.drawImage(map,minX,minY,MapSizeX,MapSizeY,0,0,MapSizeX,MapSizeY);
}

यह मानचित्र के एक छोटे हिस्से को चारों ओर केन्द्रित करेगा mapCentreX, mapCentreY। यह आपको पूरे मानचित्र के साथ-साथ उप-टाइल आंदोलन के बारे में चिकनी स्क्रॉलिंग की पेशकश करेगा - आप एक टाइल के 1/32 वें हिस्से के रूप में खिलाड़ी की स्थिति को स्टोर कर सकते हैं, इसलिए आप पूरे नक्शे पर चिकनी आंदोलन प्राप्त कर सकते हैं (स्पष्ट रूप से यदि आप चाहते हैं एक शैलीगत विकल्प के रूप में टाइल-बाय-टाइल को स्थानांतरित करें, आप बस 32 के भाग में वृद्धि कर सकते हैं)।

यदि आप चाहें, तो भी आप अपने नक्शे को काट सकते हैं, या यदि आपकी दुनिया बहुत बड़ी है और आपके लक्ष्य प्रणालियों पर स्मृति में फिट नहीं होगी (ध्यान रखें कि प्रति पिक्सेल 1 बाइट के लिए, 512x352 नक्शा 176 KB है) लेकिन पूर्व से अपने नक्शे को इस तरह से भेजना कि आपको अधिकांश ब्राउज़रों में एक बड़ा प्रदर्शन प्राप्त होगा

यह आपको क्या देता है एक बड़ी छवि को संपादित करने के सिरदर्द के बिना दुनिया भर में टाइलों के पुन: उपयोग की लचीलापन है, लेकिन यह आपको इसे जल्दी और आसानी से चलाने की अनुमति देता है और केवल एक 'मानचित्र' (या आपके जैसे कई 'नक्शे) पर विचार करता है) ।


2

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

https://gamedev.stackexchange.com/a/25035/10055

ये विखंडू आमतौर पर 2 की शक्तियों में होते हैं, इसलिए वे स्मृति में उपयुक्त रूप से फिट होते हैं।


1

आईडी का ट्रैक रखने का एक आसान तरीका बस उनके साथ एक और 2d सरणी का उपयोग करना होगा: केवल उस "मेटा सरणी" पर x, y बनाए रखने से, आप आसानी से अन्य आईडी देख सकते हैं।

कहा जा रहा है कि, यहाँ हाल ही में I / O 2012 से 2 डी टाइल किए गए कैनवस गेमिंग (अच्छी तरह से एचटीएमएल 5 मल्टीप्लेयर, लेकिन टाइल इंजन को कवर किया गया है) पर Google का टेकऑफ़ है: http://www.youtube.com/watch?v=Prkyd5n0P7k इसे स्रोत कोड भी उपलब्ध है।


1

आपका विचार पूरे मानचित्र को पहले एक सरणी में लोड करने के लिए है, एक कुशल तरीका है, लेकिन जावास्क्रिप्ट इंजेक्शन को प्राप्त करना आसान होगा, कोई भी मानचित्र को जान सकेगा और वहां रोमांच आएगा।

मैं एक आरपीजी गेम वेब-आधारित पर काम कर रहा हूं, जिस तरह से मैं अपना नक्शा लोड करता हूं वह एक PHP पेज से अजाक्स के माध्यम से होता है, जो डेटाबेस से नक्शा लोड करता है, जहां यह एक्स, वाई, जेड स्थिति और vlaue कहता है। टाइल की, इसे आकर्षित करें, और अंत में खिलाड़ी को स्थानांतरित करें।

मैं इसे और अधिक कुशल बनाने के लिए अभी भी इस पर काम कर रहा हूं, लेकिन अब तक इस तरह से इसे बनाए रखने के लिए मानचित्र काफी तेजी से लोड होता है।


1
क्या मैं एक डेमो देख सकता हूँ?
परीक्षण करें

1

नहीं , एक सरणी एक टाइल मानचित्र को संग्रहीत करने का सबसे कुशल तरीका है

कुछ संरचनाएं हो सकती हैं जिनके लिए थोड़ी कम मेमोरी की आवश्यकता होती है लेकिन केवल डेटा को लोड करने और एक्सेस करने के लिए बहुत अधिक लागतों की कीमत पर।


हालाँकि कुछ बातों पर ध्यान देने की ज़रूरत है जब आप अगले नक्शे को लोड करने जा रहे हैं। यह देखते हुए कि नक्शे विशेष रूप से बड़े नहीं हैं, वह चीज जो वास्तव में सबसे लंबे समय तक ले जाएगी, वह सर्वर को मानचित्र देने के लिए इंतजार कर रही है। वास्तविक लोडिंग में केवल कुछ मिलीसेकंड लगेगा। लेकिन इस प्रतीक्षा को अतुल्यकालिक किया जा सकता है, इससे खेल के प्रवाह को अवरुद्ध नहीं करना पड़ता है। इसलिए सबसे अच्छी बात यह है कि जरूरत पड़ने पर डेटा लोड नहीं किया जा रहा है लेकिन पहले। खिलाड़ी एक नक्शे में है, अब सभी आसन्न नक्शे लोड करें। खिलाड़ी अगले नक्शे में आगे बढ़ता है, सभी आसन्न मानचित्रों को फिर से लोड करता है, आदि। खिलाड़ी को यह भी ध्यान नहीं रहेगा कि आपका खेल पृष्ठभूमि में लोड हो रहा है।

इस तरह आप आसन्न मानचित्रों को भी आकर्षित करके एक सीमा कम दुनिया का भ्रम पैदा कर सकते हैं, उस स्थिति में आपको न केवल आसन्न नक्शे बल्कि उन आसन्न लोगों के भी लोड करने की आवश्यकता है, हालांकि।


0

मुझे यकीन नहीं है कि आप क्यों सोचते हैं: जैसा कि आप देख सकते हैं, जल्दी या बाद में, कई नक्शों के साथ मैं कई आईडी के साथ काम करूंगा। और वह संभवतः थोड़ा भ्रमित और व्यस्त हो सकता है।

LeftID हमेशा currentID का -1 होगा, rightID हमेशा currentID का +1 होगा।

UpID हमेशा रहेगा - (वर्तमान मानचित्र चौड़ाई) वर्तमान ID का और downID हमेशा वर्तमान ID का + (कुल मानचित्र चौड़ाई) शून्य अर्थ के अपवाद के साथ होगा जो आपने किनारे पर मारा है।

एक सिंगल मैप को कई मैप्स में तोड़ा जा सकता है, और मैपआईडीएक्सएक्सएक्सएक्सएक्स के साथ क्रमिक रूप से बचाया जाता है जहां XXXX आईडी है। इस तरह, वहाँ भ्रमित होने के लिए कुछ भी नहीं है। मैं आपकी साइट पर गया हूं और ऐसा लगता है, मैं गलत हो सकता हूं, कि समस्या आपके मानचित्र संपादक के लिए नीचे है, जो एक आकार सीमा को लागू कर रहा है, जो आपके स्वचालन को बचाने के लिए कई छोटे लोगों में एक बड़े नक्शे को तोड़ने के लिए बाधा बना रहा है और यह सीमा है शायद एक तकनीकी समाधान प्रतिबंधित है।

मैंने एक जावास्क्रिप्ट मैप एडिटर लिखा है जो सभी दिशाओं में स्क्रॉल करता है, 1000 x 1000 (मैं उस आकार की सिफारिश नहीं करूंगा) टाइल्स और यह अभी भी 50 x 50 मैप जितना अच्छा है और 3 परतों के साथ लंबन स्क्रॉलिंग के साथ है। यह ज्सन फॉर्मेट में सेव और रीड करता है। यदि आप कहते हैं कि आपको लगभग 2meg का ईमेल नहीं आता है, तो मैं आपको एक प्रति भेजूंगा। यह जीथब पर होने के लिए है, लेकिन मुझे कोई भी सभ्य (कानूनी) टाइलसेट नहीं मिला है, यही वजह है कि मैंने इसे अभी तक वहां लगाने की जहमत नहीं उठाई।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.