Tech Blog 1 - კონტენტის დინამიური ჩატვირთვა
·დინამიურად კონტენტის ჩატვირთვა ჩემთვის მნიშვნელოვანი საკითხკია. მინდა რომ შემეძლოს სხვადასხვა რუქის ნაწილების, პერსონაჟების, ან სულაც უნარების დამატება ისე რომ მოთამაშეს არ მოუწიოს თამაშის განახლება მოწყობილობაზე. ბუნებრივია ეხლა თუ რამე ახალი ემატება მექანიკის კუთხით ეგ რთული იქნება, მაგრამ არსებულ მექანიკაში თუ ჯდება დამატებითი "კონტენტი" ეგ არ მინდა მოთამაშის მხრიდან რამე ქმედებას საჭიროებდეს.
Unity-ში Addressable-ზე მსმენია და თითქოს ორიოდე ტუტორიალიც მქონდა ნანახი, მაგრამ მაინც არასწორედ გამიგია, და მაქედან გამომდინარე არასწორედ დამიგეგმია არქიტექტურაც. წინა პოსტში როგორც ნახეთ "კონტენტი" ცოცხლობს "Perstistence" შრეზე. ეგ სპეციალურად არის ეგრე, იქიდან გამომდინარე რომ გათხვლა იყო რომ ამ შრეზე სხვადასხვა ადაპტერის გამოყენებით, მინდა ლოკალურ ფაილებს ჩავთვირთავ, მინდა სერვერიდან წამოღებულს. ანუ:
public class LocalStorageStrategySo : StorageStrategy
{
[SerializeField] private AbilityRepositorySo abilityRepositorySo;
public AbilityRepositorySo GetAbilityRepository()
{
return abilityRepositorySo;
}
}
public class AbilityRepositorySo : ScriptableObject, IAbilityRepository
{
public List<AbilitySo> abilities;
public List<AbilitySo> GetAbilities()
{
return abilities;
}
}
public class AbilitySo : ScriptableObject
{
[Multiline(10)] public string description;
public AssetReferenceSprite icon;
public string name;
}
ეს მაგალითად არის ლოკალური ადაპტერი, და ვიფიქრე შემდგომში იარსებებდა Http ადაპტერის როგორც ესეთი:
public class HttpStorageStrategySo : StorageStrategy
{
[SerializeField] private AbilityRepositorySo abilityRepositorySo;
public AbilityRepositorySo GetAbilityRepository()
{
return abilityRepositorySo;
}
}
public class AbilityRepositorySo : ScriptableObject, IAbilityRepository
{
public List GetAbilities()
{
// download all ability related assets and store on user device
// download all AbilitySo.asset files and deserialize them
var abilities;
return abilities;
}
}
ვიფიქრე სერიალიზირებულ Ability-ს შევინახავდი სერვეზე, და შემდგომ ჩამოვტვირთავდი მასაც, მასთან დაკავშირებული ფაილებს ცალკე ჩამოვტვირთავდი, დესერიალიზაციას მოვახდენდი და voilà, აი კონტენტიც მოთამაშის მოწყობილობაში, რომელიც თავდაპირველად იქ არ იყო.
რაღაც "ნიტოა" გრძნობა მაწუხებდა, თან ზედმეტად კომლექსური იყო ეს ყველაფერი და ვფიქრობდი ნუთუ უფრო მარტივად არ შეიძლება მეთქი. პატარა nodejs სერვერი დავსტარტე, და საქმე საქმეზე რომ მიდგა აღმოვაჩინე რომ ScriptableObject დესერიალიზაცია არც ისე მარტივია, იმდენად არაა მარტივი რომ, "ესე რთული არ უნდა იყოს" გრძნობა შემომეპარა.
ტუტორიალებს მივუბრუნდი და ვაიჰ, აღმოჩნდა რომ თურმე Addressable თავისით აკეთებს ყველაფერს, ფაქტობრივად, ნებისმიერი AssetReference რომელსაც მიმართავ კოდით, Addressable-ს "მოდული" ესე თუ შეიძლება დავარქვათ, თვითონ აგვარებს მერე, დაბილდვასაც, ადაპტერის მიდგომასაც რომ გინდა ლოკალური მოწყობილობიდან აიღოს გინდა ქლაუდიდან, სერიალიზაცია, დესერიალიზაცია, მოკლედ ყველაფერი, და 80$-საც კი არ იხდი. დაახლოვებით გამოვიდა ესე:
public class ContentManager: ScriptableObject
{
[SerializeField] private AssetReference abilityRepository;
private async Task GetAbilityRepository()
{
var handle = abilityRepository.LoadAssetAsync();
await handle.Task;
return handle.Result;
}
}
ვინაიდან აღმოჩნდა რომ აბსტრაქცია არ მჭირდება, და თურმე AssetReference ისედაც აბსტრაქციაა, მაშინ კონტენტის Persistence შრეში გაჩერებამ დაკარგა ყველანაირი აზრი და გახდა მხოლოდ "პრობლემა". ამითომ არქიტექტურა ოდნავ შეიცვალა და მეც ამოვისუნთქე, ნაკლები კოდის წერა მიწევს ეხლა:
ერთი პრობლემა მაინც დარჩა, კონტენტის და დანარჩენი შრეების კავშირი ემყარება კონტენტის უნიკალურ ID-ებს. და ეგ თუ შეიცვალა, Persistence შრე რომელიც ფაქტობრივად მოთამაშეს სთავაზობს "შენახვის" ფუნქციონალს შეიძლება გაფუჭდეს. მაგალითად თუ თამაში შეინახეთ გუშინ, და დღეს ID-ბი შეიცვალა, თქვენ წინა შენახული თამაში "გაფუჭდა" და აღარ იმუშავებს. ამის მოგვარების გზები ბუნებრივია არსებობს, მაგრამ ჯერ არ ვიცი საერთოდ რომ თავი ავარიდო ამასაც ეგ შესაძლებელია თუ არა.