1) প্লেয়ার: স্টেট-মেশিন + উপাদান ভিত্তিক আর্কিটেকচার।
প্লেয়ারের জন্য সাধারণ উপাদান: হেলথসিস্টেম, মুভমেন্ট সিস্টেম, ইনভেন্টরিসিস্টেম, অ্যাকশন সিস্টেম। এগুলি সব ক্লাসের মতো class HealthSystem
।
আমি Update()
সেখানে ব্যবহার করার পরামর্শ দিচ্ছি না (প্রতিটি ক্ষেত্রে সেখানে কোনও ক্রিয়া প্রয়োজন না হলে স্বাস্থ্য ব্যবস্থায় আপডেট হওয়া কোনও স্বাভাবিক ক্ষেত্রে এটির কোনও ধারণা নেই, এগুলি খুব কমই ঘটে। এক ক্ষেত্রে আপনি ভাবতেও পারেন - প্লেয়ার বিষাক্ত হয়ে যায় এবং আপনার তার প্রয়োজন হয়) সময়ে সময়ে স্বাস্থ্য হারাতে - এখানে আমি কর্টিনগুলি ব্যবহার করার পরামর্শ দিচ্ছি আরেকটি নিয়মিত স্বাস্থ্য বা চলমান শক্তি পুনরুত্পাদন করা, আপনি কেবলমাত্র বর্তমান স্বাস্থ্য বা শক্তি গ্রহণ করুন এবং সময় এলে সেই স্তরটি পূরণ করার জন্য কর্টিনকে কল করুন। স্বাস্থ্য পূর্ণ হলে বা কর্টিনকে বিরতি দিন তিনি ক্ষতিগ্রস্থ হয়েছেন বা তিনি আবার দৌড়াতে শুরু করেছিলেন এবং ঠিক আছে OK ঠিক আছে এটি কিছুটা অফটোপিক তবে আশা করি এটি কার্যকর ছিল) ।
যুক্তরাষ্ট্র: লুটস্টেট, রানস্টেট, ওয়াকস্টেট, অ্যাটাকস্টেট, আইডিএলস্টেট।
প্রতিটি রাষ্ট্র থেকে উত্তরাধিকার সূত্রে প্রাপ্ত interface IState
। IState
আমাদের ক্ষেত্রে রয়েছে একটি উদাহরণের জন্য 4 টি পদ্ধতি।Loot() Run() Walk() Attack()
এছাড়াও, আমরা class InputController
যেখানে ব্যবহারকারীর প্রতিটি ইনপুট পরীক্ষা করি।
এখন বাস্তব উদাহরণ হিসাবে: InputController
আমরা খেলোয়াড়ের যে কোনওটি প্রেস করে কিনা তা পরীক্ষা করে দেখি WASD or arrows
এবং তারপরে তিনি যদি চাপও দেন Shift
। যদি সে কেবল চাপ দেয় WASD
তবেই আমরা কল করি _currentPlayerState.Walk();
যখন এই সুখী হয় এবং আমাদের তখন currentPlayerState
সমান হতে হয় WalkState
যখন WalkState.Walk()
আমাদের এই রাজ্যের জন্য প্রয়োজনীয় সমস্ত উপাদান রয়েছে - এই ক্ষেত্রে MovementSystem
, আমরা খেলোয়াড়কে সরানো করি public void Walk() { _playerMovementSystem.Walk(); }
- আপনি দেখুন আমাদের এখানে কী আছে? আমাদের আচরণের দ্বিতীয় স্তর রয়েছে এবং কোড রক্ষণাবেক্ষণ এবং ডিবাগিংয়ের জন্য এটি খুব ভাল।
এখন দ্বিতীয় ক্ষেত্রে: আমরা যদি WASD
+ Shift
টিপে থাকি তবে কী হবে ? তবে আমাদের আগের অবস্থা ছিল WalkState
। এই ক্ষেত্রে Run()
মধ্যে ডাকা হবে InputController
(এই তালগোল না, Run()
কারণ আমরা আছে বলা হয় WASD
+ + Shift
চেক InputController
কারণ না WalkState
)। আমরা যখন কল _currentPlayerState.Run();
মধ্যে WalkState
- আমরা জানি আমরা সুইচ আছে _currentPlayerState
করার RunState
এবং আমরা তা করতে Run()
এর WalkState
এবং এই পদ্ধতি ভিতরে আবার সেটিতে কল কিন্তু এখন একটি ভিন্ন রাষ্ট্রের সাথে কারণ আমরা হারান কর্ম এই ফ্রেম চাই না। এবং এখন অবশ্যই আমরা কল _playerMovementSystem.Run();
।
কিন্তু LootState
যখন খেলোয়াড় হাঁটতে বা চালাতে না পারে ততক্ষণ সে কী বোতামটি ছেড়ে দেয়? ঠিক আছে এই ক্ষেত্রে যখন আমরা লুটপাট শুরু করি, উদাহরণস্বরূপ যখন বোতাম E
টিপানো হয়েছিল তখন আমরা কল _currentPlayerState.Loot();
করি আমরা স্যুইচ করি LootState
এবং এখন সেখান থেকে কলটি কল করি। সেখানে আমরা উদাহরণস্বরূপ কল সংঘর্ষের পদ্ধতিটি পেয়েছি যদি এখানে সীমার মধ্যে লুটপাটের কিছু থাকে। এবং আমরা কর্টিনকে কল করি যেখানে আমাদের একটি অ্যানিমেশন রয়েছে বা যেখানে আমরা এটি শুরু করেছি এবং এটি পরীক্ষা করে দেখুন যে প্লেয়ারটি এখনও বোতামটি ধরে রেখেছে কিনা, যদি কর্টিন বিরতি না ঘটে, যদি হ্যাঁ আমরা তাকে কর্টিনের শেষে লুট দিই। তবে প্লেয়ার চাপলে WASD
কী হবে? - _currentPlayerState.Walk();
বলা হয়, কিন্তু এখানে রাষ্ট্র-মেশিন সম্পর্কে সুন্দর জিনিস thingLootState.Walk()
আমাদের একটি শূন্য পদ্ধতি রয়েছে যা কিছুই করে না বা যেমন আমি বৈশিষ্ট্য হিসাবে করব - খেলোয়াড়রা বলেছেন: "আরে মানুষ, আমি এখনও এটিকে লুট করি নি, আপনি কি অপেক্ষা করতে পারেন?" সে যখন লুটপাট শেষ করে, তখন আমরা পরিবর্তন করি IDLEState
।
এছাড়াও, আপনি অন্য একটি স্ক্রিপ্ট করতে পারেন যা ডাকা হয় class BaseState : IState
যা এই সমস্ত ডিফল্ট পদ্ধতির আচরণ বাস্তবায়িত হয়েছে, তবে সেগুলি রয়েছে virtual
যাতে আপনি override
তাদের class LootState : BaseState
ধরণের শ্রেণিতে করতে পারেন ।
উপাদান ভিত্তিক সিস্টেমটি দুর্দান্ত, কেবলমাত্র এটিই আমাকে বিরক্ত করে তা উদাহরণস্বরূপ, এর মধ্যে অনেকগুলি। এবং এটি মেমরির বেশি লাগে এবং আবর্জনা সংগ্রাহকের জন্য কাজ করে। উদাহরণস্বরূপ, আপনার কাছে শত্রুর 1000 টি উদাহরণ রয়েছে। তাদের সকলের 4 টি উপাদান রয়েছে। 1000 এর পরিবর্তে 4000 অবজেক্ট। এমবি এটি এত বড় ব্যাপার নয় (আমি পারফরম্যান্স টেস্টগুলি চালাইনি) যদি আমরা unityক্য গেমোবজেক্টের সমস্ত উপাদান বিবেচনা করি।
2) উত্তরাধিকার ভিত্তিক আর্কিটেকচার। যদিও আপনি লক্ষ্য করবেন যে আমরা উপাদানগুলি সম্পূর্ণরূপে মুক্তি দিতে পারি না - এটি যদি আমাদের পরিষ্কার এবং কার্যকরী কোড রাখতে চান তবে এটি অসম্ভব। এছাড়াও, আমরা যদি ডিজাইন প্যাটার্নগুলি ব্যবহার করতে চাই যা যথাযথ ক্ষেত্রে ব্যবহার করার জন্য অত্যন্ত প্রস্তাবিত হয় (সেগুলিকে খুব বেশি ব্যবহার করবেন না, একে ওভারেনজেনিয়ারিং বলা হয়)।
কল্পনা করুন আমাদের একটি খেলোয়াড় শ্রেণি রয়েছে যা একটি গেম থেকে বেরিয়ে আসার জন্য প্রয়োজনীয় সমস্ত বৈশিষ্ট্য রয়েছে। এটিতে স্বাস্থ্য, মন বা শক্তি রয়েছে, চলতে পারে, চালনা করতে এবং দক্ষতা ব্যবহার করতে পারে, একটি জায় আছে, আইটেম কারুকাজ করতে পারে, আইটেম লুট করতে পারে, এমনকি কিছু ব্যারিকেড বা বারান্দা তৈরি করতে পারে।
সবার আগে আমি বলতে যাচ্ছি যে ইনভেন্টরি, ক্র্যাফটিং, মুভিং, বিল্ডিংয়ের উপাদানগুলি ভিত্তিক হওয়া উচিত কারণ এটির মতো পদ্ধতি থাকার প্লেয়ারের দায়বদ্ধতা নেই AddItemToInventoryArray()
- যদিও খেলোয়াড়ের এমন পদ্ধতি থাকতে পারে PutItemToInventory()
যা পূর্ববর্তী বর্ণিত পদ্ধতিটিকে কল করতে পারে (2 স্তর - আমরা পারি বিভিন্ন স্তরগুলির উপর নির্ভর করে কিছু শর্ত যুক্ত করুন)।
বিল্ডিং সহ আরও একটি উদাহরণ। প্লেয়ার এর মতো কিছু কল করতে পারে OpenBuildingWindow()
, তবে Building
সমস্ত অংশের যত্ন নেবে এবং ব্যবহারকারী যখন নির্দিষ্ট নির্দিষ্ট বিল্ডিং তৈরি করার সিদ্ধান্ত নেয়, তখন সে সমস্ত প্রয়োজনীয় তথ্য খেলোয়াড়ের কাছে পৌঁছে দেয় Build(BuildingInfo someBuildingInfo)
এবং প্লেয়ার প্রয়োজনীয় সমস্ত অ্যানিমেশন দিয়ে এটি তৈরি করতে শুরু করে।
সলিড - ওওপি নীতিগুলি। এস - একক দায়িত্ব: আমরা আগের উদাহরণগুলিতে যা দেখেছি। হ্যাঁ ঠিক আছে, তবে উত্তরাধিকার কোথায়?
এখানে: খেলোয়াড়ের স্বাস্থ্য এবং অন্যান্য বৈশিষ্ট্যগুলি কি অন্য সত্তা দ্বারা পরিচালিত হওয়া উচিত? আমি মনে করি না. স্বাস্থ্য ছাড়া খেলোয়াড় থাকতে পারে না, যদি সেখানে থাকে তবে আমরা উত্তরাধিকার সূত্রে পাই না। উদাহরণস্বরূপ, আমরা আছে IDamagable
, LivingEntity
, IGameActor
, GameActor
। IDamagable
অবশ্যই আছে TakeDamage()
।
class LivinEntity : IDamagable {
private float _health; // For fields that are the same between Instances I would use Flyweight Pattern.
public void TakeDamage() {
....
}
}
class GameActor : LivingEntity, IGameActor {
// Here goes state machine and other attached components needed.
}
class Player : GameActor {
// Inventory, Building, Crafting.... components.
}
সুতরাং এখানে আমি উত্তরাধিকার থেকে উপাদানগুলি ভাগ করতে পারি নি, তবে আপনি যেমন দেখেন তেমন আমরা সেগুলি মিশ্রিত করতে পারি। আমরা বিল্ডিং সিস্টেমের জন্য কিছু বেস ক্লাসও তৈরি করতে পারি উদাহরণস্বরূপ আমাদের যদি এর বিভিন্ন ধরণের থাকে এবং আমরা প্রয়োজনের চেয়ে বেশি কোনও কোড লিখতে চাই না। প্রকৃতপক্ষে আমাদের বিভিন্ন ধরণের বিল্ডিং থাকতে পারে এবং এটির উপাদানটি ভিত্তিক করার কোনও ভাল উপায় নেই!
OrganicBuilding : Building
, TechBuilding : Building
। সাধারণ ক্রিয়াকলাপ বা বিল্ডিংয়ের বৈশিষ্ট্যগুলির জন্য আপনাকে 2 টি উপাদান তৈরি করতে এবং কোড লিখতে হবে না। এবং তারপরে এগুলিকে আলাদা করে যুক্ত করুন, আপনি উত্তরাধিকারের ক্ষমতা এবং পরে পলিমারফিজম এবং ইনকিপুলেশন ব্যবহার করতে পারেন।
আমি এর মধ্যে কিছু ব্যবহার করার পরামর্শ দেব। এবং অতিরিক্ত উপাদান ব্যবহার করে না।
আমি গেম প্রোগ্রামিং প্যাটার্নস সম্পর্কে এই বইটি পড়ার সর্বাধিক পরামর্শ দিই - এটি WEB এ বিনামূল্যে B