HTML5 গেমের জন্য কোন টিয়ার গাইড নেই

ভূমিকা

তাহলে আপনি ক্যানভাস এবং HTML5 ব্যবহার করে একটি গেম তৈরি করতে চান? এই টিউটোরিয়ালটি অনুসরণ করুন এবং আপনি কিছুক্ষণের মধ্যেই আপনার পথে চলে যাবেন।

টিউটোরিয়ালটি জাভাস্ক্রিপ্টের জ্ঞানের অন্তত একটি মধ্যবর্তী স্তরের অনুমান করে।

আপনি প্রথমে গেমটি খেলতে পারেন বা সরাসরি নিবন্ধে যেতে পারেন এবং গেমটির সোর্স কোড দেখতে পারেন

ক্যানভাস তৈরি করা

জিনিস আঁকার জন্য, আমাদের একটি ক্যানভাস তৈরি করতে হবে। কারণ এটি একটি নো টিয়ার্স গাইড যা আমরা jQuery ব্যবহার করব।

var CANVAS_WIDTH = 480;
var CANVAS_HEIGHT = 320;

var canvasElement = $("<canvas width='" + CANVAS_WIDTH + 
                      "' height='" + CANVAS_HEIGHT + "'></canvas>");
var canvas = canvasElement.get(0).getContext("2d");
canvasElement.appendTo('body');

গেম লুপ

মসৃণ এবং ক্রমাগত গেমপ্লের চেহারা অনুকরণ করার জন্য, আমরা গেমটি আপডেট করতে চাই এবং মানুষের মন এবং চোখ যা উপলব্ধি করতে পারে তার চেয়ে দ্রুত স্ক্রীনটি পুনরায় আঁকতে চাই।

var FPS = 30;
setInterval(function() {
  update();
  draw();
}, 1000/FPS);

আপাতত আমরা আপডেটটি ছেড়ে দিতে পারি এবং পদ্ধতিগুলি ফাঁকা রাখতে পারি। জানা গুরুত্বপূর্ণ বিষয় হল setInterval() তাদের পর্যায়ক্রমে কল করার যত্ন নেয়।

function update() { ... }
function draw() { ... }

ওহে বিশ্ব

এখন যেহেতু আমাদের একটি গেম লুপ চলছে, আসুন স্ক্রিনে কিছু পাঠ্য আঁকতে আমাদের আঁকার পদ্ধতিটি আপডেট করি।

function draw() {
  canvas.fillStyle = "#000"; // Set color to black
  canvas.fillText("Sup Bro!", 50, 50);
}

এটি স্থির পাঠ্যের জন্য বেশ দুর্দান্ত, তবে যেহেতু আমাদের ইতিমধ্যে একটি গেম লুপ সেট আপ করা আছে, তাই আমাদের এটিকে বেশ সহজে সরাতে সক্ষম হওয়া উচিত।

var textX = 50;
var textY = 50;

function update() {
  textX += 1;
  textY += 1;
}

function draw() {
  canvas.fillStyle = "#000";
  canvas.fillText("Sup Bro!", textX, textY);
}

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

function draw() {
  canvas.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  canvas.fillStyle = "#000";
  canvas.fillText("Sup Bro!", textX, textY);
}

এখন যখন আপনি স্ক্রিনে কিছু পাঠ্য ঘুরিয়েছেন, আপনি একটি বাস্তব খেলার অর্ধেক পথ। শুধু নিয়ন্ত্রণগুলি আঁটসাঁট করুন, গেমপ্লে উন্নত করুন, গ্রাফিক্স স্পর্শ করুন। ঠিক আছে হয়ত একটি বাস্তব গেম থাকার উপায়ের 1/7 তম, কিন্তু ভাল খবর হল যে টিউটোরিয়ালটিতে আরও অনেক কিছু আছে।

প্লেয়ার তৈরি করা

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

var player = {
  color: "#00A",
  x: 220,
  y: 270,
  width: 32,
  height: 32,
  draw: function() {
    canvas.fillStyle = this.color;
    canvas.fillRect(this.x, this.y, this.width, this.height);
  }
};

আমরা এখন প্লেয়ারের প্রতিনিধিত্ব করার জন্য একটি সাধারণ রঙিন আয়তক্ষেত্র ব্যবহার করছি। যখন আমরা গেমটি আঁকব, তখন আমরা ক্যানভাস পরিষ্কার করব এবং প্লেয়ারকে আঁকব।

function draw() {
  canvas.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  player.draw();
}

কীবোর্ড নিয়ন্ত্রণ

jQuery হটকি ব্যবহার করা

jQuery Hotkeys প্লাগইন ব্রাউজার জুড়ে কী হ্যান্ডলিংকে অনেক সহজ করে তোলে। দুর্বোধ্য ক্রস-ব্রাউজার keyCode এবং charCode সমস্যা নিয়ে কান্নাকাটি করার পরিবর্তে, আমরা এর মতো ইভেন্টগুলিকে আবদ্ধ করতে পারি:

$(document).bind("keydown", "left", function() { ... });

কোন কী কী কোড আছে তার বিস্তারিত নিয়ে চিন্তা করতে হবে না একটি বড় জয়। আমরা কেবল "প্লেয়ার যখন আপ বোতাম টিপুন, কিছু করুন" এর মতো জিনিস বলতে সক্ষম হতে চাই৷ jQuery Hotkeys এটি সুন্দরভাবে অনুমতি দেয়।

প্লেয়ার আন্দোলন

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

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

ভাল খবর হল যে আমি একটি 16-লাইন JS র‍্যাপার অন্তর্ভুক্ত করেছি যা ইভেন্ট কোয়েরি উপলব্ধ করবে। এটিকে key_status.js বলা হয় এবং আপনি keydown.left , ইত্যাদি চেক করে যে কোনো সময় একটি কী-এর স্থিতি অনুসন্ধান করতে পারেন।

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

function update() {
  if (keydown.left) {
    player.x -= 2;
  }

  if (keydown.right) {
    player.x += 2;
  }
}

এগিয়ে যান এবং এটি একটি ঘূর্ণি.

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

function update() {
  if (keydown.left) {
    player.x -= 5;
  }

  if (keydown.right) {
    player.x += 5;
  }

  player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}

আরও ইনপুট যোগ করা ঠিক ততটাই সহজ হবে, তাই আসুন কিছু ধরণের প্রজেক্টাইল যোগ করি।

function update() {
  if (keydown.space) {
    player.shoot();
  }

  if (keydown.left) {
    player.x -= 5;
  }

  if (keydown.right) {
    player.x += 5;
  }

  player.x = player.x.clamp(0, CANVAS_WIDTH - player.width);
}

player.shoot = function() {
  console.log("Pew pew");
  // :) Well at least adding the key binding was easy...
};

আরো খেলা বস্তু যোগ করা হচ্ছে

প্রজেক্টাইল

এখন বাস্তবের জন্য প্রজেক্টাইল যোগ করা যাক। প্রথমত, সেগুলিকে সংরক্ষণ করার জন্য আমাদের একটি সংগ্রহ প্রয়োজন:

var playerBullets = [];

পরবর্তী, বুলেট দৃষ্টান্ত তৈরি করতে আমাদের একটি কনস্ট্রাক্টর প্রয়োজন।

function Bullet(I) {
  I.active = true;

  I.xVelocity = 0;
  I.yVelocity = -I.speed;
  I.width = 3;
  I.height = 3;
  I.color = "#000";

  I.inBounds = function() {
    return I.x >= 0 && I.x <= CANVAS_WIDTH &&
      I.y >= 0 && I.y <= CANVAS_HEIGHT;
  };

  I.draw = function() {
    canvas.fillStyle = this.color;
    canvas.fillRect(this.x, this.y, this.width, this.height);
  };

  I.update = function() {
    I.x += I.xVelocity;
    I.y += I.yVelocity;

    I.active = I.active && I.inBounds();
  };

  return I;
}

যখন প্লেয়ার গুলি করে, তখন আমাদের একটি বুলেটের উদাহরণ তৈরি করা উচিত এবং এটিকে বুলেট সংগ্রহে যুক্ত করা উচিত।

player.shoot = function() {
  var bulletPosition = this.midpoint();

  playerBullets.push(Bullet({
    speed: 5,
    x: bulletPosition.x,
    y: bulletPosition.y
  }));
};

player.midpoint = function() {
  return {
    x: this.x + this.width/2,
    y: this.y + this.height/2
  };
};

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

function update() {
  ...
  playerBullets.forEach(function(bullet) {
    bullet.update();
  });

  playerBullets = playerBullets.filter(function(bullet) {
    return bullet.active;
  });
}

শেষ ধাপ হল বুলেট আঁকা:

function draw() {
  ...
  playerBullets.forEach(function(bullet) {
    bullet.draw();
  });
}

শত্রুদের

এখন সময় এসেছে শত্রুদের একইভাবে যোগ করার যেভাবে আমরা বুলেট যোগ করেছি।

  enemies = [];

function Enemy(I) {
  I = I || {};

  I.active = true;
  I.age = Math.floor(Math.random() * 128);

  I.color = "#A2B";

  I.x = CANVAS_WIDTH / 4 + Math.random() * CANVAS_WIDTH / 2;
  I.y = 0;
  I.xVelocity = 0
  I.yVelocity = 2;

  I.width = 32;
  I.height = 32;

  I.inBounds = function() {
    return I.x >= 0 && I.x <= CANVAS_WIDTH &&
      I.y >= 0 && I.y <= CANVAS_HEIGHT;
  };

  I.draw = function() {
    canvas.fillStyle = this.color;
    canvas.fillRect(this.x, this.y, this.width, this.height);
  };

  I.update = function() {
    I.x += I.xVelocity;
    I.y += I.yVelocity;

    I.xVelocity = 3 * Math.sin(I.age * Math.PI / 64);

    I.age++;

    I.active = I.active && I.inBounds();
  };

  return I;
};

function update() {
  ...

  enemies.forEach(function(enemy) {
    enemy.update();
  });

  enemies = enemies.filter(function(enemy) {
    return enemy.active;
  });

  if(Math.random() < 0.1) {
    enemies.push(Enemy());
  }
};

function draw() {
  ...

  enemies.forEach(function(enemy) {
    enemy.draw();
  });
}

ছবি লোড করা এবং অঙ্কন করা হচ্ছে

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

player.sprite = Sprite("player");

player.draw = function() {
  this.sprite.draw(canvas, this.x, this.y);
};

function Enemy(I) {
  ...

  I.sprite = Sprite("enemy");

  I.draw = function() {
    this.sprite.draw(canvas, this.x, this.y);
  };

  ...
}

সংঘর্ষ সনাক্তকরণ

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

আসুন একটি সাধারণ আয়তক্ষেত্রাকার সংঘর্ষ সনাক্তকরণ অ্যালগরিদম ব্যবহার করি:

function collides(a, b) {
  return a.x < b.x + b.width &&
         a.x + a.width > b.x &&
         a.y < b.y + b.height &&
         a.y + a.height > b.y;
}

আমরা পরীক্ষা করতে চাই এমন কয়েকটি সংঘর্ষ রয়েছে:

  1. প্লেয়ার বুলেট => শত্রু জাহাজ
  2. প্লেয়ার => শত্রু জাহাজ

আসুন সংঘর্ষগুলি পরিচালনা করার জন্য একটি পদ্ধতি তৈরি করি যা আমরা আপডেট পদ্ধতি থেকে কল করতে পারি।

function handleCollisions() {
  playerBullets.forEach(function(bullet) {
    enemies.forEach(function(enemy) {
      if (collides(bullet, enemy)) {
        enemy.explode();
        bullet.active = false;
      }
    });
  });

  enemies.forEach(function(enemy) {
    if (collides(enemy, player)) {
      enemy.explode();
      player.explode();
    }
  });
}

function update() {
  ...
  handleCollisions();
}

এখন আমাদের প্লেয়ার এবং শত্রুদের বিস্ফোরণ পদ্ধতি যোগ করতে হবে। এটি তাদের অপসারণের জন্য পতাকাঙ্কিত করবে এবং একটি বিস্ফোরণ যোগ করবে।

function Enemy(I) {
  ...

  I.explode = function() {
    this.active = false;
    // Extra Credit: Add an explosion graphic
  };

  return I;
};

player.explode = function() {
  this.active = false;
  // Extra Credit: Add an explosion graphic and then end the game
};

শব্দ

অভিজ্ঞতাটি সম্পূর্ণ করতে, আমরা কিছু মিষ্টি শব্দ প্রভাব যুক্ত করতে যাচ্ছি। এইচটিএমএল 5-এ ছবির মতো শব্দগুলি ব্যবহার করা কিছুটা কষ্টের হতে পারে, কিন্তু আমাদের ম্যাজিক নো-টিয়ার্স সূত্র sound.js-এর জন্য ধন্যবাদ, সাউন্ডকে অতি-সহজ করা যায়।

player.shoot = function() {
  Sound.play("shoot");
  ...
}

function Enemy(I) {
  ...

  I.explode = function() {
    Sound.play("explode");
    ...
  }
}

যদিও API এখন টিয়ার-মুক্ত, শব্দ যোগ করা বর্তমানে আপনার অ্যাপ্লিকেশন ক্র্যাশ করার দ্রুততম উপায়। আওয়াজ কাট-আউট বা পুরো ব্রাউজার ট্যাব নামিয়ে নেওয়া অস্বাভাবিক নয়, তাই আপনার টিস্যুগুলি প্রস্তুত করুন৷

বিদায়কালীন অনুষ্ঠান

আবার, এখানে সম্পূর্ণ কার্যকরী গেম ডেমো । আপনি একটি জিপ হিসাবে সোর্স কোড ডাউনলোড করতে পারেন, এছাড়াও.

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

তথ্যসূত্র