Використовувати екземпляр або клас для ігрових ресурсів (дерево, залізо, золото)

Тому я роблю гру, де можна відправляти кораблі на місця, щоб продавати або купувати ресурси, як дерево, залізо, золото тощо.

Тепер мені було цікаво, як слід створювати ресурси в de game. Я придумав 2 варіанти

  1. Create a class for each resource:

    public class ResourceBase {
        private int value;
       //other base properties
    }
    
    public class Gold : ResourceBase {
         public Gold {
             this.value = 40//or whatever
         }
    }
    
  2. Create instances of a Resource class

    public class Resource {
        string name;
        int value;
    
        public Resource(string name, int value) {
            this.name = name;
            this.value = value;
         }
     }
    
    // later on...
    
    Resource gold = new Resource("Gold",40);
    

З другого варіанту можна заповнити ігрові ресурси з файлу resources.json, мені подобається така структура.

Нові ідеї/шаблони дизайну/структури завжди раді!

EDIT: It's a little bit like Assassins Creed Black Flag's companion app. See the resource bar on the image below

EDIT 2: I've done some more research on the "load items/resources from JSON file" and found this blog: Power of JSON in Game Development - Items. It shows the best of option 1 and option 2. You're still able to add functionality to each resource :)

enter image description here

31
@MCMastery ohh є Minecraft з відкритим вихідним кодом? Я хотів би заглянути в цю структуру. І THX для згадки
додано Автор Jacksonkr, джерело
@Nolonar Mmm ... коли ви хочете побудувати/модернізувати корабель, він повинен знати, які ресурси йому потрібні для виконання цієї дії. Тому корабель повинен знати, які ресурси є в грі. Отже, варіант 1 був би кращим. Ти правий! Я дійсно повинен подумати про це.
додано Автор Jacksonkr, джерело
@Nolonar У вас є питання, але як би ви пішли про завантаження ресурсів з JSON. Тоді ви матимете постійну кількість ресурсів, яка не є такою гнучкою, як струни, чи не так?
додано Автор Jacksonkr, джерело
@MCMastery спасибі!
додано Автор Jacksonkr, джерело
@Funnydutchman Якщо ресурси мають фактичне використання, як дерево для створення кораблів або каменю для будівництва замків, то вам доведеться вносити зміни у свій код. Однак, якщо ресурси цілком загальні та розподілені навмання, то використання рядків може бути краще, так.
додано Автор cst1992, джерело
Не використовуйте такий рядок. Це дуже легко помилитися "золотом" з "glod" або подібним, і це величезний біль для налагодження. Замість цього використовуйте enum .
додано Автор cst1992, джерело
Minecraft не є технічно відкритим вихідним кодом, але майже повністю декомпілювався і деобфузувався. Ви не повинні бути в змозі знайти деобузацію джерела в Інтернеті, але ви можете завантажити та запустити процес, щоб зробити це з files.minecraftforge.net (завантаження MDK потрібне вам)
додано Автор JamEngulfer, джерело
Це не так, але для серверів він завжди дезафокусований ... див. github.com/Wolf-in-a-bukkit/Craftbukkit/tree/master/src/main‌/& hellip;
додано Автор Mike, джерело
Minecraft має окремі класи для кожного ресурсу (не те, що ви повинні)
додано Автор Mike, джерело

5 Відповіді

Переходьте до другого підходу, просто тому, що ви можете ввести нові типи ресурсів або елементи в будь-який час без переписування або оновлення коду ( розробка даних, керованих даними ).


Редагувати:

Щоб детальніше деталізувати, чому це взагалі добре, навіть якщо ви на 100% впевнені, що певна цінність ніколи не зміниться.

Візьмемо приклад консольної гри, згаданий у коментарях, оскільки це дає дуже вагому причину, чому ви не повинні жорстко кодувати що-небудь, якщо ви дійсно не маєте (або хочете), наприклад, ключі шифрування, ваше ім'я тощо

Випускаючи гру на консолях, вони, як правило, повинні пройти процес рецензування, де власний QA виробника консолі буде перевіряти гру, грати через неї, шукати проблеми тощо. Це обов'язково і коштує грошей, багато грошей. Я думаю, що колись прочитав, що випуск може коштувати 30 000-50 000 $ тільки для сертифікації.

А тепер уявіть, що ви висуваєте свою гру на реліз, заплативши 30 000 $ і почекайте. І раптом ви помітили, що деякі з ваших ігрових значень буквально ламаються. Припустимо, ви можете купити залізні прути на 50 золотих і продати їх за 55 золотих.

Що ти робиш? Якщо ви надмірно зашифрували цю інформацію, вам доведеться створити нову версію оновлення/випуску, яка знову повинна пройти рецензування, так що найгірший випаде виплатити за повторну сертифікацію! Упевнений, що Ubisoft не заперечує, але для вашої маленької кишеньки для розробників інді-ігор… ой!

Але уявіть, що гра просто час від часу перевірятиме оновлені визначення гри (наприклад, у вигляді файлу JSON). У вашій грі можна завантажити та використовувати останню версію в будь-який час без нового оновлення. Ви можете виправити цей дисбаланс/експлуатувати/помилку в будь-який час, не вимагаючи повторної сертифікації або будь-яких інших виплат. Тільки деяке незначне рішення дизайну, ви не подумали вартий це, тільки врятувало вас 5 цифра сума грошей! Хіба це не дивно? :)

Просто не зрозумійте мене неправильно. Це також стосується інших типів програмного забезпечення та платформ. Завантаження оновлених файлів даних в цілому набагато легше і зручніше для стандартного користувача, незалежно від того, чи це гра чи якийсь додаток/інструмент. Уявіть собі гру, встановлену у програмі Windows Files. Щоб змінити щось, адміністратору оновлення потрібні права адміністратора, і ви не можете змінювати запущені програми. За допомогою DDD програма просто завантажує дані і використовує їх. Програвач може навіть не помітити, що оновлення.

52
додано
@ AgustínLado Якщо б я мав долар за кожен раз, коли клієнт сказав: "Це ніколи не зміниться", і він змінився, я міг би взяти нас обох до пристойного ресторану на вечерю (хоча нам доведеться трохи заощадити на чайові, так що, можливо, тільки посередній ресторан ... все ще достатньо разів на вечерю для двох.)
додано Автор Douglas Anderson, джерело
І тут різниця між об'єктно-орієнтованим кодом і кодом Obsessed Object. Просто тому, що ви можете створити ієрархію об'єктів, це не обов'язково означає.
додано Автор Douglas Anderson, джерело
@Piritie Не впевнений, де вони малюють лінію. У будь-якому випадку ви на безпечніше говорить з більш гнучким підходом.
додано Автор Thomas Taylor, джерело
@AgustinLado Ні, ви все одно можете зробити багато змін/оновлень до випуску, і навіть може бути щось після релізу. Я розширив свою відповідь, щоб включити приклад, спеціально орієнтований на вигадану консольну гру, яка вимагає оновлення за допомогою обох підходів.
додано Автор Thomas Taylor, джерело
+1 для DDD. Це дуже підходить для таких речей, як ресурси.
додано Автор Kromster, джерело
@ Маріо Так, я не погоджуюся, що DDD - це шлях тут.
додано Автор zimbu668, джерело
Малі патчі для балансу зазвичай не повинні проходити через консольну сертифікацію.
додано Автор zimbu668, джерело
Я не бачу, як потрібно переписувати код першим способом; все, що потрібно зробити, це додати клас (якщо я щось не пропускаю).
додано Автор georged, джерело
@Nzall Так, засмучений напружений день і хотів почекати на якусь нову відповідь. Я зроблю це зараз.
додано Автор Jacksonkr, джерело
@SirPython "без необхідності переписати або оновити код", в цьому випадку оновлення коду шляхом додавання нового класу. З другого способу потрібно лише редагувати resources.json .
додано Автор musicman523, джерело
@Mario Я погоджуюся з використанням другого підходу у подібних випадках, але чи буде ваша думка різною, якщо ви вважаєте, що ніколи не буде новий ресурс? (Assassin's Creed 4 вийшов 3 роки тому, і з тих пір було два продовження)
додано Автор musicman523, джерело
@corsiKa О, так! Я безумовно згоден! Але серйозно, в даному конкретному випадку це не буде змінитися саме через те, що я сказав.
додано Автор musicman523, джерело
@Funnydutchman, якщо комусь відповідь допомогла вам, звичайно на Stack Exchange підвищити свою відповідь, натиснувши стрілку над номером ліворуч. Якщо відповідь допомогла вам найбільше, потрібно натиснути галочку нижче нижньої стрілки, щоб прийняти їхню відповідь. Обидві дії дають відповідь бонус у репутації і роблять корисні відповіді більш видимими для спільноти.
додано Автор Yei, джерело

Емпіричне правило полягає в тому, що ви використовуєте різні класи, коли об'єкти вимагають різних кодів і екземплярів того ж класу, коли об'єкти вимагають лише різних значень.

Коли ресурси мають різні механіки гри, які є унікальними для них, може мати сенс представляти їх з класами. Наприклад, коли у вас є плутоній, який має час напіврозпаду і кролики, які ростуть відповідно до послідовності "Регіон" , може мати сенс мати базовий клас Resource з методом Update , реалізованим як no-op і двома похідними класами HalfLifeResource і SelfGrowingResource , який перевищує цей метод для зменшення/збільшення значення (і може також включати логіку для керування тим, що відбувається, коли ви зберігаєте один з одним).

Але коли ваші ресурси дійсно просто немірні номери, то немає сенсу реалізовувати їх з чимось більш фантастичним, ніж проста змінна.

29
додано
Спасибі @Phillipp за відповідь. Це те, про що я думав. Але ресурси насправді не зміниться з точки зору властивостей/методів, тому я піду з варіантом 2 на даний момент
додано Автор Jacksonkr, джерело

Я хотів би додати ще дві додаткові опції:

Інтерфейс : ви можете вважати, що клас ресурсів буде просто "сховищем" для 5 цілих чисел, і кожний інший об'єкт буде мати різну логіку щодо ресурсів (наприклад, витрачання/грабеж гравця, місто виробляє ресурс). У цьому випадку ви можете не захотіти класу взагалі - ви просто хочете виставити, що деяка сутність має змінну, з якою інші можуть взаємодіяти:

interface IHasResources {
  int Gold { get; set; }
  int Wood { get; set; }
  int Cloth { get; set; }
 //....
}

class Player : IHasResources { }
class City: IHasResources { }

крім того, це може призвести до того, що ви можете грабувати місто з точно таким самим кодом, що і розграбувати ворожий флот, сприяючи повторному використанню коду.
Недоліком є ​​те, що реалізація такого інтерфейсу може виявитися стомлюючою, якщо багато класів реалізують його, тому ви можете в кінцевому підсумку використовувати інтерфейси, але не для початкової проблеми, вирішуючи її з варіантом 1 або 2:

interface IHasResources { 
   IEnumerable Resources { get; }
}

Instances (with enum): in some cases, it would be desirable to use enum instead of string when defining resource type:

enum Resource {
   Gold, Wood, Cloth, //...
}

class ResourceStorage {
   public Resource ResourceType { get; set; }
   public int Value { get; set; }
}

це дасть трохи "безпеки", тому що ваша IDE надасть вам список всіх дійсних ресурсів при призначенні після написання крапки ResourceType = Resource. , крім того, існує більше "трюків" з переліками вам можливо потрібно, наприклад, явні прапори типу або композиції/ які я можу уявити корисними під час створення:

[Flags]
enum Metal {
 Copper = 0x01/*01*/, Tin = 0x02/*10*/, Bronze = 0x03/*11*/
}
Metal alloy = Metal.Copper; //lets forget Value(s) for sake of simplicity
alloy |= Metal.Tin; //now add a bit of tin
Console.WriteLine(alloy); //will print "Bronze"


As for what is best - there is no silver bullet, but personally I would lean towards any form of instances, they might not be as fancy as interface but they are simple, doesn't clutter inheritance tree and are widely understood.

14
додано
@ M.Herzkamp це не поле, це властивість - і Java не підтримує властивості. Питання позначається тегами C#, C# дозволяють властивості в інтерфейсах - властивості є методами, які все-таки підводяться. Боюся, що це стосується анотацій прапорів, які не підтримуються Java, хоча я не впевнений.
додано Автор tetranz, джерело
Дякуємо за відповідь @ wondra Мені подобається enum варіант і як ви зробили цю бронзу з міді і олова; p
додано Автор Jacksonkr, джерело
Очевидно, я був занадто довгий з Java-циклу. Відколи це дозволило мати поля декларації для інтерфейсів? Наскільки я знаю, вони автоматично статичні і остаточні, і тому не дуже корисні для цілей, описаних у питанні.
додано Автор Rotsiser Mho, джерело
Дякуємо за очищення! Я пропустив тег C#, а код у запиті виглядав настільки ймовірно схожим на Java: D
додано Автор Rotsiser Mho, джерело
Я приєднався до цієї спільноти спеціально, щоб я міг проголосувати за перелік. Ви також можете переглянути атрибут enum Опис перенести з деякого JSON представлення перерахування ( my-great-enum ) до деякого C# представлення переліку ( MyGreatEnum ).
додано Автор notzach, джерело

Необхідно використовувати варіант 1, який має 3 переваги:

  1. It's easier to instantiate a resource - instead of having to pass the type of the resource as a parameter, you would just do, for example, new Gold(50)
  2. If you need to give special behaviour to a resource, you can by changing it's class.
  3. It's easier to check if a resource is a certain type - resource instanceof Gold
2
додано
Всі відповіді мають свої плюси і мінуси, важко вибрати, що краще. Я змінив питання, що ви думаєте про цю структуру?
додано Автор Jacksonkr, джерело

Якщо у ваших ресурсів відсутня власна бізнес-логіка або особливі сценарії з тим, як вони взаємодіють з навколишнім середовищем, інші ресурси (крім торгівлі, яку ви охопили) або гравець, то варіант 2 робить додавання нових дуже легко.

Якщо вам потрібно розглянути ситуації, подібні до того, що станеться, якщо ви поєднаєте два ресурси для створення, якщо ресурси можуть мати дуже різні властивості (відро води дуже відрізняється від кускового вугілля) або інші складні економічні взаємодії, то підхід 1 набагато гнучкіші для двигуна, але не дані.

1
додано
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug

ІТ КПІ - JavaScript
ІТ КПІ - JavaScript
504 учасників

співтовариство javascript розробників в Telegram