# মহাকাশ গেম তৈরি করুন পর্ব ৩: গেমে গতি যোগ করা আপনার প্রিয় গেমগুলোর কথা ভাবুন – যা তাদের আকর্ষণীয় করে তোলে তা শুধুমাত্র সুন্দর গ্রাফিক্স নয়, বরং এটি কীভাবে আপনার ক্রিয়াগুলোর প্রতি সাড়া দেয় এবং চলাচল করে। এই মুহূর্তে, আপনার মহাকাশ গেমটি একটি সুন্দর চিত্রকর্মের মতো, তবে আমরা এতে গতি যোগ করতে যাচ্ছি যা এটিকে জীবন্ত করে তুলবে। যখন নাসার প্রকৌশলীরা অ্যাপোলো মিশনের জন্য গাইডেন্স কম্পিউটার প্রোগ্রাম করেছিলেন, তারা একই চ্যালেঞ্জের মুখোমুখি হয়েছিল: কীভাবে একটি মহাকাশযানকে পাইলটের ইনপুটের প্রতি সাড়া দেওয়া যায় এবং একই সাথে স্বয়ংক্রিয়ভাবে কোর্স সংশোধন বজায় রাখা যায়? আজ আমরা যে নীতিগুলো শিখব তা একই ধারণার প্রতিধ্বনি করে – খেলোয়াড়-নিয়ন্ত্রিত গতি এবং স্বয়ংক্রিয় সিস্টেমের আচরণ পরিচালনা করা। এই পাঠে, আপনি শিখবেন কীভাবে মহাকাশযানকে স্ক্রিনে গ্লাইড করতে, খেলোয়াড়ের কমান্ডের প্রতি সাড়া দিতে এবং মসৃণ গতি প্যাটার্ন তৈরি করতে হয়। আমরা সবকিছু সহজ ধারণায় ভেঙে দেব যা স্বাভাবিকভাবে একে অপরের উপর ভিত্তি করে তৈরি হয়। শেষে, আপনার খেলোয়াড়রা তাদের হিরো শিপকে স্ক্রিনে উড়িয়ে নিয়ে যাবে, যখন শত্রু জাহাজগুলো উপরে টহল দেবে। আরও গুরুত্বপূর্ণ, আপনি গেম মুভমেন্ট সিস্টেমের মূল নীতিগুলো বুঝতে পারবেন। ## প্রাক-লেকচার কুইজ [প্রাক-লেকচার কুইজ](https://ff-quizzes.netlify.app/web/quiz/33) ## গেম মুভমেন্ট বোঝা গেমগুলো তখনই জীবন্ত হয়ে ওঠে যখন জিনিসপত্র চারপাশে চলতে শুরু করে, এবং মূলত দুটি উপায়ে এটি ঘটে: - **খেলোয়াড়-নিয়ন্ত্রিত গতি**: যখন আপনি একটি কী চাপেন বা আপনার মাউস ক্লিক করেন, তখন কিছু একটা নড়ে। এটি আপনার এবং আপনার গেম জগতের মধ্যে সরাসরি সংযোগ। - **স্বয়ংক্রিয় গতি**: যখন গেম নিজেই জিনিসগুলোকে সরানোর সিদ্ধান্ত নেয় – যেমন শত্রু জাহাজগুলো স্ক্রিনে টহল দিতে থাকে, আপনি কিছু না করলেও। কম্পিউটার স্ক্রিনে বস্তু সরানো আপনার চিন্তার চেয়ে সহজ। গণিত ক্লাসের সেই x এবং y কোঅর্ডিনেট মনে আছে? এখানেই আমরা কাজ করছি। যখন গ্যালিলিও ১৬১০ সালে বৃহস্পতির চাঁদগুলো ট্র্যাক করেছিলেন, তিনি মূলত একই কাজ করছিলেন – গতির প্যাটার্ন বুঝতে সময়ের সাথে অবস্থান প্লট করছিলেন। স্ক্রিনে জিনিস সরানো ফ্লিপবুক অ্যানিমেশন তৈরি করার মতো – আপনাকে এই তিনটি সহজ ধাপ অনুসরণ করতে হবে: 1. **অবস্থান আপডেট করুন** – আপনার বস্তুটি কোথায় থাকা উচিত তা পরিবর্তন করুন (সম্ভবত এটি ডানদিকে ৫ পিক্সেল সরান) 2. **পুরানো ফ্রেম মুছুন** – স্ক্রিন পরিষ্কার করুন যাতে সর্বত্র ভূতুড়ে ট্রেইল দেখতে না পান 3. **নতুন ফ্রেম আঁকুন** – আপনার বস্তুটি তার নতুন স্থানে রাখুন এটি যথেষ্ট দ্রুত করুন, এবং বুম! আপনি মসৃণ গতি পাবেন যা খেলোয়াড়দের কাছে স্বাভাবিক মনে হয়। কোডে এটি দেখতে এমন হতে পারে: ```javascript // Set the hero's location hero.x += 5; // Clear the rectangle that hosts the hero ctx.clearRect(0, 0, canvas.width, canvas.height); // Redraw the game background and hero ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "black"; ctx.drawImage(heroImg, hero.x, hero.y); ``` **এই কোডটি যা করে:** - **আপডেট করে** হিরোর x-কোঅর্ডিনেট ৫ পিক্সেল দ্বারা, এটি অনুভূমিকভাবে সরানোর জন্য - **পরিষ্কার করে** পুরো ক্যানভাস এলাকা, পূর্ববর্তী ফ্রেমটি সরানোর জন্য - **ভরাট করে** ক্যানভাস একটি কালো ব্যাকগ্রাউন্ড রঙ দিয়ে - **পুনরায় আঁকে** হিরো ইমেজটি তার নতুন অবস্থানে ✅ আপনি কি ভাবতে পারেন কেন আপনার হিরোকে প্রতি সেকেন্ডে অনেক ফ্রেমে পুনরায় আঁকা পারফরম্যান্স খরচ বাড়াতে পারে? [এই প্যাটার্নের বিকল্প সম্পর্কে পড়ুন](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas)। ## কীবোর্ড ইভেন্ট পরিচালনা করুন এটি সেই জায়গা যেখানে আমরা খেলোয়াড়ের ইনপুটকে গেম অ্যাকশনের সাথে সংযুক্ত করি। যখন কেউ লেজার ফায়ার করতে স্পেসবার চাপ দেয় বা একটি অ্যাস্টেরয়েড এড়াতে একটি অ্যারো কী ট্যাপ করে, তখন আপনার গেমটি সেই ইনপুটটি সনাক্ত করতে এবং তার প্রতিক্রিয়া জানাতে হবে। কীবোর্ড ইভেন্টগুলো উইন্ডো স্তরে ঘটে, অর্থাৎ আপনার পুরো ব্রাউজার উইন্ডো সেই কীপ্রেসগুলো শোনে। অন্যদিকে, মাউস ক্লিকগুলো নির্দিষ্ট উপাদানের সাথে সংযুক্ত হতে পারে (যেমন একটি বোতামে ক্লিক করা)। আমাদের মহাকাশ গেমের জন্য, আমরা কীবোর্ড নিয়ন্ত্রণের উপর ফোকাস করব কারণ এটি খেলোয়াড়দের সেই ক্লাসিক আর্কেড অনুভূতি দেয়। এটি আমাকে মনে করিয়ে দেয় যে কীভাবে ১৮০০-এর দশকে টেলিগ্রাফ অপারেটরদের মোরস কোড ইনপুটকে অর্থপূর্ণ বার্তায় অনুবাদ করতে হয়েছিল – আমরা একই কাজ করছি, কীপ্রেসগুলোকে গেম কমান্ডে অনুবাদ করছি। একটি ইভেন্ট পরিচালনা করতে আপনাকে উইন্ডোর `addEventListener()` পদ্ধতি ব্যবহার করতে হবে এবং এটিকে দুটি ইনপুট প্যারামিটার প্রদান করতে হবে। প্রথম প্যারামিটারটি ইভেন্টের নাম, উদাহরণস্বরূপ `keyup`। দ্বিতীয় প্যারামিটারটি সেই ফাংশন যা ইভেন্টটি ঘটলে আহ্বান করা উচিত। এখানে একটি উদাহরণ: ```javascript window.addEventListener('keyup', (evt) => { // evt.key = string representation of the key if (evt.key === 'ArrowUp') { // do something } }); ``` **এখানে যা ঘটে তা বিশ্লেষণ করা:** - **শোনে** পুরো উইন্ডোতে কীবোর্ড ইভেন্টগুলো - **ধরে** ইভেন্ট অবজেক্ট যা কোন কী চাপা হয়েছে তার তথ্য ধারণ করে - **পরীক্ষা করে** চাপা কীটি একটি নির্দিষ্ট কী (এই ক্ষেত্রে, আপ অ্যারো) এর সাথে মেলে কিনা - **কোড কার্যকর করে** যখন শর্তটি পূরণ হয় কী ইভেন্টের জন্য ইভেন্টে দুটি প্রপার্টি থাকে যা আপনি দেখতে পারেন কোন কী চাপা হয়েছে: - `key` - এটি চাপা কীটির একটি স্ট্রিং উপস্থাপনা, উদাহরণ `'ArrowUp'` - `keyCode` - এটি একটি সংখ্যা উপস্থাপনা, উদাহরণ `37`, যা `ArrowLeft` এর সাথে মিলে ✅ গেম ডেভেলপমেন্টের বাইরে কী ইভেন্ট ম্যানিপুলেশনটি কার্যকর। এই কৌশলটির জন্য আপনি আর কী ব্যবহার করতে পারেন তা ভাবুন। ### বিশেষ কী: একটি সতর্কতা! কিছু কীতে বিল্ট-ইন ব্রাউজার আচরণ থাকে যা আপনার গেমের সাথে হস্তক্ষেপ করতে পারে। অ্যারো কীগুলো পৃষ্ঠাটি স্ক্রোল করে এবং স্পেসবার নিচে চলে যায় – এমন আচরণ যা আপনি চান না যখন কেউ তাদের মহাকাশযান চালানোর চেষ্টা করছে। আমরা এই ডিফল্ট আচরণগুলো প্রতিরোধ করতে পারি এবং আমাদের গেমটি ইনপুটটি পরিচালনা করতে দিতে পারি। এটি অনেকটা প্রাথমিক কম্পিউটার প্রোগ্রামাররা কাস্টম আচরণ তৈরি করতে সিস্টেম ইন্টারাপ্ট ওভাররাইড করার মতো – আমরা এটি ব্রাউজার স্তরে করছি। এটি কীভাবে করা যায়: ```javascript const onKeyDown = function (e) { console.log(e.keyCode); switch (e.keyCode) { case 37: case 39: case 38: case 40: // Arrow keys case 32: e.preventDefault(); break; // Space default: break; // do not block other keys } }; window.addEventListener('keydown', onKeyDown); ``` **এই প্রতিরোধ কোডটি বোঝা:** - **পরীক্ষা করে** নির্দিষ্ট কী কোডগুলো যা অবাঞ্ছিত ব্রাউজার আচরণ ঘটাতে পারে - **প্রতিরোধ করে** অ্যারো কী এবং স্পেসবারের জন্য ডিফল্ট ব্রাউজার অ্যাকশন - **অনুমতি দেয়** অন্যান্য কীগুলোকে স্বাভাবিকভাবে কাজ করতে - **ব্যবহার করে** `e.preventDefault()` ব্রাউজারের বিল্ট-ইন আচরণ বন্ধ করতে ## গেম দ্বারা প্ররোচিত গতি এখন আসুন এমন বস্তুগুলোর কথা বলি যা খেলোয়াড়ের ইনপুট ছাড়াই চলে। শত্রু জাহাজগুলো স্ক্রিনে ক্রুজ করে, গুলি সোজা লাইনে উড়ে যায়, বা মেঘ পটভূমিতে ভেসে বেড়ায়। এই স্বয়ংক্রিয় গতি আপনার গেম জগতকে জীবন্ত করে তোলে এমনকি কেউ নিয়ন্ত্রণ না করলেও। আমরা নিয়মিত বিরতিতে অবস্থান আপডেট করতে জাভাস্ক্রিপ্টের বিল্ট-ইন টাইমার ব্যবহার করি। এই ধারণাটি অনেকটা পেন্ডুলাম ঘড়ির মতো – একটি নিয়মিত প্রক্রিয়া যা ধারাবাহিক, সময়মতো ক্রিয়াগুলো ট্রিগার করে। এটি কতটা সহজ হতে পারে: ```javascript const id = setInterval(() => { // Move the enemy on the y axis enemy.y += 10; }, 100); ``` **এই গতি কোডটি যা করে:** - **একটি টাইমার তৈরি করে** যা প্রতি ১০০ মিলিসেকেন্ডে চলে - **আপডেট করে** শত্রুর y-কোঅর্ডিনেট প্রতি বার ১০ পিক্সেল দ্বারা - **সংরক্ষণ করে** ইন্টারভাল আইডি যাতে আমরা পরে এটি বন্ধ করতে পারি - **স্বয়ংক্রিয়ভাবে** শত্রুকে স্ক্রিনে নিচের দিকে সরায় ## গেম লুপ এখানে সেই ধারণাটি যা সবকিছু একত্রিত করে – গেম লুপ। যদি আপনার গেমটি একটি সিনেমা হয়, তাহলে গেম লুপটি হবে ফিল্ম প্রজেক্টর, ফ্রেমের পর ফ্রেম দেখানো এত দ্রুত যে সবকিছু মসৃণভাবে চলতে থাকে। প্রত্যেক গেমের পেছনে একটি লুপ চলতে থাকে। এটি একটি ফাংশন যা সমস্ত গেম অবজেক্ট আপডেট করে, স্ক্রিন পুনরায় আঁকে এবং এই প্রক্রিয়াটি ক্রমাগত পুনরাবৃত্তি করে। এটি আপনার হিরো, সমস্ত শত্রু, যেকোনো উড়ন্ত লেজার – পুরো গেম স্টেটের ট্র্যাক রাখে। এই ধারণাটি আমাকে মনে করিয়ে দেয় কীভাবে প্রাথমিক চলচ্চিত্র অ্যানিমেটররা যেমন ওয়াল্ট ডিজনি চরিত্রগুলোকে ফ্রেম বাই ফ্রেম পুনরায় আঁকতে হয়েছিল যাতে গতির বিভ্রম তৈরি হয়। আমরা একই কাজ করছি, শুধু কোড দিয়ে পেন্সিলের পরিবর্তে। গেম লুপ সাধারণত কোডে এমন দেখতে পারে: ```javascript const gameLoopId = setInterval(() => { function gameLoop() { ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.fillStyle = "black"; ctx.fillRect(0, 0, canvas.width, canvas.height); drawHero(); drawEnemies(); drawStaticObjects(); } gameLoop(); }, 200); ``` **গেম লুপ স্ট্রাকচার বোঝা:** - **পরিষ্কার করে** পুরো ক্যানভাস পূর্ববর্তী ফ্রেমটি সরানোর জন্য - **ভরাট করে** ব্যাকগ্রাউন্ড একটি সলিড রঙ দিয়ে - **আঁকে** সমস্ত গেম অবজেক্ট তাদের বর্তমান অবস্থানে - **পুনরাবৃত্তি করে** এই প্রক্রিয়াটি প্রতি ২০০ মিলিসেকেন্ডে মসৃণ অ্যানিমেশন তৈরি করতে - **ফ্রেম রেট পরিচালনা করে** ইন্টারভাল টাইমিং নিয়ন্ত্রণ করে ## মহাকাশ গেম চালিয়ে যাওয়া এখন আমরা পূর্বে তৈরি করা স্থির দৃশ্যে গতি যোগ করব। আমরা এটিকে একটি স্ক্রিনশট থেকে একটি ইন্টারঅ্যাকটিভ অভিজ্ঞতায় রূপান্তরিত করতে যাচ্ছি। আমরা ধাপে ধাপে কাজ করব যাতে প্রতিটি অংশ আগেরটির উপর ভিত্তি করে তৈরি হয়। পূর্ববর্তী পাঠে যেখানে আমরা থেমেছিলাম সেখান থেকে কোডটি নিন (অথবা যদি নতুন করে শুরু করতে চান তবে [Part II- starter](../../../../6-space-game/3-moving-elements-around/your-work) ফোল্ডারে কোডটি শুরু করুন)। **আজ আমরা যা তৈরি করছি:** - **হিরো নিয়ন্ত্রণ**: অ্যারো কীগুলো আপনার মহাকাশযানকে স্ক্রিনে চালাবে - **শত্রু গতি**: সেই এলিয়েন জাহাজগুলো তাদের অগ্রগতি শুরু করবে চলুন এই বৈশিষ্ট্যগুলো বাস্তবায়ন শুরু করি। ## সুপারিশকৃত ধাপগুলো `your-work` সাব ফোল্ডারে আপনার জন্য তৈরি করা ফাইলগুলো খুঁজুন। এটি নিম্নলিখিতটি ধারণ করা উচিত: ```bash -| assets -| enemyShip.png -| player.png -| index.html -| app.js -| package.json ``` আপনার প্রকল্পটি `your-work` ফোল্ডারে শুরু করুন এই কমান্ডটি টাইপ করে: ```bash cd your-work npm start ``` **এই কমান্ডটি যা করে:** - **আপনার প্রকল্প ডিরেক্টরিতে** নেভিগেট করে - **একটি HTTP সার্ভার শুরু করে** ঠিকানা `http://localhost:5000` এ - **আপনার গেম ফাইলগুলো পরিবেশন করে** যাতে আপনি সেগুলো ব্রাউজারে পরীক্ষা করতে পারেন উপরেরটি ঠিকানা `http://localhost:5000` এ একটি HTTP সার্ভার শুরু করবে। একটি ব্রাউজার খুলুন এবং সেই ঠিকানা ইনপুট করুন, এখন এটি হিরো এবং সমস্ত শত্রুদের রেন্ডার করা উচিত; কিছুই নড়ছে না - এখনও! ### কোড যোগ করুন 1. **`hero`, `enemy` এবং `game object` এর জন্য পৃথক অবজেক্ট যোগ করুন**, তাদের `x` এবং `y` প্রপার্টি থাকা উচিত। (ইনহেরিটেন্স বা কম্পোজিশনের অংশটি মনে রাখুন [Inheritance or composition](../README.md))। *ইঙ্গিত* `game object` হওয়া উচিত যার `x` এবং `y` এবং নিজেকে ক্যানভাসে আঁকার ক্ষমতা রয়েছে। > **টিপ**: একটি নতুন `GameObject` ক্লাস যোগ করে শুরু করুন যার কনস্ট্রাক্টর নিচের মতো বিভক্ত করা হয়েছে, এবং তারপর এটি ক্যানভাসে আঁকুন: ```javascript class GameObject { constructor(x, y) { this.x = x; this.y = y; this.dead = false; this.type = ""; this.width = 0; this.height = 0; this.img = undefined; } draw(ctx) { ctx.drawImage(this.img, this.x, this.y, this.width, this.height); } } ``` **এই বেস ক্লাসটি বোঝা:** - **সাধারণ প্রপার্টিগুলো সংজ্ঞায়িত করে** যা সমস্ত গেম অবজেক্ট শেয়ার করে (অবস্থান, আকার, ইমেজ) - **একটি `dead` ফ্ল্যাগ অন্তর্ভুক্ত করে** যা ট্র্যাক করে যে অবজেক্টটি সরানো উচিত কিনা - **একটি `draw()` পদ্ধতি প্রদান করে** যা ক্যানভাসে অবজেক্টটি রেন্ডার করে - **সমস্ত প্রপার্টির জন্য ডিফল্ট মান সেট করে** যা চাইল্ড ক্লাসগুলো ওভাররাইড করতে পারে এখন, এই `GameObject` প্রসারিত করুন `Hero` এবং `Enemy` তৈরি করতে: ```javascript class Hero extends GameObject { constructor(x, y) { super(x, y); this.width = 98; this.height = 75; this.type = "Hero"; this.speed = 5; } } ``` ```javascript class Enemy extends GameObject { constructor(x, y) { super(x, y); this.width = 98; this.height = 50; this.type = "Enemy"; const id = setInterval(() => { if (this.y < canvas.height - this.height) { this.y += 5; } else { console.log('Stopped at', this.y); clearInterval(id); } }, 300); } } ``` **এই ক্লাসগুলোতে মূল ধারণা:** - **`GameObject` থেকে উত্তরাধিকারী হয়** `extends` কীওয়ার্ড ব্যবহার করে - **প্যারেন্ট কনস্ট্রাক্টর কল করে** `super(x, y)` দিয়ে - **প্রতিটি অবজেক্ট টাইপের জন্য নির্দিষ্ট মাত্রা এবং প্রপার্টি সেট করে** - **`setInterval()` ব্যবহার করে শত্রুদের জন্য স্বয়ংক্রিয় গতি বাস্তবায়ন করে** 2. **কী-ইভেন্ট হ্যান্ডলার যোগ করুন** কী নেভিগেশনের জন্য (হিরোকে উপরে/নিচে বাম/ডানে সরান) *মনে রাখুন* এটি একটি কার্টেসিয়ান সিস্টেম, উপরের-বাম কোণটি `0,0`। এছাড়াও ডিফল্ট আচরণ বন্ধ করার কোড যোগ করতে ভুলবেন না। > **টিপ**: আপনার `onKeyDown` ফাংশন তৈরি করুন এবং এটি উইন্ডোতে সংযুক্ত করুন: ```javascript const onKeyDown = function (e) { console.log(e.keyCode); // Add the code from the lesson above to stop default behavior switch (e.keyCode) { case 37: case 39: case 38: case 40: // Arrow keys case 32: e.preventDefault(); break; // Space default: break; // do not block other keys } }; window.addEventListener("keydown", onKeyDown); ``` **এই ইভেন্ট হ্যান্ডলার যা করে:** - **কীডাউন ইভেন্টগুলো শোনে** পুরো উইন্ডোতে - **কী কোড লগ করে** কোন কী চাপা হচ্ছে তা ডিবাগ করতে সাহায্য করার জন্য - **অ্যারো কী এবং স্পেসবারের জন্য ডিফল্ট ব্রাউজার আচরণ প্রতিরোধ করে** - **অন্যান্য কীগুলোকে স্বাভাবিকভাবে কাজ করতে দেয়** এই মুহূর্তে আপনার ব্রাউজার কনসোলে চেক করুন, এবং কীস্ট্রোকগুলো লগ হচ্ছে দেখুন। 3. **[Pub sub pattern](../README.md) বাস্তবায়ন করুন**, এটি আপনার কোড পরিষ্কার রাখবে কারণ আপনি বাকি অংশগুলো অনুসরণ করবেন। পাবলিশ-সাবস্ক্রাইব প্যাটার্ন আপনার কোডকে সংগঠিত করতে সাহায্য করে ইভেন্ট সনাক্তকরণকে ইভেন্ট পরিচালনা থেকে আলাদা করে। এটি আপনার কোডকে আরও মডুলার এবং রক্ষণাবেক্ষণযোগ্য করে তোলে। এটি করতে, আপনি: 1. **উইন্ডোতে একটি ইভেন্ট লিসনার যোগ করুন**: ```javascript window.addEventListener("keyup", (evt) => { if (evt.key === "ArrowUp") { eventEmitter.emit(Messages.KEY_EVENT_UP); } else if (evt.key === "ArrowDown") { eventEmitter.emit(Messages.KEY_EVENT_DOWN); } else if (evt.key === "ArrowLeft") { eventEmitter.emit(Messages.KEY_EVENT_LEFT); } else if (evt.key === "ArrowRight") { eventEmitter.emit(Messages.KEY_EVENT_RIGHT); } }); ``` **এই ইভেন্ট সিস্টেম যা করে:** - **কীবোর্ড ইনপুট সনাক্ত করে** এবং এটিকে কাস্টম গেম ইভেন্টে রূপান্তর করে - **ইনপুট সনাক্তকরণকে গেম লজিক থেকে আলাদা করে** - **পরবর্তী সময়ে নিয়ন্ত্রণ পরিবর্তন করা সহজ করে তোলে** গেম কোডে প্রভাব না ফেলেই - **একাধিক সিস্টেমকে একই ইনপুটের প্রতিক্রিয়া জানাতে দেয়** 2. **একটি EventEmitter ক্লাস তৈরি করুন** বার্তা প্রকাশ এবং সাবস্ক্রাইব করতে: ```javascript class EventEmitter { constructor() { this.listeners = {}; } on(message, listener) { if (!this.listeners[message]) { this.listeners[message] = []; } this.listeners[message].push(listener); } 3. **কনস্ট্যান্ট যোগ করুন** এবং EventEmitter সেট আপ করুন: - **শত্রুদের** একটি গ্রিড তৈরি করে নেস্টেড লুপ ব্যবহার করে - **প্রতিটি শত্রু অবজেক্টে** শত্রু ইমেজ অ্যাসাইন করে - **প্রতিটি শত্রুকে** গ্লোবাল গেম অবজেক্টস অ্যারে-তে যোগ করে এবং একটি `createHero()` ফাংশন যোগ করুন যা হিরোর জন্য একই প্রক্রিয়া সম্পন্ন করবে। ```javascript function createHero() { hero = new Hero( canvas.width / 2 - 45, canvas.height - canvas.height / 4 ); hero.img = heroImg; gameObjects.push(hero); } ``` **হিরো তৈরির কাজ:** - **হিরোকে** স্ক্রিনের নিচের কেন্দ্রে পজিশন করে - **হিরো অবজেক্টে** হিরো ইমেজ অ্যাসাইন করে - **হিরোকে** গেম অবজেক্টস অ্যারে-তে যোগ করে রেন্ডারিংয়ের জন্য এবং শেষে একটি `drawGameObjects()` ফাংশন যোগ করুন ড্রয়িং শুরু করার জন্য: ```javascript function drawGameObjects(ctx) { gameObjects.forEach(go => go.draw(ctx)); } ``` **ড্রয়িং ফাংশন বুঝুন:** - **অ্যারে-তে থাকা** সব গেম অবজেক্টের মধ্য দিয়ে ইটারেট করে - **প্রতিটি অবজেক্টের** `draw()` মেথড কল করে - **ক্যানভাস কন্টেক্সট** পাস করে যাতে অবজেক্টগুলো নিজেদের রেন্ডার করতে পারে আপনার শত্রুরা আপনার হিরো স্পেসশিপের দিকে এগিয়ে আসা শুরু করবে! } } ``` and add a `createHero()` function to do a similar process for the hero. ```javascript function createHero() { hero = new Hero( canvas.width / 2 - 45, canvas.height - canvas.height / 4 ); hero.img = heroImg; gameObjects.push(hero); } ``` এবং শেষে একটি `drawGameObjects()` ফাংশন যোগ করুন ড্রয়িং শুরু করার জন্য: ```javascript function drawGameObjects(ctx) { gameObjects.forEach(go => go.draw(ctx)); } ``` আপনার শত্রুরা আপনার হিরো স্পেসশিপের দিকে এগিয়ে আসা শুরু করবে! --- ## GitHub Copilot Agent Challenge 🚀 এখানে একটি চ্যালেঞ্জ যা আপনার গেমের মান উন্নত করবে: বাউন্ডারি এবং স্মুথ কন্ট্রোল যোগ করা। বর্তমানে, আপনার হিরো স্ক্রিনের বাইরে উড়ে যেতে পারে এবং মুভমেন্টটি খানিকটা খসখসে মনে হতে পারে। **আপনার মিশন:** স্ক্রিন বাউন্ডারি এবং ফ্লুইড মুভমেন্ট ইমপ্লিমেন্ট করে আপনার স্পেসশিপকে আরও বাস্তবসম্মত করুন। এটি অনেকটা নাসার ফ্লাইট কন্ট্রোল সিস্টেমের মতো, যা স্পেসক্রাফটকে নিরাপদ অপারেশনাল প্যারামিটার অতিক্রম করতে বাধা দেয়। **আপনার যা তৈরি করতে হবে:** একটি সিস্টেম তৈরি করুন যা আপনার হিরো স্পেসশিপকে স্ক্রিনে রাখে এবং কন্ট্রোলগুলো স্মুথ করে। যখন প্লেয়াররা কোনো অ্যারো কী ধরে রাখে, তখন স্পেসশিপটি ডিসক্রিট স্টেপে না গিয়ে ক্রমাগত গ্লাইড করবে। স্ক্রিন বাউন্ডারিতে পৌঁছানোর সময় ভিজ্যুয়াল ফিডব্যাক যোগ করার কথা ভাবুন – হয়তো প্লে এরিয়ার প্রান্তে একটি সূক্ষ্ম ইফেক্ট। আরও জানুন [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) সম্পর্কে। ## 🚀 Challenge প্রজেক্ট বড় হওয়ার সাথে সাথে কোড অর্গানাইজেশন ক্রমশ গুরুত্বপূর্ণ হয়ে ওঠে। আপনি হয়তো লক্ষ্য করেছেন যে আপনার ফাইল ফাংশন, ভ্যারিয়েবল এবং ক্লাসের মিশ্রণে ভরে গেছে। এটি আমাকে অ্যাপোলো মিশন কোড অর্গানাইজ করার সময় ইঞ্জিনিয়ারদের কথা মনে করিয়ে দেয়, যেখানে স্পষ্ট এবং রক্ষণশীল সিস্টেম তৈরি করতে হয়েছিল যাতে একাধিক টিম একসাথে কাজ করতে পারে। **আপনার মিশন:** একজন সফটওয়্যার আর্কিটেক্টের মতো চিন্তা করুন। আপনি কীভাবে আপনার কোড অর্গানাইজ করবেন যাতে ছয় মাস পরেও আপনি (বা আপনার টিমমেট) বুঝতে পারেন কী ঘটছে? এখন সবকিছু এক ফাইলেই থাকলেও, আপনি আরও ভালো অর্গানাইজেশন তৈরি করতে পারেন: - **সম্পর্কিত ফাংশনগুলো** স্পষ্ট কমেন্ট হেডারের সাথে গ্রুপ করা - **কনসার্ন আলাদা করা** - গেম লজিককে রেন্ডারিং থেকে আলাদা রাখা - **কনসিস্টেন্ট নামকরণ** কনভেনশন ব্যবহার করা ভ্যারিয়েবল এবং ফাংশনের জন্য - **মডিউল বা নেমস্পেস তৈরি করা** গেমের বিভিন্ন দিক অর্গানাইজ করার জন্য - **ডকুমেন্টেশন যোগ করা** যা প্রতিটি প্রধান সেকশনের উদ্দেশ্য ব্যাখ্যা করে **রিফ্লেকশন প্রশ্ন:** - আপনার কোডের কোন অংশগুলোতে ফিরে আসলে সবচেয়ে কঠিন মনে হয়? - আপনি কীভাবে আপনার কোড অর্গানাইজ করবেন যাতে অন্য কেউ সহজে কন্ট্রিবিউট করতে পারে? - যদি আপনি নতুন ফিচার যেমন পাওয়ার-আপ বা বিভিন্ন শত্রু টাইপ যোগ করতে চান, তাহলে কী হবে? ## Post-Lecture Quiz [Post-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/34) ## Review & Self Study আমরা সবকিছু স্ক্র্যাচ থেকে তৈরি করছি, যা শেখার জন্য চমৎকার, কিন্তু এখানে একটি ছোট্ট গোপন কথা – কিছু অসাধারণ জাভাস্ক্রিপ্ট ফ্রেমওয়ার্ক আছে যা আপনার জন্য অনেক কাজ সহজ করে দিতে পারে। আমরা যে মৌলিক বিষয়গুলো কভার করেছি তাতে আপনি স্বাচ্ছন্দ্য বোধ করলে, [উপলব্ধ জিনিসগুলো একবার দেখে নেওয়া](https://github.com/collections/javascript-game-engines) মূল্যবান। ফ্রেমওয়ার্কগুলোকে ভাবুন যেন একটি ভালোভাবে সজ্জিত টুলবক্স, যেখানে প্রতিটি টুল নিজ হাতে তৈরি করতে হয় না। এগুলো অনেক কোড অর্গানাইজেশন চ্যালেঞ্জ সমাধান করতে পারে, এবং এমন ফিচার অফার করতে পারে যা তৈরি করতে আপনার সপ্তাহ লেগে যাবে। **যা এক্সপ্লোর করার মতো:** - গেম ইঞ্জিনগুলো কীভাবে কোড অর্গানাইজ করে – তাদের চমৎকার প্যাটার্ন দেখে আপনি অবাক হবেন - পারফরম্যান্স ট্রিকস যা ক্যানভাস গেমগুলোকে মসৃণভাবে চালাতে সাহায্য করে - আধুনিক জাভাস্ক্রিপ্ট ফিচার যা আপনার কোডকে আরও পরিষ্কার এবং রক্ষণশীল করতে পারে - গেম অবজেক্ট এবং তাদের সম্পর্ক ম্যানেজ করার বিভিন্ন পদ্ধতি ## Assignment [Comment your code](assignment.md) --- **অস্বীকৃতি**: এই নথিটি AI অনুবাদ পরিষেবা [Co-op Translator](https://github.com/Azure/co-op-translator) ব্যবহার করে অনুবাদ করা হয়েছে। আমরা যথাসাধ্য সঠিকতা নিশ্চিত করার চেষ্টা করি, তবে অনুগ্রহ করে মনে রাখবেন যে স্বয়ংক্রিয় অনুবাদে ত্রুটি বা অসঙ্গতি থাকতে পারে। নথিটির মূল ভাষায় থাকা আসল সংস্করণকে প্রামাণিক উৎস হিসেবে বিবেচনা করা উচিত। গুরুত্বপূর্ণ তথ্যের জন্য, পেশাদার মানব অনুবাদ সুপারিশ করা হয়। এই অনুবাদ ব্যবহারের ফলে কোনো ভুল বোঝাবুঝি বা ভুল ব্যাখ্যার জন্য আমরা দায়বদ্ধ নই।