paint-brush
অবজেক্টপুল প্যাটার্ন ব্যবহার করে আপনার গেম প্রজেক্টকে কীভাবে উন্নত করবেন (একতা নির্দেশিকা)দ্বারা@jokeresdeu
906 পড়া
906 পড়া

অবজেক্টপুল প্যাটার্ন ব্যবহার করে আপনার গেম প্রজেক্টকে কীভাবে উন্নত করবেন (একতা নির্দেশিকা)

দ্বারা Les Dibrivniy16m2023/05/10
Read on Terminal Reader
Read this story w/o Javascript

অতিদীর্ঘ; পড়তে

অবজেক্ট পুল হল 99% গেম প্রজেক্টের অপ্টিমাইজেশনের ভিত্তি। এটি একটি প্রাথমিক নীতির উপর ভিত্তি করে: এটির কাজ শেষ করার পরে, বস্তুটি মুছে ফেলা হয় না তবে একটি পৃথক পরিবেশে স্থানান্তরিত হয় এবং পুনরুদ্ধার এবং পুনরায় ব্যবহার করা যেতে পারে। Les Dibrivniy ব্যাখ্যা করেন কেন এই প্যাটার্ন অপরিহার্য।
featured image - অবজেক্টপুল প্যাটার্ন ব্যবহার করে আপনার গেম প্রজেক্টকে কীভাবে উন্নত করবেন (একতা নির্দেশিকা)
Les Dibrivniy HackerNoon profile picture
0-item
1-item

হাই সেখানে, আমার নাম ওলেস ডিব্রিভনি, এবং আমি কেইকিতে একতা বিকাশকারী। আমরা EdTech এবং GameDev-এর সংযোগস্থলে পণ্য তৈরি করি — শিশুদের বিকাশের জন্য অ্যাপ এবং ওয়েব পণ্য। এখন আমাদের পণ্যের ব্যবহারকারী চার মিলিয়নেরও বেশি।

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

এই প্যাটার্নটি সরাসরি অ্যাপ সম্পর্কে ব্যবহারকারীর ধারণাকে প্রভাবিত করে, তাই এটি অত্যন্ত গুরুত্বপূর্ণ। এটি 99% গেম প্রকল্পের অপ্টিমাইজেশনের ভিত্তি হওয়া উচিত।

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


অবজেক্টপুল ছাড়া জিনিসগুলি কীভাবে যায়?

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

আসুন বিবেচনা করা যাক ফায়ারবল নিজেই কেমন হবে। ক্ষেত্র

 Rigidbody2D
এবং
 _speed
ফায়ারবলের আন্দোলনের জন্য দায়ী থাকবে; দ্য
 OnTriggerEnter2D
সংঘর্ষের পরে পদ্ধতিটি কাজ করবে — ফায়ারবল উপাদান সহ বস্তুটি ধ্বংস হয়ে যাবে:

 public class FireBall : MonoBehaviour 2 { 3 [SerializeField] private Rigidbody2D _rigidbody; 4 [SerializeField] private float _speed; 5   
6 public void FlyInDirection(Vector2 flyDirection) 7 { 8 _rigidbody.velocity = flyDirection * _speed; 9 } 10   
11 private void OnTriggerEnter2D(Collider2D other) 12 { 13 Destroy(gameObject); 14 } 15 }

শত্রুও বেশ সহজ দেখাবে:

 public class Enemy : MonoBehaviour 2 { 3 [SerializeField] private FireBall _fireBall; 4 [SerializeField] private Transform _castPoint; 5   
6 public void Cast() 7 { 8 FireBall fireBall = Instantiate(_fireBall, _castPoint.position, Quaternion.identity); 9 fireBall.FlyInDirection(transform.right); 10 } 11 }

আপনি কল করতে পারেন

 Cast
আপনার প্রজেক্ট বা অ্যানিমেশন ইভেন্টের যেকোনো বিন্দু থেকে পদ্ধতি। আমাদের নিম্নলিখিত প্রবাহ রয়েছে: শত্রু একটি ফায়ারবল তৈরি করেছে এবং তার দৃষ্টির দিকে এটি চালু করেছে। পথের প্রথম বাধায় পৌঁছে আগুনের গোলা ধ্বংস হয়ে যায়।

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

1. ডিভাইসের CPU এবং মেমরির অদক্ষ ব্যবহার।

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

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

এই প্রক্রিয়াগুলি রানটাইমে ক্রমাগত ঘটে। আপনি মঞ্চে শত শত বস্তু তৈরি করার পরে ক্রমাগত মেমরি বরাদ্দের কারণে প্লেয়ারটি ফ্রেমে লক্ষণীয় হ্রাস অনুভব করতে পারে।

2. আপনি যা কিছু তৈরি করেছেন তা অবশ্যই ধ্বংস এবং পরিষ্কার করতে হবে। দ্য

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

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

এর প্রকল্পের মধ্যে অবজেক্টপুল সংহত করা যাক!

সমস্যাটি সংজ্ঞায়িত করার পরে, এর সমাধানের দিকে এগিয়ে যাওয়া যাক। আমি আগে উল্লেখ করেছি, অবজেক্টপুল প্যাটার্ন অপারেশনের নীতিটি সহজ: বস্তুর সাথে কাজ শেষ করার পরে, এটি মুছে ফেলা হয় না তবে "পুলে" লুকিয়ে থাকে। বস্তুটি পুনরুদ্ধার করা যেতে পারে এবং এটি থেকে পুনরায় ব্যবহার করা যেতে পারে:

একটি সত্তা একটি বস্তু তৈরি, পুনঃব্যবহার এবং ধ্বংস করার জন্য দায়ী - আমরা এটিকে কল করব

 ObjectPool
. ফায়ারবলের সাথে কাজ করার জন্য আমরা এটিকে এর মতো দেখতে পারি:

 public class ObjectPool : MonoBehaviour 2 { 3 [SerializeField] private FireBall _fireBallPrefab; 4   
5 private readonly List <FireBall> _freeFireBalls = new List <FireBall>(); 6   
7 public FireBall GetFireBall() 8 { 9 FireBall fireBall; 10       if (_freeFireBalls.Count > 0 ) 11 { 12 fireBall = _freeFireBalls[ 0 ]; 13 _freeFireBalls. Remove(fireBall);
14 } 15       else
16 { 17 fireBall = Instantiate(_fireBallPrefab, transform); 18 } 19       return fireBall; 20 } 21   
22 private void ReturnFireBall(FireBall fireBall) 23 { 24 _freeFireBalls.Add(fireBall); 25 } 26 }

দ্য

 _freeFireBalls
তালিকা এই কোডে প্রদর্শিত হবে। আমরা তৈরি করা ফায়ারবলগুলিকে সংরক্ষণ করব যা সেখানে তাদের কাজ করেছে। শত্রু এখন এই মত দেখাবে:

 public class Enemy : MonoBehaviour 2 { 3 [SerializeField] private ObjectPool _objectPool; 4 [SerializeField] private Transform _castPoint; 5   
6 public void Cast() 7 { 8 FireBall fireBall = _objectPool.GetFireBall(); 9 fireBall.transform.position = _castPoint.position; 10 fireBall.FlyInDirection(transform.right); 11 } 12 }

আমাদের সমস্যার মূল: কিভাবে আমরা পুলে ফায়ারবল ফিরিয়ে দিতে পারি? আমরা শত্রুর উপর নির্ভর করতে পারি না; আগুনের গোলা কখন ধ্বংস হবে তা তিনি জানেন না। আমরা ফায়ারবল সম্পর্কে জ্ঞান দিতে চাই না

 ObjectPool
, কারণ এটি অপ্রয়োজনীয় সংযোগ তৈরি করবে।

আমি আশা করি আপনি লক্ষ্য করেছেন যে আমি তৈরি করেছি

 ReturnFireBall
পদ্ধতি ব্যক্তিগত। অতএব, আমরা একটি মৌলিক C# প্যাটার্ন ব্যবহার করব — পর্যবেক্ষক, এবং এর বাস্তবায়ন — ইভেন্ট । ফায়ারবল এখন এই মত দেখাবে:

 public class FireBall : MonoBehaviour 2 { 3 [SerializeField] private Rigidbody2D _rigidbody; 4 [SerializeField] private float _speed; 5   
6 public event Action<FireBall> Destroyed; 7   
8 public void FlyInDirection(Vector2 flyDirection) 9 { 10 _rigidbody.velocity = flyDirection * _speed; 11 } 12   
13 private void OnTriggerEnter2D(Collider2D other) 14 { 15 Destroyed?.Invoke(this); 16 } 17 }

 ObjectPool
সাবস্ক্রাইব করবে
 Destroyed
পৃথিবীতে বস্তুটি পাস করার পরে ঘটনা:

 public class ObjectPool : MonoBehaviour 2 { 3 [SerializeField] private FireBall _fireBallPrefab; 4 private readonly List <FireBall> _freeFireBalls = new List <FireBall>(); 5   
6 public FireBall GetFireBall() 7 { 8 FireBall fireBall; 9       if (_freeFireBalls.Count > 0 ) 10 { 11 fireBall = _freeFireBalls[ 0 ]; 12 _freeFireBalls. Remove(fireBall);
13 } 14       else
15 { 16 fireBall = Instantiate(_fireBallPrefab, transform); 17 } 18 fireBall.Destroyed += ReturnFireBall; 19       return fireBall; 20 } 21   
22 private void ReturnFireBall(FireBall fireBall) 23 { 24 fireBall.Destroyed -= ReturnFireBall; 25 _freeFireBalls.Add(fireBall); 26 } 27 }

এটি অবজেক্টের সাথে অবজেক্ট পুলটি ঝুলিয়ে রাখা অবশেষ

 Enemy
উপাদান - অভিনন্দন! আবর্জনা সংগ্রহকারী বিশ্রাম নেবে যতক্ষণ না আপনি অন্য দৃশ্যে যান বা গেমটি বন্ধ করেন। আমাদের কাছে অবজেক্টপুল এর মৌলিক বাস্তবায়ন রয়েছে, তবে আমরা এটিকে উন্নত করতে পারি।

ইন্টারফেস এবং জেনেরিক: অবজেক্টপুলের সাথে নিখুঁত মিল

দ্য

 FireBall
একমাত্র অবজেক্ট টাইপ নয় যা আমরা অবজেক্ট পুলের মাধ্যমে চালাব। আলাদা করে লিখতে হবে
 ObjectPool
প্রতিটি অন্য ধরনের সঙ্গে কাজ করার জন্য. এটি কোড বেস প্রসারিত করবে এবং কোডটিকে কম পঠনযোগ্য করে তুলবে। সুতরাং, আসুন অনুকরণ এবং জেনেরিক ব্যবহার করি।

প্রতিটি বস্তুর মাধ্যমে আমরা চালানো

 ObjectPool
একটি নির্দিষ্ট ধরনের আবদ্ধ হতে হবে। সেগুলি অবশ্যই নির্দিষ্ট বাস্তবায়নের স্বাধীনভাবে প্রক্রিয়া করা উচিত। পুল যে বস্তুগুলিকে প্রক্রিয়া করবে তার মৌলিক উত্তরাধিকার শ্রেণিবিন্যাস রাখা অপরিহার্য। তারা উত্তরাধিকার সূত্রে পাবে
 MonoBehaviour
, অন্তত. আসুন IPoolable ইন্টারফেস ব্যবহার করি:

 public interface IPoolable 2 { 3 GameObject GameObject { get ; } 4 event Action<IPoolable> Destroyed; 5 void Reset (); 6 }

আমরা উত্তরাধিকারী

 FireBall
ইহা হতে:

 public class FireBall : MonoBehaviour, IPoolable 2 { 3 [SerializeField] private Rigidbody2D _rigidbody; 4 [SerializeField] private float _speed; 5 public GameObject GameObject => gameObject; 6   
7 public event Action<IPoolable> Destroyed; 8   
9 private void OnTriggerEnter2D(Collider2D other) 10 { 11       Reset (); 12 } 13 public void Reset () 14 { 15 Destroyed?.Invoke(this); 16 } 17   
18 public void FlyInDirection(Vector2 flyDirection) 19 { 20 _rigidbody.velocity = flyDirection * _speed; 21 } 22 }

শেষ কাজ শেখানো

 ObjectPool
যেকোনো বস্তুর সাথে কাজ করতে। IPoolable যথেষ্ট হবে না কারণ Instantiate শুধুমাত্র এর সাথে বস্তুর একটি অনুলিপি তৈরি করতে পারে
 gameObject
সম্পত্তি আমরা ব্যবহার করবো
 Component
; এই ধরনের প্রতিটি বস্তু এই শ্রেণীর থেকে উত্তরাধিকারসূত্রে প্রাপ্ত।
 MonoBehaviour
এটি থেকে উত্তরাধিকারসূত্রে পাওয়া যায়। ফলস্বরূপ, আমরা নিম্নলিখিত পেতে হবে
 ObjectPool
:

 public class ObjectPool<T> where T : Component, IPoolable 2 { 3 private readonly List <IPoolable> _freeObjects; 4 private readonly Transform _container; 5 private readonly T _prefab; 6   
7 public ObjectPool(T prefab) 8 { 9 _freeObjects = new List <IPoolable>(); 10 _container = new GameObject().transform; 11 _container. name = prefab.GameObject. name ; 12 _prefab = prefab; 13 } 14   
15 public IPoolable GetFreeObject() 16 { 17 IPoolable poolable; 18       if (_freeObjects.Count > 0 ) 19 { 20 poolable = _freeObjects[ 0 ] as T; 21 _freeObjects. RemoveAt(0);
22 } 23       else
24 { 25 poolable = Object.Instantiate(_prefab, _container); 26 } 27 poolable.GameObject.SetActive(true); 28 poolable.Destroyed += ReturnToPool; 29       return poolable; 30 } 31   
32 private void ReturnToPool(IPoolable poolable) 33 { 34 _freeObjects.Add(poolable); 35 poolable.Destroyed -= ReturnToPool; 36 poolable.GameObject.SetActive(false); 37 poolable.GameObject.transform.SetParent(_container); 38 } 39 }

এখন আমরা একটি তৈরি করতে পারি

 ObjectPool
যে কোনো বস্তুর জন্য যা থেকে উত্তরাধিকারের শর্ত পূরণ করে
 Component
এবং আইপুলযোগ্য। আমি সরিয়ে দিলাম
 ObjectPool
থেকে উত্তরাধিকার
 MonoBehaviour
, এইভাবে উপাদানের সংখ্যা কমিয়ে আমরা বস্তুতে ঝুলিয়ে রাখব।

একটি সমস্যা আছে যা সমাধান করা প্রয়োজন। বেশ কয়েকটি শত্রু একই সময়ে মঞ্চে থাকতে পারে এবং তাদের প্রত্যেকে একই ফায়ারবলের জন্ম দেয়। তারা সবাই একই মধ্য দিয়ে গেলে এটি দুর্দান্ত হবে

 ObjectPool
- খুব বেশি সম্পদ সঞ্চয় হতে পারে না! একটি নির্দিষ্ট অবজেক্ট টাইপের জন্য একটি ক্লাস জিজ্ঞাসা করাও বেশ সুবিধাজনক। এই ধরনের একটি শ্রেণী বস্তুর প্রজন্ম, নিয়ন্ত্রণ, এবং শেষ নিষ্পত্তির দায়িত্ব গ্রহণ করবে। এই বিকল্পটি প্রতিটি পরিচালনার জন্য সেরা পছন্দ
 ObjectPool
ব্যক্তিগতভাবে প্রকল্পে চ্যালেঞ্জিং.

এর মৌলিক প্রয়োজনীয়তা পূরণ করতে

 ObjectPool
, দৃশ্যটি লোড হওয়ার সময় আমাদের একটি নির্দিষ্ট সংখ্যক বস্তু তৈরি করতে হবে। কোনো সম্পদ খরচ সমস্যা এড়াতে, আমরা একটি লোডিং উইন্ডো অন্তর্ভুক্ত করব। এখন এটি বাস্তবায়ন শুরু করা যাক.

আমরা একটি অতিরিক্ত সত্তা তৈরি করব

 PoolTask
এর চূড়ান্ত বাস্তবায়নে
 ObjectPool
. এই ক্লাসটি একটি প্রিফ্যাব থেকে তৈরি বস্তুর সাথে কাজ নিয়ন্ত্রণ করবে:

 public class PoolTask 2 { 3 private readonly List <IPoolable> _freeObjects; 4 private readonly List <IPoolable> _objectsInUse; 5 private readonly Transform _container; 6   
7 public PoolTask(Transform container) 8 { 9 _container = container; 10 _objectsInUse = new List <IPoolable>(); 11 _freeObjects = new List <IPoolable>(); 12 } 13   
14 public void CreateFreeObjects<T>(T prefab, int count) where T : Component, IPoolable 15 { 16       for (var i = 0 ; i < count; i++) 17 { 18 var poolable = Object.Instantiate(prefab, _container); 19 _freeObjects.Add(poolable); 20 } 21 } 22   
23 public T GetFreeObject<T>(T prefab) where T : Component, IPoolable 24 { 25 T poolable; 26       if (_freeObjects.Count > 0 ) 27 { 28 poolable = _freeObjects[ 0 ] as T; 29 _freeObjects. RemoveAt(0);
30 } 31       else
32 { 33 poolable = Object.Instantiate(prefab, _container); 34 } 35 poolable.Destroyed += ReturnToPool; 36 poolable.GameObject.SetActive(true); 37 _objectsInUse.Add(poolable); 38       return poolable; 39 } 40   
41 public void ReturnAllObjectsToPool() 42 { 43 foreach (var poolable in _objectsInUse) 44 poolable. Reset (); 45 } 46   
47 public void Dispose() 48 { 49 foreach (var poolable in _objectsInUse) 50 Object.Destroy(poolable.GameObject); 51       
52 foreach (var poolable in _freeObjects) 53 Object.Destroy(poolable.GameObject); 54 } 55   
56 private void ReturnToPool(IPoolable poolable) 57 { 58 _objectsInUse. Remove(poolable);
59 _freeObjects.Add(poolable); 60 poolable.Destroyed -= ReturnToPool; 61 poolable.GameObject.SetActive(false); 62 poolable.GameObject.transform.SetParent(_container); 63 } 64 }

পুলটাস্কের অতিরিক্ত বৈশিষ্ট্য থাকবে:

1. আমরা পৃথিবীতে ছেড়ে দিয়েছি এমন বস্তুগুলিকে ট্র্যাক করা যাতে প্রয়োজনে সেগুলিকে ধ্বংস করা যায় বা একটি নির্দিষ্ট মুহুর্তে পুলে ফিরিয়ে দেওয়া যায়;

2. মুক্ত বস্তুর একটি পূর্বনির্ধারিত পরিমাণ তৈরি করা।

অবশেষে, আসুন একটি অবজেক্টপুল তৈরি করি যা আমাদের সমস্ত চাহিদা মেটাবে এবং বস্তুর নিয়ন্ত্রণ এবং প্রজন্ম সম্পূর্ণরূপে গ্রহণ করবে:

 public class ObjectPool 2 { 3 private static ObjectPool _instance; 4 public static ObjectPool Instance => _instance ??= new ObjectPool(); 5   
6 private readonly Dictionary<Component, PoolTask> _activePoolTasks; 7 private readonly Transform _container; 8  
9 private ObjectPool() 10 { 11 _activePoolTasks = new Dictionary<Component, PoolTask>(); 12 _container = new GameObject().transform; 13 _container. name = nameof(ObjectPool); 14 } 15   
16 public void CreateFreeObjects<T>(T prefab, int count) where T : Component, IPoolable 17 { 18       if (!_activePoolTasks.TryGetValue(prefab, out var poolTask)) 19 AddTaskToPool(prefab, out poolTask); 20       
21 poolTask.CreateFreeObjects(prefab, count); 22 } 23   
24 public T GetObject<T>(T prefab) where T : Component, IPoolable 25 { 26       if (!_activePoolTasks.TryGetValue(prefab, out var poolTask)) 27 AddTaskToPool(prefab, out poolTask); 28       return poolTask.GetFreeObject(prefab); 29 } 30   
31 public void Dispose() 32 { 33 foreach (var poolTask in _activePoolTasks.Values) 34 poolTask.Dispose(); 35 } 36   
37 private void AddTaskToPool<T>(T prefab, out PoolTask poolTask) where T : Component, IPoolable 38 { 39 var taskContainer = new GameObject 40 { 41           name = $ "{prefab.name}_pool" , 42 transform = 43 { 44 parent = _container 45 } 46 }; 47 poolTask = new PoolTask(taskContainer.transform); 48 _activePoolTasks.Add(prefab, poolTask); 49 } 50 }

সিঙ্গেলটনের ব্যবহার আপনার নজর কাড়তে পারে - এটি শুধুমাত্র একটি উদাহরণ। আপনি আপনার প্রকল্পে ব্যবহার কাস্টমাইজ করতে পারেন — এটি চলমান হতে পারে

 ObjectPool
জেনজেক্টের মাধ্যমে কনস্ট্রাক্টর বা ইনজেকশনের মাধ্যমে।

আমরা আমাদের চূড়ান্ত সংস্করণ আছে

 Cast
মধ্যে পদ্ধতি
 Enemy
:

 public class Enemy : MonoBehaviour 2 { 3 [SerializeField] private FireBall _prefab; 4 [SerializeField] private Transform _castPoint; 5   
6 public void Cast() 7 { 8 FireBall fireBall = ObjectPool.Instance.GetObject(_prefab); 9 fireBall.transform.position = _castPoint.position; 10 fireBall.FlyInDirection(transform.right); 11 } 12 }

জেনেরিক ব্যবহার করার কারণে আমরা অবিলম্বে প্রক্রিয়াকরণের জন্য প্রয়োজনীয় ধরনের একটি বস্তু পাই।

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

যাইহোক, UI উপাদানগুলির সাথে কাজ করার সময় সতর্কতা অবলম্বন করুন: যখন অভিভাবকদের মধ্যে একটি বস্তু সরানোর সময় ভিন্ন সাথে রূপান্তরিত হয়৷

 localScale
, দ্য
 localScale
বস্তুর নিজেই পরিবর্তন হবে. আপনার প্রোজেক্টে একটি অভিযোজিত UI থাকলে, ক্যানভাস উপাদানের সাথে রূপান্তরগুলি তাদের পরিবর্তন করবে
 localScale
এক্সটেনশনের উপর নির্ভর করে। আমি আপনাকে এই সহজ অপারেশন করার পরামর্শ দিচ্ছি:

 poolable.GameObject.transform.localScale = Vector2. on e ;

আপনি অন্যান্য বিকল্পে 3টি স্ক্রিপ্ট ব্যবহার করতে পারেন:

 ObjectPool
,
 PoolTask
, এবং
 IPoolable
. তাই নির্দ্বিধায় সেগুলিকে আপনার প্রকল্পে যুক্ত করুন এবং 100% এর জন্য অবজেক্ট পুল প্যাটার্ন ব্যবহার করুন!