परिचय
पिछले साल (2010) की शुरुआत में, मुझे HTML5 और उससे जुड़ी टेक्नोलॉजी के लिए, तेज़ी से बढ़ रही सहायता में दिलचस्पी हुई. उस समय, मैंने और मेरे एक दोस्त ने गेम डेवलपमेंट से जुड़ी दो हफ़्ते की प्रतियोगिताओं में एक-दूसरे को चुनौती दी थी. इससे हमें प्रोग्रामिंग और डेवलपमेंट की अपनी स्किल को बेहतर बनाने में मदद मिली. साथ ही, हमने गेम के उन आइडिया को भी ज़िंदा किया जो हम एक-दूसरे को बताते रहते थे. इसलिए, मैंने अपनी प्रतियोगिता में शामिल एंट्री में HTML5 एलिमेंट शामिल करना शुरू किया, ताकि उनके काम करने के तरीके को बेहतर तरीके से समझा जा सके. साथ ही, ऐसे काम किए जा सकें जो एचटीएमएल के पुराने वर्शन का इस्तेमाल करके करना मुश्किल था.
HTML5 की कई नई सुविधाओं में से, कैनवस टैग के लिए बढ़ती सहायता ने मुझे JavaScript का इस्तेमाल करके इंटरैक्टिव आर्ट लागू करने का एक शानदार मौका दिया. इसकी मदद से, मैंने एक पहेली गेम को लागू करने की कोशिश की, जिसे अब Entanglement कहा जाता है. मैंने Settlers of Catan टाइल के पीछे की तरफ़ का इस्तेमाल करके, पहले ही एक प्रोटोटाइप बना लिया था. इसलिए, इसे ब्लूप्रिंट के तौर पर इस्तेमाल करके, वेब पर खेलने के लिए HTML5 कैनवस पर हेक्सागॉन टाइल बनाने के लिए, तीन ज़रूरी चीज़ें हैं: हेक्सागॉन बनाना, पाथ बनाना, और टाइल को घुमाना. यहां इस बारे में पूरी जानकारी दी गई है कि मैंने इन सभी को मौजूदा तौर पर कैसे हासिल किया.
हेक्सागॉन बनाना
Entanglement के ओरिजनल वर्शन में, मैंने हेक्सागॉन बनाने के लिए कैनवस ड्रॉ के कई तरीकों का इस्तेमाल किया था. हालांकि, गेम के मौजूदा वर्शन में स्प्राइट शीट से काटे गए टेक्सचर बनाने के लिए drawImage()
का इस्तेमाल किया जाता है.

मैंने इमेज को एक फ़ाइल में जोड़ दिया है, ताकि इस मामले में, सर्वर को 10 के बजाय सिर्फ़ एक अनुरोध भेजा जा सके. कैनवस पर चुना गया हेक्सागॉन बनाने के लिए, हमें सबसे पहले अपने टूल इकट्ठा करने होंगे: कैनवस, कॉन्टेक्स्ट, और इमेज.
कैनवस बनाने के लिए, हमें अपने एचटीएमएल दस्तावेज़ में कैनवस टैग की ज़रूरत होती है. यह टैग इस तरह दिखता है:
<canvas id="myCanvas"></canvas>
मैंने इसे एक आईडी दिया है, ताकि हम इसे अपनी स्क्रिप्ट में शामिल कर सकें:
var cvs = document.getElementById('myCanvas');
दूसरी बात, हमें कैनवस के लिए 2D कॉन्टेक्स्ट लेना होगा, ताकि हम ड्रॉइंग शुरू कर सकें:
var ctx = cvs.getContext('2d');
आखिर में, हमें इमेज की ज़रूरत है. अगर यह हमारे वेब पेज के उसी फ़ोल्डर में "tiles.png" नाम से मौजूद है, तो इसे पाने के लिए:
var img = new Image();
img.src = 'tiles.png';
अब हमारे पास तीन कॉम्पोनेंट हैं. इसलिए, स्प्राइट शीट से कैनवस पर अपनी पसंद का एक हेक्सागॉन बनाने के लिए, ctx.drawImage() का इस्तेमाल किया जा सकता है:
ctx.drawImage(img, sourceX, sourceY, sourceWidth, sourceHeight,
destinationX, destinationY, destinationWidth, destinationHeight);
इस मामले में, हम सबसे ऊपर वाली पंक्ति में बाईं ओर से चौथे हेक्सागॉन का इस्तेमाल कर रहे हैं. साथ ही, हम इसे सबसे ऊपर बाएं कोने में कैनवस पर खींचेंगे और इसे ओरिजनल साइज़ में ही रखेंगे. मान लें कि हेक्सागॉन 400 पिक्सल चौड़े और 346 पिक्सल ऊंचे हैं, तो यह कुछ इस तरह दिखेगा:
var cvs = document.getElementById('myCanvas');
var ctx = cvs.getContext('2d');
var img = new Image();
img.src = 'tiles.png';
var sourceX = 1200;
var sourceY = 0;
var sourceWidth = 400;
var sourceHeight = 346;
var destinationX = 0;
var destinationY = 0;
var destinationWidth = 400;
var destinationHeight = 346;
ctx.drawImage(img, sourceX, sourceY, sourceWidth, sourceHeight,
destinationX, destinationY, destinationWidth, destinationHeight);
हमने इमेज के कुछ हिस्से को कैनवस पर कॉपी कर लिया है. इसका नतीजा यह है:

पाथ बनाना
अब हमने कैनवस पर हेक्सागॉन बना लिया है. अब हमें उस पर कुछ लाइनें खींचनी हैं. सबसे पहले, हम हेक्सागॉन टाइल के बारे में कुछ ज्यामिति देखेंगे. हमें हर तरफ़ दो लाइन एंड चाहिए. हर लाइन एंड, किनारे के 1/4 हिस्से पर होना चाहिए और एक-दूसरे से 1/2 हिस्से की दूरी पर होना चाहिए. जैसे:

हमें एक अच्छा कर्व भी चाहिए. इसलिए, कुछ कोशिश करने के बाद मुझे पता चला कि अगर हर एंडपॉइंट के किनारे से लंबवत रेखा बनाई जाती है, तो हेक्सागॉन के किसी दिए गए ऐंगल के आस-पास मौजूद हर एंडपॉइंट के जोड़े के इंटरसेक्शन से, दिए गए एंडपॉइंट के लिए एक अच्छा बेज़ियर कंट्रोल पॉइंट बनता है:

अब, हम एंडपॉइंट और कंट्रोल पॉइंट, दोनों को कैनवस इमेज से जुड़े कार्टेशियन प्लेन पर मैप करते हैं. इसके बाद, हम कोड पर वापस आ सकते हैं. इसे आसान बनाने के लिए, हम एक लाइन से शुरू करेंगे. हम सबसे ऊपर बाईं ओर मौजूद एंडपॉइंट से लेकर सबसे नीचे दाईं ओर मौजूद एंडपॉइंट तक पाथ बनाकर शुरू करेंगे. हमारी पिछली हेक्सागॉन इमेज 400x346 थी. इससे, हमारा टॉप एंडपॉइंट 150 पिक्सल चौड़ा और 0 पिक्सल नीचे होगा. इसका शॉर्टहैंड (150, 0) होगा. इसका कंट्रोल पॉइंट (150, 86) होगा. सबसे नीचे के एज का एंडपॉइंट (250, 346) है और कंट्रोल पॉइंट (250, 260) है:

निर्देशांक मिलने के बाद, अब हम ड्रॉइंग शुरू कर सकते हैं. हम ctx.beginPath() का इस्तेमाल करके, नए सिरे से शुरू करेंगे. इसके बाद, पहले एंडपॉइंट पर जाने के लिए, इनका इस्तेमाल करेंगे:
ctx.moveTo(pointX1,pointY1);
इसके बाद, ctx.bezierCurveTo() का इस्तेमाल करके, लाइन को इस तरह से खुद खींचा जा सकता है:
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
हमें लाइन के लिए एक अच्छी सी बॉर्डर चाहिए. इसलिए, हम इस पाथ को दो बार स्ट्रोक करेंगे. हर बार अलग-अलग चौड़ाई और रंग का इस्तेमाल किया जाएगा. रंग को ctx.strokeStyle प्रॉपर्टी का इस्तेमाल करके सेट किया जाएगा और चौड़ाई को ctx.lineWidth का इस्तेमाल करके सेट किया जाएगा. कुल मिलाकर, पहली लाइन को इस तरह ड्रॉ किया जाएगा:
var pointX1 = 150;
var pointY1 = 0;
var controlX1 = 150;
var controlY1 = 86;
var controlX2 = 250;
var controlY2 = 260;
var pointX2 = 250;
var pointY2 = 346;
ctx.beginPath();
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();
अब हमारे पास एक हेक्सागॉनल टाइल है, जिसमें पहली लाइन टेढ़ी-मेढ़ी है:

अन्य 10 एंडपॉइंट के साथ-साथ, उनसे जुड़े बिज़ीर कर्व कंट्रोल पॉइंट के निर्देशांक डालकर, ऊपर दिया गया तरीका दोहराया जा सकता है. इससे इस तरह की टाइल बनाई जा सकती है:

कैनवस को घुमाना
टाइल बनाने के बाद, हमें उसे घुमाना होगा, ताकि गेम में अलग-अलग रास्ते चुने जा सकें. कैनवस का इस्तेमाल करके, ऐसा करने के लिए हम ctx.translate()
और ctx.rotate()
का इस्तेमाल करते हैं. हमें टाइल को उसके बीच से घुमाना है. इसलिए, हमारा पहला चरण कैनवस के रेफ़रंस पॉइंट को हेक्सागॉन टाइल के बीच में ले जाना है.
इसके लिए, हम इनका इस्तेमाल करते हैं:
ctx.translate(originX, originY);
यहां originX, हेक्सागॉनल टाइल की चौड़ाई का आधा होगा और originY, ऊंचाई का आधा होगा. इससे हमें यह मिलेगा:
var originX = 200;
var originY = 173;
ctx.translate(originX, originY);
अब हम नए सेंटर पॉइंट की मदद से, टाइल को घुमाने में सक्षम हैं. हेक्सागॉन के पास छह साइड होती हैं. इसलिए, हम इसे Math.PI के मल्टीपल में घुमाना चाहते हैं और उसमें तीन से भाग करना चाहते हैं. हम इसे आसान रखेंगे और एक बार घड़ी की सुई की दिशा में घुमाकर, इस तरह से दिखाएंगे:
ctx.rotate(Math.PI / 3);
हालांकि, हमारा हेक्सागॉन और लाइनें, ऑरिजिन के तौर पर पुराने (0,0) निर्देशांक का इस्तेमाल कर रही हैं. इसलिए, घुमाने के बाद, हम ड्रॉ करने से पहले, उन्हें वापस ट्रांसलेट करना चाहेंगे. इसलिए, अब हमारे पास ये सभी सुविधाएं हैं:
var originX = 200;
var originY = 173;
ctx.translate(originX, originY);
ctx.rotate(Math.PI / 3);
ctx.translate(-originX, -originY);
रेंडरिंग कोड से पहले ऊपर दिए गए ट्रांसलेशन और रोटेशन को डालने पर, अब यह टाइल को घुमाकर रेंडर करेगा:

खास जानकारी
ऊपर मैंने कैनवस टैग का इस्तेमाल करके, HTML5 की कुछ सुविधाओं के बारे में बताया है. इनमें इमेज रेंडर करना, बेज़ियर कर्व बनाना, और कैनवस को घुमाना शामिल है. एन्टेंगलमेंट के लिए, एचटीएमएल5 कैनवस टैग और उसके JavaScript ड्रॉइंग टूल का इस्तेमाल करना एक बेहतरीन अनुभव रहा. मुझे उम्मीद है कि इस ओपन और नई टेक्नोलॉजी की मदद से, लोग कई नए ऐप्लिकेशन और गेम बनाएंगे.
कोड रेफ़रंस
ऊपर दिए गए सभी कोड के उदाहरणों को रेफ़रंस के तौर पर यहां एक साथ दिया गया है:
var cvs = document.getElementById('myCanvas');
var ctx = cvs.getContext('2d');
var img = new Image();
img.src = 'tiles.png';
var originX = 200;
var originY = 173;
ctx.translate(originX, originY);
ctx.rotate(Math.PI / 3);
ctx.translate(-originX, -originY);
var sourceX = 1200;
var sourceY = 0;
var sourceWidth = 400;
var sourceHeight = 346;
var destinationX = 0;
var destinationY = 0;
var destinationWidth = 400;
var destinationHeight = 346;
ctx.drawImage(img, sourceX, sourceY, sourceWidth, sourceHeight,
destinationX, destinationY, destinationWidth, destinationHeight);
ctx.beginPath();
var pointX1 = 150;
var pointY1 = 0;
var controlX1 = 150;
var controlY1 = 86;
var controlX2 = 250;
var controlY2 = 260;
var pointX2 = 250;
var pointY2 = 346;
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();
ctx.beginPath();
pointX1 = 250;
pointY1 = 0;
controlX1 = 250;
controlY1 = 86;
controlX2 = 150;
controlY2 = 86;
pointX2 = 75;
pointY2 = 43;
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();
ctx.beginPath();
pointX1 = 150;
pointY1 = 346;
controlX1 = 150;
controlY1 = 260;
controlX2 = 300;
controlY2 = 173;
pointX2 = 375;
pointY2 = 213;
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();
ctx.beginPath();
pointX1 = 325;
pointY1 = 43;
controlX1 = 250;
controlY1 = 86;
controlX2 = 300;
controlY2 = 173;
pointX2 = 375;
pointY2 = 130;
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();
ctx.beginPath();
pointX1 = 25;
pointY1 = 130;
controlX1 = 100;
controlY1 = 173;
controlX2 = 100;
controlY2 = 173;
pointX2 = 25;
pointY2 = 213;
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();
ctx.beginPath();
pointX1 = 325;
pointY1 = 303;
controlX1 = 250;
controlY1 = 260;
controlX2 = 150;
controlY2 = 260;
pointX2 = 75;
pointY2 = 303;
ctx.moveTo(pointX1, pointY1);
ctx.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, pointX2, pointY2);
ctx.lineWidth = 15;
ctx.strokeStyle = '#ffffff';
ctx.stroke();
ctx.lineWidth = 10;
ctx.strokeStyle = '#786c44';
ctx.stroke();