দ্য হবিট এক্সপেরিয়েন্স 2014

Hobbit অভিজ্ঞতায় WebRTC গেমপ্লে যোগ করা হচ্ছে

ড্যানিয়েল ইসাকসন
ড্যানিয়েল ইসাকসন

নতুন হবিট মুভি "দ্য হবিট: দ্য ব্যাটল অফ দ্য ফাইভ আর্মিস" এর জন্য আমরা গত বছরের ক্রোম এক্সপেরিমেন্ট, এ জার্নি থ্রু মিডল-আর্থ কিছু নতুন বিষয়বস্তু নিয়ে কাজ করেছি৷ এবারের প্রধান ফোকাস হল WebGL-এর ব্যবহার প্রসারিত করা কারণ আরও ব্রাউজার এবং ডিভাইসগুলি বিষয়বস্তু দেখতে পারে এবং Chrome এবং Firefox-এ WebRTC ক্ষমতার সাথে কাজ করতে পারে৷ এই বছরের পরীক্ষায় আমাদের তিনটি লক্ষ্য ছিল:

  • Android এর জন্য Chrome-এ WebRTC এবং WebGL ব্যবহার করে P2P গেমপ্লে
  • একটি মাল্টি-প্লেয়ার গেম তৈরি করুন যা খেলতে সহজ এবং এটি স্পর্শ ইনপুটের উপর ভিত্তি করে
  • গুগল ক্লাউড প্ল্যাটফর্মে হোস্ট করুন

খেলার সংজ্ঞা

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

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

খেলার অংশ

এই মাল্টি-প্লেয়ার গেমটি তৈরি করার জন্য কয়েকটি মূল অংশ রয়েছে যা আমাদের তৈরি করতে হয়েছিল:

  • একটি সার্ভার সাইড প্লেয়ার ম্যানেজমেন্ট API ব্যবহারকারী, ম্যাচ মেকিং, সেশন এবং গেমের পরিসংখ্যান পরিচালনা করে।
  • খেলোয়াড়দের মধ্যে সংযোগ স্থাপনে সাহায্য করার জন্য সার্ভার।
  • AppEngine চ্যানেল API সিগন্যালিং পরিচালনার জন্য একটি API যা গেম রুমের সমস্ত খেলোয়াড়দের সাথে সংযোগ এবং যোগাযোগ করতে ব্যবহৃত হয়।
  • একটি জাভাস্ক্রিপ্ট গেম ইঞ্জিন যা রাজ্যের সিঙ্কিং এবং দুই প্লেয়ার/পিয়ারের মধ্যে RTC মেসেজিং পরিচালনা করে।
  • ওয়েবজিএল গেম ভিউ।

প্লেয়ার ম্যানেজমেন্ট

বিপুল সংখ্যক খেলোয়াড়কে সমর্থন করার জন্য আমরা প্রতি যুদ্ধক্ষেত্রে অনেকগুলি সমান্তরাল গেম-রুম ব্যবহার করি। গেম-রুম প্রতি খেলোয়াড়ের সংখ্যা সীমিত করার প্রধান কারণ হল যুক্তিসঙ্গত সময়ে নতুন খেলোয়াড়দের লিডারবোর্ডের শীর্ষে পৌঁছাতে দেওয়া। সীমাটি json অবজেক্টের আকারের সাথে সংযুক্ত রয়েছে যা চ্যানেল API এর মাধ্যমে প্রেরিত গেম-রুম বর্ণনা করে যার সীমা 32kb। আমাদের খেলায় খেলোয়াড়, রুম, স্কোর, সেশন এবং তাদের সম্পর্ক সংরক্ষণ করতে হবে। এটি করার জন্য, প্রথমে আমরা সত্তার জন্য NDB ব্যবহার করেছি এবং সম্পর্কগুলি মোকাবেলা করার জন্য ক্যোয়ারী ইন্টারফেস ব্যবহার করেছি। NDB হল Google ক্লাউড ডেটাস্টোরের একটি ইন্টারফেস। এনডিবি ব্যবহার শুরুতে দুর্দান্ত কাজ করেছিল কিন্তু আমরা শীঘ্রই এটিকে কীভাবে ব্যবহার করতে হবে তা নিয়ে আমরা সমস্যায় পড়েছিলাম। ক্যোয়ারীটি ডাটাবেসের "প্রতিশ্রুতিবদ্ধ" সংস্করণের বিপরীতে চালানো হয়েছিল (এনডিবি রাইটসটি এই গভীর নিবন্ধে ব্যাপকভাবে ব্যাখ্যা করা হয়েছে) যা কয়েক সেকেন্ডের বিলম্ব হতে পারে। কিন্তু সত্তার নিজেরা সেই বিলম্ব করেনি কারণ তারা সরাসরি ক্যাশে থেকে প্রতিক্রিয়া জানায়। কিছু উদাহরণ কোড দিয়ে ব্যাখ্যা করা কিছুটা সহজ হতে পারে:

// example code to explain our issue with eventual consistency
def join_room(player_id, room_id):
    room = Room.get_by_id(room_id)
    
    player = Player.get_by_id(player_id)
    player.room = room.key
    player.put()
    
    // the player Entity is updated directly in the cache
    // so calling this will return the room key as expected
    player.room // = Key(Room, room_id)

    // Fetch all the players with room set to 'room.key'
    players_in_room = Player.query(Player.room == room.key).fetch()
    // = [] (an empty list of players)
    // even though the saved player above may be expected to be in the
    // list it may not be there because the query api is being run against the 
    // "committed" version and may still be empty for a few seconds

    return {
        room: room,
        players: players_in_room,
    }

ইউনিট পরীক্ষা যোগ করার পরে আমরা সমস্যাটি স্পষ্টভাবে দেখতে পাচ্ছি এবং আমরা মেমক্যাশে একটি কমা বিভক্ত তালিকায় সম্পর্ক রাখার পরিবর্তে প্রশ্নগুলি থেকে দূরে সরে গেছি। এটি কিছুটা হ্যাকের মতো অনুভূত হয়েছিল কিন্তু এটি কাজ করেছে এবং AppEngine মেমক্যাশে চমৎকার "তুলনা এবং সেট" বৈশিষ্ট্য ব্যবহার করে কীগুলির জন্য একটি লেনদেনের মতো সিস্টেম রয়েছে তাই এখন পরীক্ষাগুলি আবার পাস হয়েছে৷

দুর্ভাগ্যবশত মেমক্যাশে সমস্ত রংধনু এবং ইউনিকর্ন নয় তবে কয়েকটি সীমার সাথে আসে, সবচেয়ে উল্লেখযোগ্য হল 1MB মান আকার (একটি যুদ্ধক্ষেত্রের সাথে সম্পর্কিত খুব বেশি রুম থাকতে পারে না) এবং কী মেয়াদ শেষ হয়েছে, বা ডক্স এটি ব্যাখ্যা করে:

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

অবশেষে আমরা Google ক্লাউড এসকিউএল খুঁজে পেয়েছি এবং সম্পর্কগুলিকে MySQL-এ সরিয়ে নিয়েছি। এটি অনেক কাজ ছিল কিন্তু অবশেষে এটি দুর্দান্ত কাজ করেছে, আপডেটগুলি এখন সম্পূর্ণ পারমাণবিক এবং পরীক্ষাগুলি এখনও পাস করে। এটি ম্যাচ মেকিং এবং স্কোর-কিপিং বাস্তবায়নকে অনেক বেশি নির্ভরযোগ্য করে তুলেছে।

সময়ের সাথে সাথে NDB এবং memcache থেকে ধীরে ধীরে এসকিউএল-এ আরও বেশি ডেটা স্থানান্তরিত হয়েছে কিন্তু সাধারণভাবে প্লেয়ার, যুদ্ধক্ষেত্র এবং রুম এন্টিটি এখনও NDB-তে সংরক্ষণ করা হয় যখন সেশন এবং তাদের মধ্যে সম্পর্কগুলি সবগুলি SQL-এ সংরক্ষণ করা হয়।

আমাদের কে কে খেলছে তাও ট্র্যাক রাখতে হয়েছিল এবং খেলোয়াড়দের দক্ষতার স্তর এবং অভিজ্ঞতা বিবেচনা করে এমন একটি ম্যাচিং মেকানিজম ব্যবহার করে একে অপরের বিরুদ্ধে খেলোয়াড়দের জুটিবদ্ধ করতে হয়েছিল। আমরা ওপেন সোর্স লাইব্রেরি Glicko2 এর উপর ভিত্তি করে ম্যাচ তৈরি করেছি।

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

WebRTC সেট আপ করা হচ্ছে

যখন দুটি খেলোয়াড় একটি যুদ্ধের জন্য মিলিত হয় তখন একটি সংকেত পরিষেবা ব্যবহার করা হয় যাতে দুটি মিলে যাওয়া সমবয়সীদের একে অপরের সাথে কথা বলা হয় এবং একটি পিয়ার সংযোগ শুরু করতে সহায়তা করা হয়।

সিগন্যালিং পরিষেবার জন্য আপনি ব্যবহার করতে পারেন এমন বেশ কয়েকটি তৃতীয় পক্ষের লাইব্রেরি রয়েছে এবং এটি WebRTC সেট আপ করাকেও সহজ করে। কিছু বিকল্প হল PeerJS , SimpleWebRTC , এবং PubNub WebRTC SDK । PubNub একটি হোস্ট করা সার্ভার সমাধান ব্যবহার করে এবং এই প্রকল্পের জন্য আমরা Google ক্লাউড প্ল্যাটফর্মে হোস্ট করতে চেয়েছিলাম। অন্য দুটি লাইব্রেরি node.js সার্ভার ব্যবহার করে যা আমরা Google Compute Engine-এ ইনস্টল করতে পারতাম কিন্তু আমাদের এটাও নিশ্চিত করতে হবে যে এটি হাজার হাজার সমসাময়িক ব্যবহারকারীদের পরিচালনা করতে পারে, যা আমরা ইতিমধ্যেই জানতাম যে চ্যানেল API করতে পারে।

এই ক্ষেত্রে Google ক্লাউড প্ল্যাটফর্ম ব্যবহার করার প্রধান সুবিধাগুলির মধ্যে একটি হল স্কেলিং। একটি AppEngine প্রকল্পের জন্য প্রয়োজনীয় সংস্থানগুলিকে স্কেল করা Google Developers Console-এর মাধ্যমে সহজেই পরিচালনা করা হয় এবং চ্যানেল API ব্যবহার করার সময় সিগন্যালিং পরিষেবা স্কেল করার জন্য কোনও অতিরিক্ত কাজের প্রয়োজন নেই৷

লেটেন্সি এবং চ্যানেল এপিআই কতটা মজবুত তা নিয়ে কিছু উদ্বেগ ছিল কিন্তু আমরা পূর্বে কিউবস্ল্যাম প্রকল্পের জন্য এটি ব্যবহার করেছিলাম এবং এটি সেই প্রকল্পের লক্ষ লক্ষ ব্যবহারকারীর জন্য কাজ করে বলে প্রমাণিত হয়েছে তাই আমরা এটি আবার ব্যবহার করার সিদ্ধান্ত নিয়েছি।

যেহেতু আমরা WebRTC এর সাথে সাহায্য করার জন্য একটি তৃতীয় পক্ষের লাইব্রেরি ব্যবহার করা বেছে নিইনি আমাদের নিজেদের তৈরি করতে হয়েছিল৷ সৌভাগ্যবশত আমরা কিউবস্ল্যাম প্রকল্পের জন্য অনেক কাজ পুনঃব্যবহার করতে পারি। যখন উভয় খেলোয়াড় একটি সেশনে যোগদান করে তখন সেশনটি "সক্রিয়" এ সেট করা হয় এবং উভয় খেলোয়াড়ই চ্যানেল API এর মাধ্যমে পিয়ার-টু-পিয়ার সংযোগ শুরু করতে সেই সক্রিয় সেশন আইডি ব্যবহার করবে। এর পরে দুই খেলোয়াড়ের মধ্যে সমস্ত যোগাযোগ একটি RTCDataChannel-এর মাধ্যমে পরিচালিত হবে।

সংযোগ স্থাপন এবং NATs এবং ফায়ারওয়ালগুলির সাথে মোকাবিলা করতে আমাদের STUN এবং TURN সার্ভারেরও প্রয়োজন৷ HTML5 Rocks নিবন্ধে WebRTC সেট আপ করার বিষয়ে আরও গভীরভাবে পড়ুন WebRTC বাস্তব জগতে: STUN, TURN, এবং সংকেত

ব্যবহৃত টার্ন সার্ভারের সংখ্যাও ট্র্যাফিকের উপর নির্ভর করে স্কেল করতে সক্ষম হওয়া দরকার। এটি পরিচালনা করার জন্য আমরা Google Deployment Manager পরীক্ষা করেছি। এটি আমাদের গতিশীলভাবে Google Compute Engine-এ সম্পদ স্থাপন করতে এবং একটি টেমপ্লেট ব্যবহার করে টার্ন সার্ভার ইনস্টল করতে দেয়। এটি এখনও আলফাতে আছে কিন্তু আমাদের উদ্দেশ্যে এটি নির্দোষভাবে কাজ করেছে। টার্ন সার্ভারের জন্য আমরা coturn ব্যবহার করি, যা STUN/TURN এর একটি খুব দ্রুত, দক্ষ এবং আপাতদৃষ্টিতে নির্ভরযোগ্য বাস্তবায়ন।

চ্যানেল API

চ্যানেল API ক্লায়েন্ট সাইডের গেম রুমে এবং থেকে সমস্ত যোগাযোগ পাঠাতে ব্যবহৃত হয়। আমাদের প্লেয়ার ম্যানেজমেন্ট এপিআই গেম ইভেন্ট সম্পর্কে বিজ্ঞপ্তির জন্য চ্যানেল API ব্যবহার করছে।

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

var que = [];  // [seq, packet...]
var seq = 0;
var rcv = -1;

function send(message) {
  var packet = JSON.stringify({
    seq: seq++,
    msg: message
  });
  channel.send(packet);
}

function recv(packet) {
  var data = JSON.parse(packet);

  if (data.seq <= rcv) {
    // ignoring message, older or already received
  } else if (data.seq > rcv + 1) {
    // message from the future. queue it up.
    que.push(data.seq, packet);
  } else {
    // message in order! update the rcv index and emit the message
    rcv = data.seq;
    emit('message', data.message);

    // and now that we have updated the `rcv` index we 
    // will check the que for any other we can send
    setTimeout(flush, 10);
  }
}

function flush() {
  for (var i=0; i<que.length; i++) {
    var seq = que[i];
    var packet = que[i+1];
    if (data.seq == rcv + 1) {
      recv(packet);
      return; // wait for next flush
    }
  }
}

আমরা সাইটের বিভিন্ন API গুলিকে মডুলার রাখতে এবং সাইটের হোস্টিং থেকে আলাদা রাখতে এবং GAE-তে তৈরি মডিউলগুলি ব্যবহার করে শুরু করতে চেয়েছিলাম। দুর্ভাগ্যবশত dev-এ কাজ করার জন্য এটি সব পাওয়ার পরে আমরা বুঝতে পেরেছি যে চ্যানেল API উত্পাদনে মোটেও মডিউলগুলির সাথে কাজ করে না । পরিবর্তে আমরা আলাদা GAE ইন্সট্যান্স ব্যবহার করতে চলেছি এবং CORS সমস্যায় পড়েছিলাম যা আমাদের একটি iframe postMessage ব্রিজ ব্যবহার করতে বাধ্য করে।

গেম ইঞ্জিন

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

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

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

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

দূরবর্তী ব্যবহারকারীর কাছে মাউসের অবস্থান আরও ঘন ঘন পাঠানো হয় এবং এই মুহূর্তে কার্সারটি কোথায় রয়েছে সে সম্পর্কে একটি 3d-আলো সূক্ষ্ম ইঙ্গিত দেয়।