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


31

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

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

  1. Створіть клас для кожного ресурсу:

    public class ResourceBase {
        private int value;
        // other base properties
    }
    
    public class Gold : ResourceBase {
         public Gold {
             this.value = 40 // or whatever
         }
    }
    
  2. Створіть екземпляри класу Resource

    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);
    

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

Нові ідеї / дизайнерські структури / структури завжди вітаються!

EDIT: Це трохи схоже на додаток-компаньйон Assassins Creed Black Flag. Дивіться рядок ресурсів на зображенні нижче

EDIT 2: Я провів ще кілька досліджень щодо "завантаження елементів / ресурсів з файлу JSON" і знайшов цей блог: Power JSON у розробці ігор - елементи . Він показує найкращий варіант 1 та варіант 2. Ви все ще можете додати функціональність до кожного ресурсу :)

введіть тут опис зображення


1
У Minecraft є окремі класи для кожного ресурсу (не те, що вам слід)
MCMastery

@MCMastery о, це Minecraft з відкритим кодом? Я хотів би заглянути в цю структуру. І thx для згадки
MDijkstra

1
Це не так, але його завжди знеструмлено
MCMastery

12
Не використовуйте такий рядок. Все надто просто помилково вводити "золото" з "glod" або подібним, і налагоджувати величезний біль. Використовуйте enumзамість цього.
Нолонар

Minecraft не є технічно відкритим кодом, але він майже повністю був декомпільований і знешкоджений. Ви не зможете знайти знецінене джерело в будь-якій точці Інтернету, але ви можете завантажити та запустити процес, щоб зробити це з files.minecraftforge.net (завантаження MDK - саме те, що ви хочете)
JamEngulfer

Відповіді:


51

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


Редагувати:

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

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

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

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

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

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

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


6
+1 для DDD. Це дуже підходить для таких речей, як ресурси.
Кромстер каже, що підтримує Моніку

@Funnydutchman, якщо вам допомогла чиясь відповідь, на Stack Exchange прийнято відповідати, натискаючи стрілку вище номера ліворуч. Якщо відповідь вам найбільше допомогла, слід натиснути галочку під стрілкою внизу, щоб прийняти їх відповідь. Обидві дії дають відповідачу бонус за репутацію та роблять корисні відповіді більш видимими для громади.
Nzall

2
Я не бачу, як вам довелося б переписати код першим способом; все, що ви зробили б - це додати клас (якщо я щось не пропускаю).
SirPython

4
І ось різниця між об'єктно-орієнтованим кодом та кодом Obsed Obsed. Тільки тому, що ви можете створити ієрархію об’єктів, не обов'язково означає, що ви повинні.
corsiKa

2
@ AgustínLado Якби я мав долар за кожен раз, коли клієнт сказав "Це ніколи не зміниться", і це змінилося, я б міг відвезти нас обох у пристойний ресторан на вечерю (хоча нам доведеться трохи скупитися на підказку, тож можливо лише посередній ресторан ... ще достатньо разів на вечерю на двох.)
corsiKa

29

Основне правило полягає в тому, що ви використовуєте різні класи, коли для об'єктів потрібен різний код, і екземпляри одного класу, коли для об'єктів потрібні лише різні значення.

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

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


Дякуємо @Phillipp за вашу відповідь. Це я думав. Але ресурси насправді не зміняться щодо властивостей / методів, тому я зараз перейду з варіантом 2
MDijkstra

14

Я хотів би додати, що є два додаткові варіанти:
Інтерфейс: ви можете врахувати це, якщо клас ресурсів був би просто "сховищем" для 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<Resource> Resources { get; }
}

Примірники (з enum): у деяких випадках було б бажано використовувати enum замість рядка при визначенні типу ресурсу:

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"


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


2
Дякую за вашу відповідь @wondra Мені подобається варіант перерахування, і як ви зробили цю бронзу з міді та олова; p
MDijkstra

2
Я приєднався до цієї спільноти спеціально, щоб я міг проголосувати рішення про перерахування. Ви також можете вивчити використання атрибута опису enum для зіставлення деякого JSON-представлення enum ( my-great-enum) з деяким представленням C # enum ( MyGreatEnum).
Ден Форбс

Мабуть, я занадто довго виходив з петлі Java. З тих пір, коли дозволено мати декларації на місцях для інтерфейсів? Наскільки мені відомо, вони автоматично є статичними і остаточними, і тому вони не дуже корисні для цілей, описаних у питанні.
М.Герцкамп

2
@ M.Herzkamp це не поле, це властивість - і Java не підтримує властивості. Питання позначено тегами C #, C # дозволяють властивості в інтерфейсах - властивості є методами, що знаходяться під кришкою. Я боюся, що це стосується анотацій прапорів, які не підтримуються в Java, хоча я не зовсім впевнений.
wondra

Дякуємо, що очистили це! Я пропустив тег C #, і код у запитанні виглядав так прикро, як Java: D
M.Herzkamp

2

Слід скористатися варіантом 1, який має 3 переваги:

  1. Простіше інстанціювати ресурс - замість того, щоб передати тип ресурсу як параметр, ви просто зробили б, наприклад, new Gold(50)
  2. Якщо вам потрібно надати особливу поведінку ресурсу, ви можете, змінивши його клас.
  3. Простіше перевірити, чи ресурс певного типу - resource instanceof Gold

Усі відповіді мають свої плюси і мінуси, важко вибрати, який краще. Я змінив питання, що ви думаєте про цю структуру?
MDijkstra

1

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.