কেস স্টাডি - আক্রমণ! এরিনা

ভূমিকা

2010 সালের জুন মাসে, এটি আমাদের নজরে আসে যে স্থানীয় প্রকাশনা "zine" বোয়িং বোয়িং একটি গেম ডেভেলপমেন্ট প্রতিযোগিতায় অংশ নিচ্ছে। আমরা জাভাস্ক্রিপ্ট এবং <canvas> এ একটি দ্রুত, সহজ গেম তৈরি করার জন্য এটিকে একটি সম্পূর্ণ ভাল অজুহাত হিসাবে দেখেছি, তাই আমরা কাজ শুরু করেছি। প্রতিযোগিতার পরেও আমাদের অনেক ধারণা ছিল এবং আমরা যা শুরু করেছি তা শেষ করতে চেয়েছিলাম। এই যে রেজাল্টের কেস স্টাডি, অনসলট নামে একটা ছোট্ট খেলা! এরিনা

বিপরীতমুখী, pixelated চেহারা

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

আক্রমণের ! এরিনা পিক্সেল আকার
পিক্সেলের আকার বৃদ্ধি গ্রাফিক ডিজাইনের কাজ কমাতে পারে।

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

এখানে একটি দৃশ্যকল্প যা আমরা বিবেচনা করেছি:

<style>
canvas {
  width: 640px;
  height: 320px;
}
</style>
<canvas width="320" height="240">
  Sorry, your browser is not supported.
</canvas>

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

ক্যানভাস আকার পরিবর্তন বিকল্প
বাম: ফটোশপে পিক্সেল-নিখুঁত সম্পদ দ্বিগুণ হয়েছে। ডান: CSS আকার পরিবর্তন একটি অস্পষ্ট প্রভাব যোগ করেছে।

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

মজার ক্যানভাস কৌশল

আমরা সবাই জানি যে <canvas> হল নতুন উষ্ণতা, কিন্তু কখনও কখনও বিকাশকারীরা এখনও DOM ব্যবহার করার পরামর্শ দেন । আপনি যদি বেড়াতে থাকেন যেটি ব্যবহার করবেন, তাহলে এখানে একটি উদাহরণ দেওয়া হল কিভাবে <canvas> আমাদের প্রচুর সময় এবং শক্তি বাঁচিয়েছে।

যখন শত্রু আক্রমণে আঘাত পায়! এরিনা , এটি লাল ঝলকানি এবং সংক্ষিপ্তভাবে একটি "বেদনা" অ্যানিমেশন প্রদর্শন করে। আমাদের তৈরি করা গ্রাফিক্সের সংখ্যা সীমিত করতে, আমরা কেবলমাত্র নিচের দিকের দিকে "ব্যথায়" শত্রুদের দেখাই। এটি ইন-গেম গ্রহণযোগ্য দেখায় এবং স্প্রাইট তৈরির অনেক সময় বাঁচিয়েছে। তবে বস দানবদের জন্য, ব্যথার ফ্রেমের জন্য বাম দিকে বা ওপরের দিকে মুখ করে হঠাৎ নিচের দিকে মুখ করে একটি বড় স্প্রাইট (64x64 পিক্সেল বা তার বেশি) দেখতে বিরক্তিকর ছিল।

একটি সুস্পষ্ট সমাধান হ'ল প্রতিটি বসের জন্য আটটি দিকের প্রতিটিতে একটি ব্যথার ফ্রেম আঁকতে হবে, তবে এটি খুব সময়সাপেক্ষ হত। ধন্যবাদ <canvas> , আমরা কোডে এই সমস্যাটি সমাধান করতে সক্ষম হয়েছি:

হামলায় ক্ষয়ক্ষতি নিচ্ছেন দর্শক! এরিনা
context.globalCompositeOperation ব্যবহার করে আকর্ষণীয় প্রভাব তৈরি করা যেতে পারে।

প্রথমে আমরা দানবটিকে একটি লুকানো "বাফার" <canvas> এ আঁকি, এটিকে লাল দিয়ে ওভারলে করি, তারপর ফলাফলটি আবার স্ক্রিনে রেন্ডার করি। কোড এই মত কিছু দেখায়:

// Get the "buffer" canvas (that isn't visible to the user)
var bufferCanvas = document.getElementById("buffer");
var buffer = bufferCanvas.getContext("2d");

// Draw your image on the buffer
buffer.drawImage(image, 0, 0);

// Draw a rectangle over the image using a nice translucent overlay
buffer.save();
buffer.globalCompositeOperation = "source-in";
buffer.fillStyle = "rgba(186, 51, 35, 0.6)"; // red
buffer.fillRect(0, 0, image.width, image.height);
buffer.restore();

// Copy the buffer onto the visible canvas
document.getElementById("stage").getContext("2d").drawImage(bufferCanvas, x, y);

গেম লুপ

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

এখানে একটি গেম লুপের একটি উদাহরণ:

function main () {
  handleInput();
  update();
  render();
};

setInterval(main, 1);

প্রথম গুরুত্বপূর্ণ পার্থক্য হ'ল handleInput ফাংশনটি এখনই কিছু করে না। যদি একজন ব্যবহারকারী একটি সাধারণ ওয়েব অ্যাপে একটি কী টিপে, তাহলে অবিলম্বে কাঙ্খিত ক্রিয়া সম্পাদন করা বোধগম্য হয়৷ কিন্তু একটি খেলায়, জিনিসগুলি সঠিকভাবে প্রবাহিত হওয়ার জন্য কালানুক্রমিক ক্রমে ঘটতে হবে।

window.addEventListener("mousedown", function(e) {
  // A mouse click means the players wants to attack.
  // We don't actually do that yet, but instead tell the rest
  // of the program about the request.
  buttonStates[e.button] = true;
}, false);

function handleInput() {
  // Here is where we respond to the click
  if (buttonStates[LEFT_BUTTON]) {
    player.attacking = true;
    delete buttonStates[LEFT_BUTTON];
  }
};

এখন আমরা ইনপুট সম্পর্কে জানি এবং update ফাংশনে এটি বিবেচনা করতে পারি, জেনে যে এটি গেমের বাকি নিয়মগুলি মেনে চলবে।

function update() {
  // Check for collisions, states, whatever else is needed

  // If after that the player can still attack, do it!
  if (player.attacking && player.canAttack()) {
    player.attack();
  }
};

অবশেষে, একবার সবকিছু গণনা করা হয়ে গেলে, স্ক্রীনটি পুনরায় আঁকার সময়! DOM-ল্যান্ডে, ব্রাউজার এই হিভিং লিফটিং পরিচালনা করে। কিন্তু <canvas> ব্যবহার করার সময় যখনই কিছু ঘটবে তখনই ম্যানুয়ালি পুনরায় আঁকতে হবে (যা সাধারণত প্রতিটি একক ফ্রেম!)

function render() {
  // First erase everything, something like:
  context.clearRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

  // Draw the player (and whatever else you need)
  context.drawImage(
    player.getImage(),
    player.x, player.y
  );
};

সময়-ভিত্তিক মডেলিং

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

সময়-ভিত্তিক মডেলিং ব্যবহার করার জন্য আমাদের শেষ ফ্রেম আঁকার পর থেকে অতিবাহিত সময় ক্যাপচার করতে হবে। এটি ট্র্যাক করতে আমাদের গেম লুপের update() ফাংশন বাড়াতে হবে।

function update() {

  // NOTE: You'll need to initially seed this.lastUpdate
  // with the current time when your game loop starts
  // this.lastUpdate = Date.now();

  // Calculate elapsed time since last frame
  var now = Date.now();
  var elapsed = (now - this.lastUpdate);
  this.lastUpdate = now;

  // Do stuff with elapsed

};

এখন যেহেতু আমাদের অতিবাহিত সময় আছে আমরা গণনা করতে পারি যে একটি প্রদত্ত স্প্রাইট প্রতিটি ফ্রেমকে কতদূর সরানো উচিত। প্রথমত, আমাদের একটি স্প্রাইট অবজেক্টে কয়েকটি জিনিসের ট্র্যাক রাখতে হবে: বর্তমান অবস্থান, গতি এবং দিক।

var Sprite = function() {

  // The sprite's position relative to the top left of the game world
  this.position = {x: 0, y: 0};

  // The sprite's direction. A positive x value indicates moving to the right
  this.direction = {x: 1, y: 0};

  // How many pixels the sprite moves per second
  this.speed = 50;
};

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

// Determine how far this sprite will move this frame
var distance = (sprite.speed / 1000) * elapsed;

// Apply the movement distance to the sprite's current position
// taking into account its direction
sprite.position.x += (distance * sprite.direction.x);
sprite.position.y += (distance * sprite.direction.y);

লক্ষ্য করুন যে direction.x এবং direction.y মান স্বাভাবিক করা উচিত যার মানে তারা সবসময় -1 এবং 1 এর মধ্যে পড়ে।

নিয়ন্ত্রণ করে

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

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

আক্রমণের ! এরিনা কন্ট্রোল মডেল (বঞ্চিত)
একটি পুরানো নিয়ন্ত্রণ বা "কিভাবে খেলতে হয়" অনসলট মডেল! এরিনা।

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

আক্রমণের ! এরিনা টিউটোরিয়াল নিয়ন্ত্রণ করে
খেলোয়াড়রা বেশিরভাগ টিউটোরিয়াল ওভারলে উপেক্ষা করে; তারা বরং খেলবে এবং মজা করবে!

কিছু ইউরোপীয় অনুরাগী থাকার জন্য আমরা সৌভাগ্যবান, কিন্তু আমরা তাদের কাছ থেকে হতাশা শুনেছি যে তাদের সাধারণ QWERTY কীবোর্ড নাও থাকতে পারে এবং দিকনির্দেশনামূলক আন্দোলনের জন্য WASD কীগুলি ব্যবহার করতে অক্ষম। বাঁ-হাতি খেলোয়াড়রাও একই অভিযোগ করেছেন।

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

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

// Find the nearest hostile target (if any) to the player
var player = this.getPlayerObject();
var hostile = this.getNearestHostile(player);
if (hostile !== null) {
  // Found one! Shoot in its direction
  var shoot = hostile.boundingBox().center().subtract(
    player.boundingBox().center()
  ).normalize();
}

// Move towards where the player clicked/touched
var move = this.targetReticle.position.clone().subtract(
  player.boundingBox().center()
).normalize();
var distance = this.targetReticle.position.clone().subtract(
  player.boundingBox().center()
).magnitude();

// Prevent jittering if the character is close enough
if (distance < 3) {
  move.zero();
}

// Move the player
if ((move.x !== 0) || (move.y !== 0)) {
  player.setDirection(move);
}

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

শ্রুতি

নিয়ন্ত্রণ এবং পারফরম্যান্সের মধ্যে, অনসলট বিকাশ করার সময় আমাদের সবচেয়ে বড় সমস্যাগুলির মধ্যে একটি! Arena ছিল HTML5 এর <audio> ট্যাগ। সম্ভবত সবচেয়ে খারাপ দিক হল লেটেন্সি: প্রায় সব ব্রাউজারেই কলিং .play() এবং সাউন্ড আসলে বাজতে দেরি হয়। এটি একজন গেমারের অভিজ্ঞতা নষ্ট করতে পারে, বিশেষ করে যখন আমাদের মতো দ্রুত গতির গেমের সাথে খেলা হয়।

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

/*
This example uses the SoundManager 2 library by Scott Schiller:
http://www.schillmania.com/projects/soundmanager2/
*/

// Default to sm2 (Flash)
var api = "sm2";

function initAudio (callback) {
  switch (api) {
    case "sm2":
      soundManager.onerror = (function (init) {
        return function () {
          api = "html5";
          init(callback);
        };
      }(arguments.callee));
      break;
    case "html5":
      var audio = document.createElement("audio");

      if (
        audio
        && audio.canPlayType
        && audio.canPlayType("audio/mpeg;")
      ) {
        callback();
      } else {
        // No audio support :(
      }
      break;
  }
};

MP3 ফাইল (যেমন Mozilla Firefox) চালাবে না এমন ব্রাউজারগুলিকে সমর্থন করা একটি গেমের জন্য গুরুত্বপূর্ণও হতে পারে। যদি এটি হয়, সমর্থন সনাক্ত করা যেতে পারে এবং এই মত কোড সহ Ogg Vorbis এর মত কিছুতে স্যুইচ করা যেতে পারে:

/*
Note: you could instead use "new Audio()" here,
but the client will throw an error if it doesn't support Audio,
which makes using "document.createElement" a safer approach.
*/

var audio = document.createElement("audio");

if (audio && audio.canPlayType) {
  if (!audio.canPlayType("audio/mpeg;")) {
    // Here you know you CANNOT use .mp3 files
    if (audio.canPlayType("audio/ogg; codecs=vorbis")) {
      // Here you know you CAN use .ogg files
    }
  }
}

ডেটা সংরক্ষণ করা হচ্ছে

আপনি উচ্চ স্কোর ছাড়া একটি আর্কেড-স্টাইল শুট 'এম আপ করতে পারেন না! আমরা জানতাম যে আমাদের কিছু গেমের ডেটা টিকে থাকতে হবে, এবং যখন আমরা কুকিজের মতো পুরানো টুপি ব্যবহার করতে পারতাম, আমরা মজাদার নতুন HTML5 প্রযুক্তিগুলি খনন করতে চেয়েছিলাম। স্থানীয় স্টোরেজ, সেশন স্টোরেজ এবং ওয়েব এসকিউএল ডেটাবেস সহ বিকল্পগুলির অবশ্যই কোন অভাব নেই।

ALT_TEXT_HERE
উচ্চ স্কোর সংরক্ষণ করা হয়, সেইসাথে প্রতিটি বসকে পরাজিত করার পরে গেমে আপনার স্থান।

আমরা localStorage ব্যবহার করার সিদ্ধান্ত নিয়েছি যেহেতু এটি নতুন, দুর্দান্ত এবং ব্যবহার করা সহজ৷ এটি মৌলিক কী/মান জোড়া সংরক্ষণ সমর্থন করে যা আমাদের সমস্ত সাধারণ খেলার প্রয়োজন। এটি কীভাবে ব্যবহার করবেন তার একটি সরল উদাহরণ এখানে:

if (typeof localStorage == "object") {
  localStorage.setItem("foo", "bar");
  localStorage.getItem("foo"); // Value is "bar"
  localStorage.removeItem("foo");
  localStorage.getItem("foo"); // Value is now null
}

সচেতন হতে কিছু "গোটচা" আছে। আপনি যা পাস করেন না কেন, মানগুলি স্ট্রিং হিসাবে সংরক্ষণ করা হয়, যা কিছু অপ্রত্যাশিত ফলাফলের দিকে নিয়ে যেতে পারে:

localStorage.setItem("foo", false);
typeof localStorage.getItem("foo"); // Value is "false" (a string literal)
if (localStorage.getItem("foo")) {
  // It's true!
}

// Don't pass objects into setItem
localStorage.setItem("bar", {"key": "value"});
localStorage.getItem("bar"); // Value is "[object Object]" (a string literal)

// JSON stringify and parse when dealing with localStorage
localStorage.setItem("json", JSON.stringify({"key": "value"}));
typeof localStorage.getItem("json"); // string
JSON.parse(localStorage.getItem("json")); // {"key": "value"}

সারসংক্ষেপ

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

আক্রমণের ! একটি লুকানো HTML5 লোগো সহ এরিনা৷
অনসলট খেলার সময় আপনি "html5" টাইপ করে একটি HTML5 শিল্ড পেতে পারেন! এরিনা।