কেস স্টাডি - ইনসাইড ওয়ার্ল্ড ওয়াইড মেজ

ওয়ার্ল্ড ওয়াইড মেজ হল এমন একটি গেম যেখানে আপনি তাদের লক্ষ্য পয়েন্টে পৌঁছানোর চেষ্টা করার জন্য ওয়েবসাইটগুলি থেকে তৈরি 3D মেজগুলির মাধ্যমে একটি রোলিং বল নেভিগেট করতে আপনার স্মার্টফোন ব্যবহার করেন৷

ওয়ার্ল্ড ওয়াইড গোলকধাঁধা

গেমটিতে HTML5 বৈশিষ্ট্যের প্রচুর ব্যবহার রয়েছে। উদাহরণস্বরূপ, ডিভাইস অরিয়েন্টেশন ইভেন্ট স্মার্টফোন থেকে টিল্ট ডেটা পুনরুদ্ধার করে, যা পরে WebSocket-এর মাধ্যমে পিসিতে পাঠানো হয়, যেখানে খেলোয়াড়রা WebGL এবং Web Workers দ্বারা নির্মিত 3D স্পেসগুলির মাধ্যমে তাদের পথ খুঁজে পায়।

এই প্রবন্ধে, আমি এই বৈশিষ্ট্যগুলি কীভাবে ব্যবহার করা হয়, সামগ্রিক উন্নয়ন প্রক্রিয়া এবং অপ্টিমাইজেশনের জন্য মূল পয়েন্টগুলি সম্পর্কে স্পষ্টভাবে ব্যাখ্যা করব৷

ডিভাইস ওরিয়েন্টেশন

ডিভাইস ওরিয়েন্টেশন ইভেন্ট ( উদাহরণ ) স্মার্টফোন থেকে টিল্ট ডেটা পুনরুদ্ধার করতে ব্যবহৃত হয়। যখন DeviceOrientation ইভেন্টের সাথে addEventListener ব্যবহার করা হয়, তখন নিয়মিত বিরতিতে একটি আর্গুমেন্ট হিসাবে DeviceOrientationEvent অবজেক্টের সাথে একটি কলব্যাক আহ্বান করা হয়। ব্যবধানগুলি ব্যবহৃত ডিভাইসের সাথে পরিবর্তিত হয়। উদাহরণস্বরূপ, iOS + Chrome এবং iOS + Safari-এ, প্রতি সেকেন্ডের 1/20তম সময়ে কলব্যাক আহ্বান করা হয়, যখন Android 4 + Chrome-এ এটি প্রতি সেকেন্ডের প্রায় 1/10তম সময়ে আহ্বান করা হয়।

window.addEventListener('deviceorientation', function (e) {
  // do something here..
});

DeviceOrientationEvent অবজেক্টে প্রতিটি X , Y , এবং Z অক্ষের জন্য ডিগ্রীতে (রেডিয়ান নয়) টিল্ট ডেটা থাকে ( HTML5Rocks এ আরও পড়ুন )। যাইহোক, ব্যবহৃত ডিভাইস এবং ব্রাউজারের সংমিশ্রণের সাথে রিটার্ন মানগুলিও পরিবর্তিত হয়। প্রকৃত রিটার্ন মানগুলির পরিসর নীচের সারণীতে দেওয়া হয়েছে:

ডিভাইস অভিযোজন।

নীল রঙে হাইলাইট করা উপরের মানগুলি হল W3C স্পেসিফিকেশনে সংজ্ঞায়িত। সবুজ রঙে হাইলাইট করা এই স্পেসিফিকেশনগুলির সাথে মেলে, যখন লাল রঙে হাইলাইট করাগুলি বিচ্যুত হয়। আশ্চর্যজনকভাবে, শুধুমাত্র অ্যান্ড্রয়েড-ফায়ারফক্স সংমিশ্রণটি নির্দিষ্টকরণের সাথে মেলে এমন মান ফিরিয়ে দিয়েছে। তবুও, যখন এটি বাস্তবায়নের কথা আসে তখন ঘন ঘন ঘটতে থাকা মানগুলিকে মিটমাট করা আরও বোধগম্য হয়। ওয়ার্ল্ড ওয়াইড মেজ তাই iOS রিটার্ন মানগুলিকে স্ট্যান্ডার্ড হিসাবে ব্যবহার করে এবং সেই অনুযায়ী অ্যান্ড্রয়েড ডিভাইসগুলির জন্য সামঞ্জস্য করে।

if android and event.gamma > 180 then event.gamma -= 360

যদিও এটি এখনও নেক্সাস 10 সমর্থন করে না। যদিও Nexus 10 অন্যান্য অ্যান্ড্রয়েড ডিভাইসের মতো একই পরিসরের মান প্রদান করে, সেখানে একটি বাগ রয়েছে যা বিটা এবং গামা মানকে বিপরীত করে দেয়। এটি আলাদাভাবে সম্বোধন করা হচ্ছে। (সম্ভবত এটি ল্যান্ডস্কেপ ওরিয়েন্টেশনে ডিফল্ট?)

এটি যেমন দেখায়, এমনকি যদি ফিজিক্যাল ডিভাইসের সাথে জড়িত API গুলি স্পেসিফিকেশন সেট করে থাকে, তবে ফেরত দেওয়া মানগুলি সেই স্পেসিফিকেশনগুলির সাথে মিলবে এমন কোনও গ্যারান্টি নেই৷ সমস্ত সম্ভাব্য ডিভাইসে তাদের পরীক্ষা করা তাই অত্যন্ত গুরুত্বপূর্ণ। এর মানে হল যে অপ্রত্যাশিত মান সন্নিবেশ করা হতে পারে, যার জন্য সমাধান তৈরি করা প্রয়োজন। ওয়ার্ল্ড ওয়াইড মেজ প্রথমবারের খেলোয়াড়দের তাদের টিউটোরিয়ালের ধাপ 1 হিসাবে তাদের ডিভাইসগুলিকে ক্যালিব্রেট করতে অনুরোধ করে, তবে এটি অপ্রত্যাশিত টিল্ট মানগুলি গ্রহণ করলে এটি শূন্য অবস্থানে সঠিকভাবে ক্যালিব্রেট করবে না। তাই এটির একটি অভ্যন্তরীণ সময়সীমা রয়েছে এবং প্লেয়ারকে কীবোর্ড নিয়ন্ত্রণে স্যুইচ করতে অনুরোধ করে যদি এটি সেই সময়সীমার মধ্যে ক্যালিব্রেট করতে না পারে।

ওয়েবসকেট

ওয়ার্ল্ড ওয়াইড মেজে, আপনার স্মার্টফোন এবং পিসি ওয়েবসকেটের মাধ্যমে সংযুক্ত থাকে। আরও সঠিকভাবে, তারা তাদের মধ্যে একটি রিলে সার্ভারের মাধ্যমে সংযুক্ত থাকে, অর্থাৎ স্মার্টফোন থেকে সার্ভার থেকে পিসি। এর কারণ ওয়েবসকেটের ব্রাউজারগুলিকে একে অপরের সাথে সরাসরি সংযোগ করার ক্ষমতা নেই। (WebRTC ডেটা চ্যানেল ব্যবহার করা পিয়ার-টু-পিয়ার সংযোগের অনুমতি দেয় এবং একটি রিলে সার্ভারের প্রয়োজনীয়তা দূর করে, কিন্তু বাস্তবায়নের সময় এই পদ্ধতিটি শুধুমাত্র Chrome Canary এবং Firefox Nightly এর সাথে ব্যবহার করা যেতে পারে ।)

আমি Socket.IO (v0.9.11) নামক একটি লাইব্রেরি ব্যবহার করে বাস্তবায়ন করতে বেছে নিয়েছি, যা সংযোগের সময়সীমা বা সংযোগ বিচ্ছিন্ন হওয়ার ক্ষেত্রে পুনরায় সংযোগ করার বৈশিষ্ট্যগুলি অন্তর্ভুক্ত করে। আমি এটি NodeJS এর ​​সাথে একসাথে ব্যবহার করেছি, কারণ এই NodeJS + Socket.IO সংমিশ্রণটি বেশ কয়েকটি WebSocket বাস্তবায়ন পরীক্ষায় সেরা সার্ভার-সাইড কর্মক্ষমতা দেখিয়েছে।

সংখ্যা দ্বারা জোড়া

  1. আপনার পিসি সার্ভারের সাথে সংযোগ করে।
  2. সার্ভার আপনার পিসিকে একটি এলোমেলোভাবে জেনারেট করা নম্বর দেয় এবং সংখ্যা এবং পিসির সংমিশ্রণ মনে রাখে।
  3. আপনার মোবাইল ডিভাইস থেকে, একটি নম্বর নির্দিষ্ট করুন এবং সার্ভারের সাথে সংযোগ করুন৷
  4. যদি নির্দিষ্ট করা নম্বরটি একটি সংযুক্ত পিসির মতোই হয়, তাহলে আপনার মোবাইল ডিভাইসটি সেই পিসির সাথে যুক্ত করা হয়েছে।
  5. যদি কোনও মনোনীত পিসি না থাকে তবে একটি ত্রুটি ঘটে।
  6. যখন আপনার মোবাইল ডিভাইস থেকে ডেটা আসে, তখন এটি সেই পিসিতে পাঠানো হয় যার সাথে এটি পেয়ার করা হয় এবং এর বিপরীতে।

আপনি পরিবর্তে আপনার মোবাইল ডিভাইস থেকে প্রাথমিক সংযোগ করতে পারেন। ডিভাইসগুলি কেবল সেই ক্ষেত্রে বিপরীত হয়।

ট্যাব সিঙ্ক

Chrome-নির্দিষ্ট ট্যাব সিঙ্ক বৈশিষ্ট্য পেয়ারিং প্রক্রিয়াটিকে আরও সহজ করে তোলে। এটির সাহায্যে, পিসিতে খোলা পৃষ্ঠাগুলি সহজেই একটি মোবাইল ডিভাইসে খোলা যেতে পারে (এবং তদ্বিপরীত)। PC সার্ভার দ্বারা ইস্যু করা সংযোগ নম্বরটি নেয় এবং history.replaceState ব্যবহার করে একটি পৃষ্ঠার URL-এ যুক্ত করে।

history.replaceState(null, null, '/maze/' + connectionNumber)

ট্যাব সিঙ্ক সক্রিয় থাকলে, ইউআরএলটি কয়েক সেকেন্ড পরে সিঙ্ক হয় এবং একই পৃষ্ঠাটি মোবাইল ডিভাইসে খোলা যেতে পারে। মোবাইল ডিভাইসটি খোলা পৃষ্ঠার URL চেক করে, এবং যদি একটি নম্বর যুক্ত করা হয় তবে এটি অবিলম্বে সংযোগ করা শুরু করে। এটি ম্যানুয়ালি নম্বর লিখতে বা ক্যামেরা দিয়ে QR কোড স্ক্যান করার প্রয়োজনীয়তা দূর করে।

লেটেন্সি

যেহেতু রিলে সার্ভারটি মার্কিন যুক্তরাষ্ট্রে অবস্থিত, তাই জাপান থেকে এটি অ্যাক্সেস করার ফলে স্মার্টফোনের টিল্ট ডেটা পিসিতে পৌঁছানোর আগে প্রায় 200ms দেরি হয়৷ প্রতিক্রিয়ার সময়গুলি বিকাশের সময় ব্যবহৃত স্থানীয় পরিবেশের তুলনায় স্পষ্টতই মন্থর ছিল, তবে একটি লো-পাস ফিল্টার (আমি EMA ব্যবহার করেছি) এর মতো কিছু সন্নিবেশ করানো এটিকে বাধাহীন স্তরে উন্নত করেছে। (অভ্যাসগতভাবে, উপস্থাপনার উদ্দেশ্যেও একটি লো-পাস ফিল্টার প্রয়োজন ছিল; টিল্ট সেন্সর থেকে রিটার্ন মানগুলির মধ্যে যথেষ্ট পরিমাণে শব্দ ছিল, এবং সেই মানগুলিকে স্ক্রিনে প্রয়োগ করার ফলে প্রচুর ঝাঁকুনি হয়।) এটি হয়নি t জাম্পের সাথে কাজ করুন, যা স্পষ্টতই অলস ছিল, কিন্তু এটি সমাধান করার জন্য কিছুই করা যায়নি।

যেহেতু আমি শুরু থেকেই লেটেন্সি সমস্যাগুলি আশা করেছিলাম, তাই আমি বিশ্বজুড়ে রিলে সার্ভার সেট আপ করার কথা বিবেচনা করেছি যাতে ক্লায়েন্টরা সবচেয়ে কাছের উপলব্ধের সাথে সংযোগ করতে পারে (এইভাবে লেটেন্সি কম করে)। যাইহোক, আমি Google Compute Engine (GCE) ব্যবহার করে শেষ করেছি, যেটি তখন শুধুমাত্র মার্কিন যুক্তরাষ্ট্রে বিদ্যমান ছিল, তাই এটি সম্ভব ছিল না।

নাগেল অ্যালগরিদম সমস্যা

Nagle অ্যালগরিদমটি সাধারণত TCP স্তরে বাফারিংয়ের মাধ্যমে দক্ষ যোগাযোগের জন্য অপারেটিং সিস্টেমে অন্তর্ভুক্ত করা হয়, কিন্তু আমি দেখেছি যে এই অ্যালগরিদমটি সক্রিয় থাকাকালীন আমি রিয়েল টাইমে ডেটা পাঠাতে পারিনি৷ (বিশেষ করে যখন TCP বিলম্বিত স্বীকৃতির সাথে মিলিত হয়। এমনকি কোনো বিলম্বিত ACK না থাকলেও, সার্ভার বিদেশে অবস্থিত হওয়ার মতো কারণগুলির কারণে ACK একটি নির্দিষ্ট মাত্রায় বিলম্বিত হলে একই সমস্যা দেখা দেয়।)

নাগল লেটেন্সি সমস্যাটি Android-এর জন্য Chrome-এ WebSocket-এর সাথে ঘটেনি, যার মধ্যে Nagle অক্ষম করার জন্য TCP_NODELAY বিকল্প রয়েছে, কিন্তু এটি iOS-এর জন্য Chrome-এ ব্যবহৃত WebKit WebSocket-এর সাথে ঘটেছে, যাতে এই বিকল্পটি সক্ষম করা নেই। (সাফারি, যেটি একই ওয়েবকিট ব্যবহার করে, তারও এই সমস্যা ছিল৷ সমস্যাটি Google এর মাধ্যমে অ্যাপলকে জানানো হয়েছিল এবং দৃশ্যত ওয়েবকিটের বিকাশ সংস্করণে সমাধান করা হয়েছে

যখন এই সমস্যাটি দেখা দেয়, তখন প্রতি 100 ms এ পাঠানো টিল্ট ডেটা এমন অংশে একত্রিত হয় যা শুধুমাত্র প্রতি 500 ms এ পিসিতে পৌঁছায়। গেমটি এই অবস্থার অধীনে কাজ করতে পারে না, তাই এটি সার্ভার সাইডকে অল্প ব্যবধানে (প্রতি 50ms বা তার বেশি) ডেটা প্রেরণ করে এই বিলম্বতা এড়ায়। আমি বিশ্বাস করি যে অল্প ব্যবধানে ACK গ্রহণ করা নাগেল অ্যালগরিদমকে বোকা বানায় যে ডেটা পাঠানো ঠিক।

নাগেল অ্যালগরিদম ঘ

উপরের গ্রাফগুলি প্রাপ্ত প্রকৃত ডেটার ব্যবধানগুলিকে দেখায়৷ এটি প্যাকেটের মধ্যে সময়ের ব্যবধান নির্দেশ করে; সবুজ আউটপুট ব্যবধান প্রতিনিধিত্ব করে এবং লাল ইনপুট ব্যবধান প্রতিনিধিত্ব করে। সর্বনিম্ন 54ms, সর্বোচ্চ 158ms, এবং মাঝখানে 100ms এর কাছাকাছি। এখানে আমি জাপানে অবস্থিত একটি রিলে সার্ভার সহ একটি আইফোন ব্যবহার করেছি। আউটপুট এবং ইনপুট উভয়ই প্রায় 100ms, এবং অপারেশন মসৃণ।

নাগেল অ্যালগরিদম 2

বিপরীতে, এই গ্রাফটি মার্কিন যুক্তরাষ্ট্রে সার্ভার ব্যবহারের ফলাফল দেখায়। যদিও সবুজ আউটপুট ব্যবধান 100ms এ স্থির থাকে, ইনপুট ব্যবধান 0ms এর নিম্ন এবং 500ms এর মধ্যে ওঠানামা করে, যা নির্দেশ করে যে পিসি খণ্ডে ডেটা গ্রহণ করছে।

ALT_TEXT_HERE

অবশেষে, এই গ্রাফটি সার্ভারকে প্লেসহোল্ডার ডেটা পাঠানোর মাধ্যমে বিলম্বতা এড়ানোর ফলাফল দেখায়। যদিও এটি জাপানি সার্ভার ব্যবহার করে বেশ ভালোভাবে কাজ করে না, এটি স্পষ্ট যে ইনপুট ব্যবধানগুলি প্রায় 100ms এ তুলনামূলকভাবে স্থিতিশীল থাকে।

একটি বাগ?

Android 4 (ICS) এর ডিফল্ট ব্রাউজারে WebSocket API থাকা সত্ত্বেও, এটি সংযোগ করতে পারে না, যার ফলে একটি Socket.IO connect_failed ইভেন্ট হয়। অভ্যন্তরীণভাবে এটি সময় শেষ হয়, এবং সার্ভার সাইড একটি সংযোগ যাচাই করতে পারে না। (আমি একা WebSocket দিয়ে এটি পরীক্ষা করিনি, তাই এটি একটি Socket.IO সমস্যা হতে পারে।)

রিলে সার্ভার স্কেলিং

যেহেতু রিলে সার্ভারের ভূমিকা তেমন জটিল নয়, তাই যতক্ষণ আপনি নিশ্চিত করেন যে একই পিসি এবং মোবাইল ডিভাইস একই সার্ভারের সাথে সংযুক্ত থাকে ততক্ষণ পর্যন্ত সার্ভারের সংখ্যা বৃদ্ধি করা এবং সংখ্যা বৃদ্ধি করা কঠিন হবে না।

পদার্থবিদ্যা

ইন-গেম বল মুভমেন্ট (উতরাই ঘূর্ণায়মান, মাটির সাথে সংঘর্ষ, দেয়ালের সাথে সংঘর্ষ, আইটেম সংগ্রহ ইত্যাদি) সবই একটি 3D পদার্থবিদ্যা সিমুলেটর দিয়ে করা হয়। আমি Ammo.jsEmscripten ব্যবহার করে জাভাস্ক্রিপ্টে বহুল ব্যবহৃত বুলেট ফিজিক্স ইঞ্জিনের একটি পোর্ট — Physijs- এর সাথে এটিকে "ওয়েব ওয়ার্কার" হিসাবে ব্যবহার করেছি৷

ওয়েব কর্মী

Web Workers হল আলাদা থ্রেডে JavaScript চালানোর জন্য একটি API। জাভাস্ক্রিপ্ট একটি ওয়েব ওয়ার্কার হিসাবে চালু করা হয় একটি থ্রেড হিসাবে চলে যা মূলত এটিকে বলা হয়, তাই পৃষ্ঠাটিকে প্রতিক্রিয়াশীল রাখার সময় ভারী কাজগুলি সম্পাদন করা যেতে পারে। Physijs সাধারণত নিবিড় 3D পদার্থবিদ্যা ইঞ্জিনকে মসৃণভাবে চলতে সাহায্য করার জন্য দক্ষতার সাথে ওয়েব কর্মীদের ব্যবহার করে। World Wide Maze ফিজিক্স ইঞ্জিন এবং WebGL ইমেজ রেন্ডারিং সম্পূর্ণ ভিন্ন ফ্রেম রেটে পরিচালনা করে, তাই ভারী WebGL রেন্ডারিং লোডের কারণে কম-স্পেক মেশিনে ফ্রেম রেট কমে গেলেও, ফিজিক্স ইঞ্জিন নিজেই কমবেশি 60 fps রক্ষণাবেক্ষণ করবে এবং বাধা দেবে না। খেলা নিয়ন্ত্রণ।

FPS

এই চিত্রটি একটি Lenovo G570 এর ফলে ফ্রেম রেট দেখায়। উপরের বাক্সটি ওয়েবজিএল (চিত্র রেন্ডারিং) এর জন্য ফ্রেম রেট দেখায় এবং নীচেরটি পদার্থবিদ্যা ইঞ্জিনের ফ্রেম রেট দেখায়। GPU হল একটি ইন্টিগ্রেটেড ইন্টেল এইচডি গ্রাফিক্স 3000 চিপ, তাই ইমেজ রেন্ডারিং ফ্রেম রেট প্রত্যাশিত 60 fps অর্জন করতে পারেনি। যাইহোক, যেহেতু ফিজিক্স ইঞ্জিন প্রত্যাশিত ফ্রেম রেট অর্জন করেছে, তাই গেমপ্লেটি একটি হাই-স্পেক মেশিনের পারফরম্যান্স থেকে আলাদা নয়।

যেহেতু সক্রিয় ওয়েব ওয়ার্কারদের সাথে থ্রেডগুলিতে কনসোল অবজেক্ট থাকে না, তাই ডিবাগিং লগগুলি তৈরি করতে পোস্টমেসেজের মাধ্যমে ডেটা অবশ্যই মূল থ্রেডে পাঠাতে হবে। console4Worker ব্যবহার করে ওয়ার্কারে একটি কনসোল অবজেক্টের সমতুল্য তৈরি করে, যা ডিবাগিং প্রক্রিয়াটিকে উল্লেখযোগ্যভাবে সহজ করে তোলে।

সেবা কর্মীরা

ক্রোমের সাম্প্রতিক সংস্করণগুলি আপনাকে ওয়েব ওয়ার্কার্স চালু করার সময় ব্রেকপয়েন্ট সেট করার অনুমতি দেয়, যা ডিবাগিংয়ের জন্যও কার্যকর। এটি বিকাশকারী সরঞ্জামগুলিতে "শ্রমিক" প্যানেলে পাওয়া যাবে৷

কর্মক্ষমতা

উচ্চ বহুভুজ গণনা সহ পর্যায়গুলি কখনও কখনও 100,000 বহুভুজ অতিক্রম করে, কিন্তু কার্যকারিতা বিশেষভাবে ক্ষতিগ্রস্ত হয়নি এমনকি যখন সেগুলি সম্পূর্ণরূপে Physijs.ConcaveMesh ( btBvhTriangleMeshShape in Bullet) হিসাবে তৈরি করা হয়েছিল।

প্রাথমিকভাবে, সংঘর্ষ সনাক্তকরণের প্রয়োজনীয় বস্তুর সংখ্যা বৃদ্ধি পাওয়ায় ফ্রেমের হার কমে যায়, কিন্তু ফিজিজে অপ্রয়োজনীয় প্রক্রিয়াকরণ দূর করার ফলে কর্মক্ষমতা উন্নত হয়। এই উন্নতি মূল Physijs একটি কাঁটাচামচ করা হয়েছে.

ভূত বস্তু

যে বস্তুগুলির সংঘর্ষ সনাক্তকরণ আছে কিন্তু সংঘর্ষের উপর কোন প্রভাব নেই এবং এইভাবে অন্যান্য বস্তুর উপর কোন প্রভাব নেই তাদেরকে বুলেটে "ভূত বস্তু" বলা হয়। যদিও Physijs আনুষ্ঠানিকভাবে ভূতের বস্তুকে সমর্থন করে না, তবে Physijs.Mesh তৈরি করার পর পতাকা দিয়ে টিঙ্কার করে সেখানে তাদের তৈরি করা সম্ভব। ওয়ার্ল্ড ওয়াইড মেজ আইটেম এবং লক্ষ্য পয়েন্টগুলির সংঘর্ষ সনাক্তকরণের জন্য ভূত বস্তু ব্যবহার করে।

hit = new Physijs.SphereMesh(geometry, material, 0)
hit._physijs.collision_flags = 1 | 4
scene.add(hit)

collision_flags জন্য, 1 হল CF_STATIC_OBJECT , এবং 4 হল CF_NO_CONTACT_RESPONSE ৷ আরও তথ্যের জন্য বুলেট ফোরাম , স্ট্যাক ওভারফ্লো বা বুলেট ডকুমেন্টেশন অনুসন্ধান করার চেষ্টা করুন। যেহেতু Physijs হল Ammo.js এর জন্য একটি র‍্যাপার এবং Ammo.js মূলত বুলেটের সাথে অভিন্ন, তাই বেশিরভাগ জিনিস যা বুলেটে করা যায় তা Physijs-এও করা যেতে পারে।

ফায়ারফক্স 18 সমস্যা

17 থেকে 18 সংস্করণের ফায়ারফক্স আপডেটটি ওয়েব ওয়ার্কারদের ডেটা আদান-প্রদানের পদ্ধতি পরিবর্তন করেছে এবং এর ফলে ফিজিজ কাজ করা বন্ধ করে দিয়েছে। সমস্যাটি গিটহাবে রিপোর্ট করা হয়েছিল এবং কয়েক দিন পরে সমাধান করা হয়েছিল। যদিও এই ওপেন সোর্স দক্ষতা আমাকে মুগ্ধ করেছে, ঘটনাটি আমাকে মনে করিয়ে দিয়েছে যে কিভাবে ওয়ার্ল্ড ওয়াইড মেজ বিভিন্ন ওপেন সোর্স ফ্রেমওয়ার্কের সমন্বয়ে গঠিত। আমি কিছু ধরণের প্রতিক্রিয়া প্রদানের আশায় এই নিবন্ধটি লিখছি।

asm.js

যদিও এটি ওয়ার্ল্ড ওয়াইড মেজকে সরাসরি উদ্বেগজনক নয়, Ammo.js ইতিমধ্যেই Mozilla-এর সম্প্রতি ঘোষিত asm.js-কে সমর্থন করে (আশ্চর্যজনক নয় যেহেতু asm.js মূলত Emscripten দ্বারা জেনারেট করা জাভাস্ক্রিপ্টের গতি বাড়ানোর জন্য তৈরি করা হয়েছিল, এবং Emscripten-এর স্রষ্টাও এর নির্মাতা। Ammo.js)। যদি ক্রোম asm.jsও সমর্থন করে, তাহলে পদার্থবিদ্যা ইঞ্জিনের কম্পিউটিং লোড যথেষ্ট হ্রাস পাবে৷ ফায়ারফক্স নাইটলি দিয়ে পরীক্ষা করার সময় গতি লক্ষণীয়ভাবে দ্রুত ছিল। সম্ভবত C/C++-এ আরও গতির প্রয়োজন এমন বিভাগগুলি লিখতে এবং তারপর Emscripten ব্যবহার করে জাভাস্ক্রিপ্টে পোর্ট করা ভাল হবে?

ওয়েবজিএল

WebGL বাস্তবায়নের জন্য আমি সবচেয়ে সক্রিয়ভাবে বিকশিত লাইব্রেরি, three.js (r53) ব্যবহার করেছি। যদিও পুনর্বিবেচনা 57 ইতিমধ্যেই বিকাশের শেষ পর্যায়ে প্রকাশিত হয়েছিল, API-তে বড় পরিবর্তনগুলি করা হয়েছিল, তাই আমি মুক্তির জন্য মূল সংশোধনের সাথে আটকেছিলাম।

গ্লো প্রভাব

বলের কোরে এবং আইটেমগুলিতে যোগ করা গ্লো ইফেক্ট তথাকথিত " কাওয়াসে মেথড এমজিএফ " এর একটি সাধারণ সংস্করণ ব্যবহার করে প্রয়োগ করা হয়। যাইহোক, যখন Kawase পদ্ধতিটি সমস্ত উজ্জ্বল অঞ্চলগুলিকে প্রস্ফুটিত করে, ওয়ার্ল্ড ওয়াইড মেজ সেই অঞ্চলগুলির জন্য আলাদা রেন্ডার লক্ষ্য তৈরি করে যেগুলিকে আলোকিত করতে হবে৷ এর কারণ হল একটি ওয়েবসাইটের স্ক্রিনশট স্টেজ টেক্সচারের জন্য ব্যবহার করা আবশ্যক, এবং শুধুমাত্র সমস্ত উজ্জ্বল এলাকা বের করার ফলে পুরো ওয়েবসাইটটি উজ্জ্বল হয়ে উঠবে, উদাহরণস্বরূপ, যদি এটির একটি সাদা ব্যাকগ্রাউন্ড থাকে। আমি এইচডিআর-এ সবকিছু প্রক্রিয়াকরণের কথাও বিবেচনা করেছি, কিন্তু আমি এইবার এটির বিরুদ্ধে সিদ্ধান্ত নিয়েছি যেহেতু বাস্তবায়নটি বেশ জটিল হয়ে উঠত।

দীপ্তি

উপরের বাম দিকে প্রথম পাস দেখায়, যেখানে গ্লো এলাকাগুলি আলাদাভাবে রেন্ডার করা হয়েছিল এবং তারপরে একটি অস্পষ্টতা প্রয়োগ করা হয়েছিল৷ নীচের ডানদিকে দ্বিতীয় পাস দেখায়, যেখানে ছবির আকার 50% কমানো হয়েছে এবং তারপরে একটি অস্পষ্টতা প্রয়োগ করা হয়েছে। উপরের ডানদিকে তৃতীয় পাসটি দেখায়, যেখানে চিত্রটি আবার 50% কমিয়ে তারপর ঝাপসা করা হয়েছে। তারপরে নীচে বাম দিকে দেখানো চূড়ান্ত যৌগিক চিত্র তৈরি করতে তিনটিকে ওভারলেড করা হয়েছিল। অস্পষ্টতার জন্য আমি তিন.js-এ অন্তর্ভুক্ত VerticalBlurShader এবং HorizontalBlurShader ব্যবহার করেছি, তাই আরও অপ্টিমাইজেশনের জন্য এখনও জায়গা রয়েছে।

প্রতিফলিত বল

বলের প্রতিফলন থ্রি.জেএস থেকে প্রাপ্ত নমুনার উপর ভিত্তি করে। সমস্ত দিকনির্দেশ বলের অবস্থান থেকে রেন্ডার করা হয় এবং পরিবেশের মানচিত্র হিসাবে ব্যবহৃত হয়। প্রতিবার বল নড়াচড়া করার সময় পরিবেশের মানচিত্রগুলি আপডেট করা প্রয়োজন, কিন্তু যেহেতু 60 fps-এ আপডেট করা নিবিড়, সেগুলি পরিবর্তে প্রতি তিনটি ফ্রেমে আপডেট করা হয়। ফলাফলটি প্রতিটি ফ্রেম আপডেট করার মতো মসৃণ নয়, তবে উল্লেখ না করা পর্যন্ত পার্থক্যটি কার্যত অদৃশ্য।

শেডার, শেডার, শেডার…

WebGL-এর সমস্ত রেন্ডারিংয়ের জন্য শেডার (ভার্টেক্স শেডার, ফ্র্যাগমেন্ট শেডার) প্রয়োজন। যদিও three.js-এ অন্তর্ভুক্ত শেডারগুলি ইতিমধ্যেই বিস্তৃত প্রভাবের জন্য অনুমতি দেয়, আরও বিস্তৃত ছায়া এবং অপ্টিমাইজেশনের জন্য আপনার নিজের লেখা অনিবার্য৷ যেহেতু ওয়ার্ল্ড ওয়াইড মেজ সিপিইউকে তার ফিজিক্স ইঞ্জিনে ব্যস্ত রাখে, তাই আমি যতটা সম্ভব শেডিং ল্যাঙ্গুয়েজ (জিএলএসএল) লিখে জিপিইউ ব্যবহার করার চেষ্টা করেছি, এমনকি যখন সিপিইউ প্রসেসিং (জাভাস্ক্রিপ্টের মাধ্যমে) সহজ হতো। সাগরের তরঙ্গের প্রভাবগুলি শেডারের উপর নির্ভর করে, স্বাভাবিকভাবেই, যেমন গোল পয়েন্টে আতশবাজি এবং বলটি উপস্থিত হওয়ার সময় ব্যবহৃত জাল প্রভাব।

শেডার বল

উপরেরটি বলটি উপস্থিত হওয়ার সময় ব্যবহৃত জাল প্রভাবের পরীক্ষা থেকে। বাম দিকের একটি হল 320টি বহুভুজ দ্বারা গঠিত একটি ইন-গেমে ব্যবহৃত। কেন্দ্রের একটিটি প্রায় 5,000 বহুভুজ ব্যবহার করে এবং ডানদিকেরটি প্রায় 300,000 বহুভুজ ব্যবহার করে৷ এমনকি এই বহু বহুভুজ সহ, শেডারগুলির সাথে প্রক্রিয়াকরণ 30 fps এর একটি স্থির ফ্রেম রেট রাখতে পারে।

শেডের জাল

স্টেজ জুড়ে ছড়িয়ে ছিটিয়ে থাকা ছোট আইটেমগুলি সবই এক জালের মধ্যে একত্রিত হয়, এবং স্বতন্ত্র আন্দোলন প্রতিটি বহুভুজ টিপসকে সরানো শেডারের উপর নির্ভর করে। প্রচুর পরিমাণে বস্তু উপস্থিত থাকলে কর্মক্ষমতা ক্ষতিগ্রস্থ হবে কিনা তা দেখার জন্য এটি একটি পরীক্ষা থেকে। প্রায় 20,000টি বহুভুজ নিয়ে গঠিত প্রায় 5,000টি বস্তু এখানে রাখা হয়েছে। পারফরম্যান্স মোটেও ক্ষতিগ্রস্থ হয়নি।

poly2tri

পর্যায়গুলি সার্ভার থেকে প্রাপ্ত রূপরেখা তথ্যের উপর ভিত্তি করে গঠিত হয় এবং তারপর জাভাস্ক্রিপ্ট দ্বারা বহুভুজ করা হয়। ত্রিভুজকরণ, এই প্রক্রিয়ার একটি মূল অংশ, three.js দ্বারা খারাপভাবে প্রয়োগ করা হয় এবং সাধারণত ব্যর্থ হয়। তাই আমি নিজে পলি2ট্রি নামে একটি ভিন্ন ত্রিভুজ লাইব্রেরি সংহত করার সিদ্ধান্ত নিয়েছি। এটি সক্রিয় আউট হিসাবে, three.js স্পষ্টতই অতীতে একই জিনিস চেষ্টা করেছিল, তাই আমি এটির কিছু অংশ মন্তব্য করে এটিকে কাজ করতে পেরেছি। ত্রুটিগুলি উল্লেখযোগ্যভাবে কমে গেছে ফলস্বরূপ, আরও অনেকগুলি খেলার যোগ্য পর্যায়ের অনুমতি দেয়৷ মাঝে মাঝে ত্রুটি অব্যাহত থাকে, এবং কিছু কারণে poly2tri সতর্কতা জারি করে ত্রুটিগুলি পরিচালনা করে, তাই আমি পরিবর্তে ব্যতিক্রমগুলি নিক্ষেপ করার জন্য এটি সংশোধন করেছি।

poly2tri

উপরেরটি দেখায় কিভাবে নীল রূপরেখা ত্রিভুজাকার এবং লাল বহুভুজ তৈরি হয়।

একটি ধারনার পরিশোধন

যেহেতু স্ট্যান্ডার্ড আইসোট্রপিক এমআইপি ম্যাপিং অনুভূমিক এবং উল্লম্ব উভয় অক্ষের চিত্রগুলিকে ছোট করে, তাই তির্যক কোণ থেকে বহুভুজ দেখার ফলে ওয়ার্ল্ড ওয়াইড মেজ স্টেজের শেষ প্রান্তে টেক্সচারগুলি অনুভূমিকভাবে দীর্ঘায়িত, কম-রেজোলিউশনের টেক্সচারের মতো দেখায়। এই উইকিপিডিয়া পৃষ্ঠার উপরের ডানদিকে চিত্রটি এর একটি ভাল উদাহরণ দেখায়। অনুশীলনে, আরও অনুভূমিক রেজোলিউশন প্রয়োজন, যা ওয়েবজিএল (ওপেনজিএল) অ্যানিসোট্রপিক ফিল্টারিং নামক একটি পদ্ধতি ব্যবহার করে সমাধান করে। three.js-এ, THREE.Texture.anisotropy এর জন্য 1-এর বেশি একটি মান সেট করা অ্যানিসোট্রপিক ফিল্টারিং সক্ষম করে। যাইহোক, এই বৈশিষ্ট্যটি একটি এক্সটেনশন এবং সমস্ত GPU দ্বারা সমর্থিত নাও হতে পারে৷

অপ্টিমাইজ করুন

এই WebGL সর্বোত্তম অনুশীলন নিবন্ধটিও উল্লেখ করে, WebGL (OpenGL) কর্মক্ষমতা উন্নত করার সবচেয়ে গুরুত্বপূর্ণ উপায় হল ড্র কলগুলিকে কম করা। ওয়ার্ল্ড ওয়াইড মেজের প্রাথমিক বিকাশের সময়, সমস্ত ইন-গেম দ্বীপ, সেতু এবং গার্ড রেলগুলি আলাদা বস্তু ছিল। এর ফলে কখনও কখনও 2,000 টিরও বেশি ড্র কল হয়, যা জটিল পর্যায়গুলিকে অবাধ্য করে তোলে। যাইহোক, একবার আমি একই ধরণের অবজেক্টগুলিকে এক জালে প্যাক করে ফেললে, ড্র কলগুলি পঞ্চাশ বা তার বেশি হয়ে যায়, কার্যক্ষমতা উল্লেখযোগ্যভাবে উন্নত হয়।

আমি আরও অপ্টিমাইজেশানের জন্য Chrome ট্রেসিং বৈশিষ্ট্যটি ব্যবহার করেছি। ক্রোমের বিকাশকারী সরঞ্জামগুলিতে অন্তর্ভুক্ত প্রোফাইলাররা সামগ্রিক পদ্ধতির প্রক্রিয়াকরণের সময়গুলি কিছু ডিগ্রি নির্ধারণ করতে পারে, তবে ট্রেসিং আপনাকে সঠিকভাবে বলতে পারে যে প্রতিটি অংশ কত সময় নেয়, সেকেন্ডের 1/1000তম পর্যন্ত। কীভাবে ট্রেসিং ব্যবহার করবেন তার বিশদ বিবরণের জন্য এই নিবন্ধটি দেখুন।

অপ্টিমাইজেশান

উপরেরটি বলের প্রতিফলনের জন্য পরিবেশের মানচিত্র তৈরির ফলাফলগুলি। console.time এবং console.timeEnd তিন.js-এ আপাতদৃষ্টিতে প্রাসঙ্গিক অবস্থানে ঢোকানো আমাদের একটি গ্রাফ দেয় যা দেখতে এইরকম। সময় বাম থেকে ডানে প্রবাহিত হয়, এবং প্রতিটি স্তর একটি কল স্ট্যাকের মত কিছু। একটি console.time একটি console.time এর মধ্যে নেস্ট করা আরও পরিমাপের অনুমতি দেয়৷ উপরের গ্রাফটি প্রাক-অপ্টিমাইজেশান এবং নীচেরটি পোস্ট-অপ্টিমাইজেশন। উপরের গ্রাফটি দেখায়, প্রাক-অপ্টিমাইজেশনের সময় 0-5 রেন্ডারগুলির প্রতিটির জন্য updateMatrix (যদিও শব্দটি ছোট করা হয়েছে) বলা হয়েছিল। আমি এটি সংশোধন করেছি যাতে এটি শুধুমাত্র একবার বলা হয়, তবে, এই প্রক্রিয়াটি তখনই প্রয়োজন যখন বস্তুর অবস্থান বা অভিযোজন পরিবর্তন হয়।

ট্রেসিং প্রক্রিয়া নিজেই সম্পদ গ্রহণ করে, স্বাভাবিকভাবেই, তাই অতিরিক্তভাবে console.time ঢোকানো প্রকৃত কর্মক্ষমতা থেকে একটি উল্লেখযোগ্য বিচ্যুতি ঘটাতে পারে, অপ্টিমাইজেশনের জন্য ক্ষেত্রগুলি চিহ্নিত করা কঠিন করে তোলে।

কর্মক্ষমতা সমন্বয়কারী

ইন্টারনেটের প্রকৃতির কারণে, গেমটি সম্ভবত ব্যাপকভাবে পরিবর্তিত চশমা সহ সিস্টেমে খেলা হবে। ফাইন্ড ইওর ওয়ে টু অজ , ফেব্রুয়ারির শুরুতে প্রকাশিত হয়েছে, ফ্রেম রেট ওঠানামা অনুযায়ী IFLAutomaticPerformanceAdjust পারফরমেন্স অ্যাডজাস্ট নামক একটি ক্লাস ব্যবহার করে, যা মসৃণ প্লেব্যাক নিশ্চিত করতে সাহায্য করে। World Wide Maze একই IFLAutomaticPerformanceAdjust ক্লাসের উপর তৈরি করে এবং গেমপ্লেকে যথাসম্ভব মসৃণ করতে নিম্নলিখিত ক্রমে প্রভাবগুলিকে স্কেল করে:

  1. ফ্রেম রেট 45 fps এর নিচে নেমে গেলে, পরিবেশ মানচিত্র আপডেট হওয়া বন্ধ করে দেয়।
  2. যদি এটি এখনও 40 fps-এর নিচে নেমে যায়, রেন্ডারিং রেজোলিউশন 70% (সারফেস রেশিওর 50%) এ কমে যায়।
  3. যদি এটি এখনও 40 fps এর নিচে নেমে আসে, FXAA (অ্যান্টি-আলিয়াসিং) বাদ দেওয়া হয়।
  4. যদি এটি এখনও 30 fps-এর নিচে নেমে আসে, তাহলে গ্লো ইফেক্ট বাদ দেওয়া হয়।

মেমরি লিক

বস্তুকে সুন্দরভাবে নির্মূল করা তিন.js-এর সাথে এক ধরণের ঝামেলার মতো। কিন্তু তাদের একা রেখে যাওয়া স্পষ্টতই মেমরি ফাঁসের দিকে পরিচালিত করবে, তাই আমি নীচের পদ্ধতিটি তৈরি করেছি। @renderer বলতে THREE.WebGLRenderer বোঝায়। (3.js-এর সর্বশেষ সংশোধনটি ডিললোকেশনের একটি সামান্য ভিন্ন পদ্ধতি ব্যবহার করে, তাই এটি সম্ভবত এটির সাথে কাজ করবে না।)

destructObjects: (object) =>
  switch true
    when object instanceof THREE.Object3D
      @destructObjects(child) for child in object.children
      object.parent?.remove(object)
      object.deallocate()
      object.geometry?.deallocate()
      @renderer.deallocateObject(object)
      object.destruct?(this)

    when object instanceof THREE.Material
      object.deallocate()
      @renderer.deallocateMaterial(object)

    when object instanceof THREE.Texture
      object.deallocate()
      @renderer.deallocateTexture(object)

    when object instanceof THREE.EffectComposer
      @destructObjects(object.copyPass.material)
      object.passes.forEach (pass) =>
        @destructObjects(pass.material) if pass.material
        @renderer.deallocateRenderTarget(pass.renderTarget) if pass.renderTarget
        @renderer.deallocateRenderTarget(pass.renderTarget1) if pass.renderTarget1
        @renderer.deallocateRenderTarget(pass.renderTarget2) if pass.renderTarget2

এইচটিএমএল

ব্যক্তিগতভাবে, আমি মনে করি WebGL অ্যাপের সবচেয়ে ভালো জিনিস হল HTML-এ পৃষ্ঠা লেআউট ডিজাইন করার ক্ষমতা। ফ্ল্যাশ বা ওপেনফ্রেমওয়ার্কস (ওপেনজিএল) এ স্কোর বা পাঠ্য প্রদর্শনের মতো 2D ইন্টারফেস তৈরি করা এক ধরণের ব্যথা। ফ্ল্যাশের অন্তত একটি আইডিই আছে, তবে ওপেনফ্রেমওয়ার্কগুলি কঠিন যদি আপনি এটিতে অভ্যস্ত না হন (কোকোস 2 ডি এর মতো কিছু ব্যবহার করা এটিকে সহজ করে তুলতে পারে)। অন্যদিকে, এইচটিএমএল, ওয়েবসাইট তৈরি করার সময়, সিএসএসের সাথে সমস্ত ফ্রন্টএন্ড ডিজাইনের দিকগুলির সুনির্দিষ্ট নিয়ন্ত্রণের অনুমতি দেয়। যদিও জটিল প্রভাব যেমন একটি লোগোতে কণা ঘনীভূত করা অসম্ভব, CSS ট্রান্সফর্মের ক্ষমতার মধ্যে কিছু 3D প্রভাব সম্ভব। ওয়ার্ল্ড ওয়াইড মেজের "গোল" এবং "টাইম ইজ আপ" পাঠ্য প্রভাবগুলি সিএসএস ট্রানজিশনে স্কেল ব্যবহার করে অ্যানিমেটেড করা হয়েছে ( ট্রানজিটের সাথে বাস্তবায়িত)। (স্পষ্টতই ব্যাকগ্রাউন্ড গ্রেডেশন WebGL ব্যবহার করে।)

গেমের প্রতিটি পৃষ্ঠার (শিরোনাম, ফলাফল, র‍্যাঙ্কিং, ইত্যাদি) নিজস্ব HTML ফাইল রয়েছে এবং একবার এগুলি টেমপ্লেট হিসাবে লোড হয়ে গেলে, $(document.body).append() উপযুক্ত সময়ে উপযুক্ত মান সহ কল ​​করা হয়। . একটি হেঁচকি ছিল যে মাউস এবং কীবোর্ড ইভেন্টগুলি যোগ করার আগে সেট করা যায় না, তাই যোগ করার আগে el.click (e) -> console.log(e) চেষ্টা করা কাজ করেনি।

আন্তর্জাতিকীকরণ (i18n)

ইংরেজি ভাষার সংস্করণ তৈরি করার জন্য HTML-এ কাজ করাও সুবিধাজনক ছিল। আমি আমার আন্তর্জাতিকীকরণের প্রয়োজনের জন্য i18next , একটি ওয়েব i18n লাইব্রেরি ব্যবহার করতে বেছে নিয়েছি, যা আমি পরিবর্তন ছাড়াই ব্যবহার করতে পেরেছি।

ইন-গেম পাঠ্যের সম্পাদনা এবং অনুবাদ Google ডক্স স্প্রেডশীটে করা হয়েছিল। যেহেতু i18next-এর জন্য JSON ফাইলের প্রয়োজন, তাই আমি স্প্রেডশীটগুলি TSV-এ রপ্তানি করেছি এবং তারপর একটি কাস্টম রূপান্তরকারীর সাথে রূপান্তর করেছি৷ আমি প্রকাশের ঠিক আগে অনেক আপডেট করেছি, তাই Google ডক্স স্প্রেডশীট থেকে রপ্তানি প্রক্রিয়া স্বয়ংক্রিয়ভাবে কাজগুলিকে আরও সহজ করে তুলত৷

Chrome এর স্বয়ংক্রিয় অনুবাদ বৈশিষ্ট্যটিও সাধারণত কাজ করে যেহেতু পৃষ্ঠাগুলি HTML দিয়ে তৈরি করা হয়৷ যাইহোক, এটি কখনও কখনও সঠিকভাবে ভাষা সনাক্ত করতে ব্যর্থ হয়, পরিবর্তে এটিকে সম্পূর্ণ ভিন্ন (যেমন, ভিয়েতনামী) বলে ভুল করে, তাই এই বৈশিষ্ট্যটি বর্তমানে অক্ষম করা হয়েছে। ( এটি মেটা ট্যাগ ব্যবহার করে নিষ্ক্রিয় করা যেতে পারে ।)

JS প্রয়োজন

আমি আমার জাভাস্ক্রিপ্ট মডিউল সিস্টেম হিসাবে RequireJS বেছে নিয়েছি। গেমটির সোর্স কোডের 10,000 লাইনগুলিকে প্রায় 60টি ক্লাসে (= কফি ফাইল) ভাগ করা হয়েছে এবং পৃথক js ফাইলগুলিতে কম্পাইল করা হয়েছে। RequireJS নির্ভরতার উপর ভিত্তি করে উপযুক্ত ক্রমে এই পৃথক ফাইলগুলিকে লোড করে।

define ->
  class Hoge
    hogeMethod: ->

উপরে সংজ্ঞায়িত ক্লাস (hoge.coffee) নিম্নলিখিত হিসাবে ব্যবহার করা যেতে পারে:

define ['hoge'], (Hoge) ->
  class Moge
    constructor: ->
      @hoge = new Hoge()
      @hoge.hogeMethod()

কাজ করার জন্য, hoge.js কে অবশ্যই moge.js এর আগে লোড করতে হবে এবং যেহেতু "hoge" কে "define" এর প্রথম আর্গুমেন্ট হিসাবে মনোনীত করা হয়েছে, তাই hoge.js সর্বদা প্রথমে লোড করা হয় (hoge.js লোড করার পরে আবার বলা হয়)। এই প্রক্রিয়াটিকে AMD বলা হয়, এবং যেকোন তৃতীয় পক্ষের লাইব্রেরিটি একই ধরনের কলব্যাকের জন্য ব্যবহার করা যেতে পারে যতক্ষণ না এটি AMD সমর্থন করে। এমনকি যারা (যেমন, three.js) করে না তারাও একইভাবে কাজ করবে যতক্ষণ না d নির্ভরতা আগে থেকে নির্দিষ্ট করা থাকে

এটি AS3 আমদানির অনুরূপ, তাই এটি অদ্ভুত বলে মনে করা উচিত নয়। আপনি যদি আরও নির্ভরশীল ফাইলের সাথে শেষ করেন তবে এটি একটি সম্ভাব্য সমাধান।

r.js

RequireJS-এ r.js নামে একটি অপ্টিমাইজার রয়েছে। এটি প্রধান js কে সমস্ত নির্ভরশীল js ফাইলের সাথে একত্রিত করে, তারপর UglifyJS (বা ক্লোজার কম্পাইলার) ব্যবহার করে এটিকে ছোট করে। এটি ফাইলের সংখ্যা এবং ব্রাউজারকে লোড করার জন্য প্রয়োজনীয় ডেটার মোট পরিমাণ হ্রাস করে। ওয়ার্ল্ড ওয়াইড মেজ-এর জন্য মোট জাভাস্ক্রিপ্ট ফাইলের আকার প্রায় 2 এমবি এবং r.js অপ্টিমাইজেশানের সাথে প্রায় 1 MB পর্যন্ত কমানো যেতে পারে। যদি জিজিপ ব্যবহার করে গেমটি বিতরণ করা যায় তবে এটি আরও 250 কেবিতে হ্রাস পাবে। (GAE-এর একটি সমস্যা রয়েছে যা 1 MB বা তার চেয়ে বড় ফাইলগুলিকে ট্রান্সমিশনের অনুমতি দেবে না, তাই গেমটি বর্তমানে 1 MB প্লেইন টেক্সট হিসাবে অসঙ্কোচিতভাবে বিতরণ করা হয়েছে।)

মঞ্চ নির্মাতা

স্টেজ ডেটা নিম্নরূপ তৈরি করা হয়, যা সম্পূর্ণরূপে মার্কিন যুক্তরাষ্ট্রের GCE সার্ভারে সম্পাদিত হয়:

  1. একটি স্টেজে রূপান্তরিত করা ওয়েবসাইটের URL WebSocket এর মাধ্যমে পাঠানো হয়।
  2. PhantomJS একটি স্ক্রিনশট নেয়, এবং div এবং img ট্যাগের অবস্থানগুলি পুনরুদ্ধার করা হয় এবং JSON ফর্ম্যাটে আউটপুট করা হয়।
  3. স্টেপ 2 থেকে স্ক্রিনশট এবং HTML উপাদানের পজিশনিং ডেটার উপর ভিত্তি করে, একটি কাস্টম C++ (OpenCV, Boost) প্রোগ্রাম অপ্রয়োজনীয় এলাকা মুছে দেয়, দ্বীপ তৈরি করে, দ্বীপগুলিকে সেতুর সাথে সংযুক্ত করে, গার্ড রেল এবং আইটেমের অবস্থান গণনা করে, লক্ষ্য পয়েন্ট সেট করে ইত্যাদি। ফলাফলগুলি JSON ফর্ম্যাটে আউটপুট হয় এবং ব্রাউজারে ফিরে আসে।

ফ্যান্টমজেএস

ফ্যান্টমজেএস এমন একটি ব্রাউজার যার জন্য কোনও স্ক্রিন প্রয়োজন হয় না। এটি উইন্ডোজ খোলা ছাড়াই ওয়েব পৃষ্ঠাগুলি লোড করতে পারে, তাই এটি স্বয়ংক্রিয় পরীক্ষায় বা সার্ভারের পাশে স্ক্রিনশট ক্যাপচার করতে ব্যবহার করা যেতে পারে। এর ব্রাউজার ইঞ্জিন হল ওয়েবকিট, ক্রোম এবং সাফারি দ্বারা ব্যবহৃত একই, তাই এর লেআউট এবং জাভাস্ক্রিপ্ট এক্সিকিউশন ফলাফলগুলিও কমবেশি স্ট্যান্ডার্ড ব্রাউজারগুলির মতোই।

ফ্যান্টমজেএস এর সাথে, জাভাস্ক্রিপ্ট বা কফিস্ক্রিপ্ট ব্যবহার করা হয় আপনি যে প্রসেসগুলি চালাতে চান তা লিখতে। স্ক্রিনশট ক্যাপচার করা খুবই সহজ, যেমনটি এই নমুনায় দেখানো হয়েছে। আমি একটি লিনাক্স সার্ভারে (CentOS) কাজ করছিলাম, তাই আমাকে জাপানি ( M+ FONTS ) প্রদর্শনের জন্য ফন্ট ইনস্টল করতে হবে। তারপরেও, উইন্ডোজ বা ম্যাক ওএসের তুলনায় ফন্ট রেন্ডারিং ভিন্নভাবে পরিচালনা করা হয়, তাই একই ফন্ট অন্যান্য মেশিনে ভিন্ন দেখতে পারে (যদিও পার্থক্যটি ন্যূনতম)।

img এবং div ট্যাগ পজিশন পুনরুদ্ধার করা মূলত স্ট্যান্ডার্ড পৃষ্ঠাগুলির মতোই পরিচালনা করা হয়। jQuery কোনো সমস্যা ছাড়াই ব্যবহার করা যেতে পারে।

মঞ্চ_নির্মাতা

আমি প্রাথমিকভাবে ধাপগুলি তৈরি করার জন্য আরও DOM-ভিত্তিক পদ্ধতির ব্যবহার বিবেচনা করেছিলাম ( Firefox 3D Inspector এর মতো) এবং ফ্যান্টমজেএস-এ DOM বিশ্লেষণের মতো কিছু করার চেষ্টা করেছি। শেষ পর্যন্ত, যদিও, আমি একটি চিত্র প্রক্রিয়াকরণ পদ্ধতিতে স্থির হয়েছি। এই লক্ষ্যে আমি একটি C++ প্রোগ্রাম লিখেছিলাম যা OpenCV এবং বুস্ট ব্যবহার করে "stage_builder"। এটি নিম্নলিখিত কাজ করে:

  1. স্ক্রিনশট এবং JSON ফাইল(গুলি) লোড করে।
  2. ছবি এবং পাঠ্যকে "দ্বীপে" রূপান্তর করে।
  3. দ্বীপগুলিকে সংযুক্ত করার জন্য সেতু তৈরি করে।
  4. একটি গোলকধাঁধা তৈরি করতে অপ্রয়োজনীয় সেতু দূর করে।
  5. বড় আইটেম রাখে।
  6. ছোট আইটেম রাখে।
  7. গার্ড রেল স্থাপন.
  8. JSON ফর্ম্যাটে পজিশনিং ডেটা আউটপুট করে।

প্রতিটি ধাপ নিচে বিস্তারিত আছে।

স্ক্রিনশট এবং JSON ফাইল(গুলি) লোড হচ্ছে

সাধারণ cv::imread স্ক্রিনশট লোড করতে ব্যবহৃত হয়। আমি JSON ফাইলগুলির জন্য বেশ কয়েকটি লাইব্রেরি পরীক্ষা করেছি, কিন্তু পিকোজসন এর সাথে কাজ করা সবচেয়ে সহজ বলে মনে হয়েছিল।

ছবি এবং পাঠ্যকে "দ্বীপে" রূপান্তর করা হচ্ছে

মঞ্চ নির্মাণ

উপরেরটি aid-dcc.com এর সংবাদ বিভাগের একটি স্ক্রিনশট (প্রকৃত আকার দেখতে ক্লিক করুন)। ছবি এবং টেক্সট উপাদান দ্বীপে রূপান্তর করা আবশ্যক. এই বিভাগগুলিকে বিচ্ছিন্ন করার জন্য, আমাদের সাদা পটভূমির রঙটি মুছে ফেলা উচিত - অন্য কথায় স্ক্রিনশটের সবচেয়ে প্রচলিত রঙ। একবার এটি সম্পন্ন হলে এটি দেখতে কেমন তা এখানে রয়েছে:

মঞ্চ নির্মাণ

সাদা অংশগুলি সম্ভাব্য দ্বীপ।

লেখাটি খুবই সূক্ষ্ম এবং ধারালো, তাই আমরা এটিকে cv::dilate , cv::GaussianBlur , এবং cv::threshold দিয়ে ঘন করব। ছবির বিষয়বস্তুও অনুপস্থিত, তাই PhantomJS থেকে img ট্যাগ ডেটা আউটপুটের উপর ভিত্তি করে আমরা সেই জায়গাগুলিকে সাদা দিয়ে পূরণ করব। ফলস্বরূপ চিত্রটি এইরকম দেখাচ্ছে:

মঞ্চ নির্মাণ

টেক্সট এখন উপযুক্ত গুচ্ছ গঠন করে, এবং প্রতিটি চিত্র একটি সঠিক দ্বীপ।

দ্বীপগুলোকে সংযুক্ত করার জন্য সেতু তৈরি করা

দ্বীপগুলি প্রস্তুত হয়ে গেলে, সেগুলি সেতুগুলির সাথে সংযুক্ত করা হয়। প্রতিটি দ্বীপ বামে, ডানে, উপরে এবং নীচে সংলগ্ন দ্বীপগুলির সন্ধান করে, তারপরে একটি সেতুকে নিকটতম দ্বীপের নিকটতম বিন্দুতে সংযুক্ত করে, যার ফলস্বরূপ এরকম কিছু হয়:

মঞ্চ নির্মাণ

একটি গোলকধাঁধা তৈরি করতে অপ্রয়োজনীয় সেতু দূর করা

সমস্ত সেতু রাখা মঞ্চটি নেভিগেট করা খুব সহজ করে তুলবে, তাই কিছু একটি গোলকধাঁধা তৈরি করতে অবশ্যই বাদ দিতে হবে। একটি দ্বীপ (উদাহরণস্বরূপ, উপরের বাম দিকের একটি) একটি সূচনা বিন্দু হিসাবে বেছে নেওয়া হয়েছে এবং সেই দ্বীপের সাথে সংযোগকারী একটি সেতু (এলোমেলোভাবে নির্বাচিত) বাদে সমস্ত মুছে ফেলা হয়েছে৷ তারপর অবশিষ্ট সেতু দ্বারা সংযুক্ত পরবর্তী দ্বীপের জন্য একই জিনিস করা হয়। একবার পথটি একটি শেষ প্রান্তে পৌঁছে গেলে বা পূর্বে পরিদর্শন করা দ্বীপে ফিরে গেলে, এটি এমন একটি বিন্দুতে ফিরে যায় যা একটি নতুন দ্বীপে প্রবেশের অনুমতি দেয়। সমস্ত দ্বীপ এইভাবে প্রক্রিয়া করা হলে গোলকধাঁধাটি সম্পন্ন হয়।

মঞ্চ নির্মাণ

বড় আইটেম স্থাপন

প্রতিটি দ্বীপে এক বা একাধিক বড় আইটেম স্থাপন করা হয় তার মাত্রার উপর নির্ভর করে, দ্বীপের প্রান্ত থেকে সবচেয়ে দূরে থাকা পয়েন্টগুলি থেকে বেছে নিয়ে। যদিও খুব স্পষ্ট নয়, এই পয়েন্টগুলি নীচে লাল রঙে দেখানো হয়েছে:

মঞ্চ নির্মাণ

এই সমস্ত সম্ভাব্য বিন্দু থেকে, উপরের বাম দিকের একটি সূচনা বিন্দু (লাল বৃত্ত) হিসাবে সেট করা হয়েছে, নীচে ডানদিকে একটি লক্ষ্য হিসাবে সেট করা হয়েছে (সবুজ বৃত্ত), এবং বাকিগুলির মধ্যে সর্বাধিক ছয়টি বড় জন্য বেছে নেওয়া হয়েছে আইটেম বসানো (বেগুনি বৃত্ত)।

ছোট আইটেম স্থাপন

মঞ্চ নির্মাণ

দ্বীপের প্রান্ত থেকে নির্দিষ্ট দূরত্বে লাইন বরাবর উপযুক্ত সংখ্যক ছোট আইটেম স্থাপন করা হয়। উপরের ছবিটি (aid-dcc.com থেকে নয়) ধূসর, অফসেট এবং দ্বীপের প্রান্ত থেকে নিয়মিত বিরতিতে প্রজেক্টেড প্লেসমেন্ট লাইন দেখায়। লাল বিন্দুগুলি নির্দেশ করে যে ছোট আইটেমগুলি কোথায় রাখা হয়েছে। যেহেতু এই চিত্রটি একটি মধ্য-উন্নয়ন সংস্করণ থেকে এসেছে, তাই আইটেমগুলিকে সরল রেখায় রাখা হয়েছে, কিন্তু চূড়ান্ত সংস্করণটি ধূসর রেখার উভয় পাশে একটু বেশি অনিয়মিতভাবে আইটেমগুলিকে ছড়িয়ে দেয়৷

গার্ড রেল স্থাপন

গার্ড রেলগুলি মূলত দ্বীপগুলির বাইরের সীমানা বরাবর স্থাপন করা হয় তবে অ্যাক্সেসের অনুমতি দেওয়ার জন্য সেতুগুলিতে অবশ্যই কেটে ফেলতে হবে। বুস্ট জ্যামিতি লাইব্রেরি এটির জন্য উপযোগী প্রমাণিত হয়েছে, জ্যামিতিক গণনাকে সরল করেছে যেমন দ্বীপের সীমানা ডেটা সেতুর উভয় পাশের লাইনের সাথে কোথায় ছেদ করে তা নির্ধারণ করা।

মঞ্চ নির্মাণ

দ্বীপগুলির রূপরেখার সবুজ রেখাগুলি হল গার্ড রেল। এই ছবিতে দেখা কঠিন হতে পারে, কিন্তু যেখানে সেতুগুলো আছে সেখানে সবুজ লাইন নেই। এটি ডিবাগিংয়ের জন্য ব্যবহৃত চূড়ান্ত চিত্র, যেখানে JSON-এ আউটপুট করতে হবে এমন সমস্ত বস্তু অন্তর্ভুক্ত করা হয়েছে। হালকা নীল বিন্দুগুলি হল ছোট আইটেম, এবং ধূসর বিন্দুগুলি পুনরায় শুরু করার বিন্দু প্রস্তাবিত। যখন বলটি সাগরে পড়ে, তখন খেলাটি নিকটতম রিস্টার্টিং পয়েন্ট থেকে পুনরায় শুরু হয়। দ্বীপের প্রান্ত থেকে একটি নির্দিষ্ট দূরত্বে নিয়মিত বিরতিতে ছোট আইটেমগুলি একইভাবে পুনঃসূচনা পয়েন্টগুলি কমবেশি সাজানো হয়।

JSON বিন্যাসে পজিশনিং ডেটা আউটপুট করা

আমি আউটপুটের জন্য পিকোজসনও ব্যবহার করেছি। এটি স্ট্যান্ডার্ড আউটপুটে ডেটা লেখে, যা তারপর কলার (Node.js) দ্বারা প্রাপ্ত হয়।

লিনাক্সে চালানোর জন্য একটি ম্যাকে একটি C++ প্রোগ্রাম তৈরি করা

গেমটি একটি ম্যাকে ডেভেলপ করা হয়েছিল এবং লিনাক্সে স্থাপন করা হয়েছিল, কিন্তু যেহেতু ওপেনসিভি এবং বুস্ট উভয় অপারেটিং সিস্টেমের জন্যই বিদ্যমান ছিল, তাই কম্পাইল এনভায়রনমেন্ট প্রতিষ্ঠিত হওয়ার পরে বিকাশ নিজেই কঠিন ছিল না। আমি ম্যাকে বিল্ড ডিবাগ করতে এক্সকোডে কমান্ড লাইন টুল ব্যবহার করেছি, তারপর অটোমেক/অটোকনফ ব্যবহার করে একটি কনফিগার ফাইল তৈরি করেছি যাতে বিল্ডটি লিনাক্সে কম্পাইল করা যায়। তারপর আমাকে এক্সিকিউটেবল ফাইল তৈরি করতে লিনাক্সে "কনফিগার && মেক" ব্যবহার করতে হয়েছিল। কম্পাইলার সংস্করণের পার্থক্যের কারণে আমি কিছু লিনাক্স-নির্দিষ্ট বাগগুলির সম্মুখীন হয়েছি কিন্তু জিডিবি ব্যবহার করে তুলনামূলকভাবে সহজে সমাধান করতে সক্ষম হয়েছি।

উপসংহার

ফ্ল্যাশ বা ইউনিটি দিয়ে এই ধরনের একটি গেম তৈরি করা যেতে পারে, যা অনেক সুবিধা নিয়ে আসবে। যাইহোক, এই সংস্করণের কোন প্লাগইন প্রয়োজন নেই, এবং HTML5 + CSS3 এর লেআউট বৈশিষ্ট্যগুলি অত্যন্ত শক্তিশালী বলে প্রমাণিত হয়েছে৷ প্রতিটি কাজের জন্য সঠিক সরঞ্জাম থাকা অবশ্যই গুরুত্বপূর্ণ। আমি ব্যক্তিগতভাবে বিস্মিত হয়েছিলাম যে গেমটি সম্পূর্ণরূপে HTML5-এ তৈরি একটির জন্য কতটা ভাল হয়েছে, এবং যদিও এটি এখনও অনেক ক্ষেত্রে অনুপস্থিত, আমি ভবিষ্যতে এটি কীভাবে বিকাশ করে তা দেখার জন্য উন্মুখ।