टी एल; डॉ
यह जवाब थोड़ा पागल कर देता है। लेकिन ऐसा इसलिए है क्योंकि मैं देख रहा हूं कि आप अपनी क्षमताओं को "कमांड" के रूप में लागू करने के बारे में बात कर रहे हैं, जिसका अर्थ है C ++ / Java / .NET डिजाइन पैटर्न, जो एक कोड-भारी दृष्टिकोण का अर्थ है। यह लगभग मान्य है, लेकिन एक बेहतर तरीका है। शायद आप पहले से ही दूसरे तरीके से कर रहे हैं। यदि हां, तो ठीक है। उम्मीद है कि दूसरों को यह उपयोगी लगे अगर ऐसा हो।
पीछा करने के लिए कटौती करने के लिए नीचे डेटा-प्रेरित दृष्टिकोण देखें। यहां याकूब पेनेक के कस्टमएसेटसेटिलिटी प्राप्त करें और इसके बारे में उनकी पोस्ट पढ़ें ।
एकता के साथ काम करना
जैसा कि दूसरों ने उल्लेख किया है, 100-300 वस्तुओं की सूची का पता लगाना उतना बड़ा सौदा नहीं है जितना आप सोच सकते हैं। तो अगर यह आपके लिए एक सहज दृष्टिकोण है, तो बस ऐसा ही करें। मस्तिष्क की दक्षता का अनुकूलन। शब्दकोश, लेकिन @Norguard के रूप में डिक्शनरी ने अपने जवाब में कहा , उस समस्या को खत्म करने के लिए आसान- ब्रेन-पावर -आवश्यक तरीका है क्योंकि आपको निरंतर-समय सम्मिलन और पुनर्प्राप्ति मिलती है। आपको शायद इसका इस्तेमाल करना चाहिए।
एकता के भीतर इस काम को अच्छी तरह से करने के संदर्भ में, मेरी आंत मुझसे कहती है कि प्रति क्षमता एक मोनोहेवियर नीचे जाने के लिए एक खतरनाक रास्ता है। यदि आपकी क्षमताओं में से कोई भी समय पर निष्पादित होता है, तो आपको उस राज्य को रीसेट करने का एक तरीका प्रदान करना होगा। Coroutines इस समस्या को कम करती है, लेकिन आप अभी भी उस स्क्रिप्ट के हर अपडेट फ्रेम पर एक IEnumerator संदर्भ का प्रबंधन कर रहे हैं, और यह सुनिश्चित करने के लिए कि आपके पास निश्चित रूप से आग है जिससे कि क्षमताओं को अधूरा और अटक-ए-राज्य-लूप को रीसेट किया जा सके। क्षमताओं चुपचाप अपने खेल की स्थिरता को पेंच करना शुरू करते हैं जब वे किसी का ध्यान नहीं जाते हैं। "बेशक मैं ऐसा करूँगा!" आप कहते हैं, "मैं एक 'अच्छा प्रोग्रामर' हूँ!"। लेकिन वास्तव में, आप जानते हैं, हम सभी उद्देश्यपूर्ण भयानक प्रोग्रामर हैं और यहां तक कि सबसे बड़े एआई शोधकर्ताओं और संकलक लेखकों ने हर समय सामान बिखेर दिया है।
सभी तरीकों से आप एकता में कमांड इंस्टेंटेशन और रिट्रीवल को लागू कर सकते हैं, मैं दो के बारे में सोच सकता हूं: एक ठीक है और आपको एक एन्यूरिज्म नहीं देगा, और दूसरा UNIBUNDED MAGICAL CREATIVITY के लिए अनुमति देता है । की तरह।
कोड-सेंट्रिक दृष्टिकोण
पहला एक ज्यादातर इन-कोड दृष्टिकोण है। मेरा सुझाव है कि आप प्रत्येक कमांड को एक साधारण वर्ग बनाते हैं, जो या तो बेसकॉम्बैंड एबट्रैक्ट क्लास से विरासत में मिलता है या एक आईसीओएमएंड इंटरफ़ेस लागू करता है (मैं संक्षिप्तता के लिए मान रहा हूं कि ये कमांड केवल चरित्र क्षमता होंगे, यह शामिल करना मुश्किल नहीं है अन्य उपयोग)। यह सिस्टम मानता है कि प्रत्येक कमांड एक ICommand है, एक सार्वजनिक कंस्ट्रक्टर है जो कोई पैरामीटर नहीं लेता है, और सक्रिय होने पर प्रत्येक फ्रेम को अपडेट करने की आवश्यकता होती है।
यदि आप एक सार आधार वर्ग का उपयोग करते हैं तो चीजें सरल हैं, लेकिन मेरा संस्करण इंटरफेस का उपयोग करता है।
यह महत्वपूर्ण है कि आपका मोनोबीवियर्स एक विशिष्ट व्यवहार या निकट-संबंधित व्यवहारों की एक प्रणाली को अतिक्रमण करता है। यह बहुत अच्छा है MonoBehaviours है कि प्रभावी रूप से सिर्फ सादे सी # कक्षाओं के लिए बाहर छद्म है, लेकिन अगर आप पाते हैं अपने आप को भी कर रहा है अद्यतन करने के लिए विभिन्न वस्तुओं के सभी प्रकार को इंगित करने के लिए जहां यह एक XNA खेल की तरह लग रहा है, तो आप कर सकते हैं गंभीर संकट में हैं और अपनी वास्तुकला को बदलने की जरूरत है।
// ICommand.cs
public interface ICommand
{
public void Execute(AbilityActivator originator, TargetingInfo targets);
public void Update();
public bool IsActive { get; }
}
// CommandList.cs
// Attach this to a game object in your loading screen
public static class CommandList
{
public static ICommand GetInstance(string key)
{
return commandDict[key].GetRef();
}
static CommandListInitializerScript()
{
commandDict = new Dictionary<string, ICommand>() {
{ "SwordSpin", new CommandRef<SwordSpin>() },
{ "BellyRub", new CommandRef<BellyRub>() },
{ "StickyShield", new CommandRef<StickyShield>() },
// Add more commands here
};
}
private class CommandRef<T> where T : ICommand, new()
{
public ICommand GetNew()
{
return new T();
}
}
private static Dictionary<string, ICommand> commandDict;
}
// AbilityActivator.cs
// Attach this to your character objects
public class AbilityActivator : MonoBehaviour
{
List<ICommand> activeAbilities = new List<ICommand>();
void Update()
{
string activatedAbility = GetActivatedAbilityThisFrame();
if (!string.IsNullOrEmpty(acitvatedAbility))
ICommand command = CommandList.Get(activatedAbility).GetRef();
command.Execute(this, this.GetTargets());
activeAbilities.Add(command);
}
foreach (var ability in activeAbilities) {
ability.Update();
}
activeAbilities.RemoveAll(a => !a.IsActive);
}
}
यह पूरी तरह से ठीक काम करता है, लेकिन आप बेहतर कर सकते हैं (यह भी, List<T>
समयबद्ध क्षमताओं को संग्रहीत करने के लिए इष्टतम डेटा संरचना नहीं है, आप एक LinkedList<T>
या चाहते हो सकते हैं SortedDictionary<float, T>
)।
डेटा-प्रेरित दृष्टिकोण
यह संभवतः संभव है कि आप अपनी क्षमता के प्रभावों को तार्किक व्यवहार में कम कर सकते हैं जो कि इसे मानकीकृत किया जा सकता है। यह वही है जो वास्तव में एकता के लिए बनाया गया था। आप, एक प्रोग्रामर के रूप में, एक ऐसी प्रणाली डिजाइन करते हैं, जिसके बाद या तो आप या एक डिजाइनर विभिन्न प्रकार के प्रभावों का उत्पादन करने के लिए संपादक में जा सकते हैं और हेरफेर कर सकते हैं। यह कोड की "हेराफेरी" को बहुत सरल करेगा, और विशेष रूप से एक क्षमता के निष्पादन पर ध्यान केंद्रित करेगा। यहां आधार कक्षाओं या इंटरफेस और जेनरिक को टटोलने की जरूरत नहीं है। यह सभी विशुद्ध रूप से संचालित डेटा होगा (जो कमांड इंस्टेंसेस को इनिशियलाइज़ करने में भी सरल करता है)।
पहली चीज़ जो आपको चाहिए वह है एक ScriptableObject जो आपकी क्षमताओं का वर्णन कर सकता है। ScriptableObjects कमाल के हैं। वे MonoBehaviours की तरह काम करने के लिए डिज़ाइन किए गए हैं, जिसमें आप एकता के इंस्पेक्टर में उनके सार्वजनिक क्षेत्र सेट कर सकते हैं, और उन परिवर्तनों को डिस्क पर क्रमबद्ध रूप से प्राप्त किया जाएगा। हालांकि, वे किसी भी वस्तु से नहीं जुड़े हैं और किसी दृश्य या तात्कालिक रूप से किसी गेम ऑब्जेक्ट से जुड़े नहीं हैं। वे एकता के कैच-ऑल डेटा बकेट हैं। वे मूल प्रकार, एनम और सरल वर्ग (कोई विरासत) चिह्नित कर सकते हैं [Serializable]
। यूनिटी में संरचनाओं को क्रमबद्ध नहीं किया जा सकता है, और क्रमांकन वह है जो आपको निरीक्षक में ऑब्जेक्ट फ़ील्ड को संपादित करने की अनुमति देता है, इसलिए याद रखें।
यहाँ एक ScriptableObject है जो बहुत कुछ करने की कोशिश करता है। आप इसे और अधिक क्रमबद्ध कक्षाओं और ScriptableObjects में तोड़ सकते हैं, लेकिन यह सिर्फ आपको यह अंदाजा देता है कि इसे कैसे करना है। आम तौर पर यह C # जैसी एक अच्छी आधुनिक वस्तु उन्मुख भाषा में बदसूरत दिखता है, क्योंकि यह वास्तव में उन सभी Enums के साथ कुछ C89 बकवास की तरह लगता है, लेकिन यहाँ असली शक्ति यह है कि अब आप विभिन्न क्षमताओं के सभी प्रकार के बिना नए कोड लिखने के लिए समर्थन कर सकते हैं उन्हें। और अगर आपका पहला प्रारूप वह नहीं करता है जो आपको करने की आवश्यकता है, तो बस इसे तब तक जोड़ते रहें जब तक कि यह न हो जाए। जब तक आप फ़ील्ड नाम नहीं बदलते हैं, तब तक आपकी सभी पुरानी अनुक्रमित संपत्ति फाइलें अभी भी काम करेंगी।
// CommandAbilityDescription.cs
public class CommandAbilityDecription : ScriptableObject
{
// Identification and information
public string displayName; // Name used for display purposes for the GUI
// We don't need an identifier field, because this will actually be stored
// as a file on disk and thus implicitly have its own identifier string.
// Description of damage to targets
// I put this enum inside the class for answer readability, but it really belongs outside, inside a namespace rather than nested inside a class
public enum DamageType
{
None,
SingleTarget,
SingleTargetOverTime,
Area,
AreaOverTime,
}
public DamageType damageType;
public float damage; // Can represent either insta-hit damage, or damage rate over time (depend)
public float duration; // Used for over-time type damages, or as a delay for insta-hit damage
// Visual FX
public enum EffectPlacement
{
CenteredOnTargets,
CenteredOnFirstTarget,
CenteredOnCharacter,
}
[Serializable]
public class AbilityVisualEffect
{
public EffectPlacement placement;
public VisualEffectBehavior visualEffect;
}
public AbilityVisualEffect[] visualEffects;
}
// VisualEffectBehavior.cs
public abtract class VisualEffectBehavior : MonoBehaviour
{
// When an artist makes a visual effect, they generally make a GameObject Prefab.
// You can extend this base class to support different kinds of visual effects
// such as particle systems, post-processing screen effects, etc.
public virtual void PlayEffect();
}
आप नुकसान की धारा को एक धारावाहिक श्रेणी में आगे बढ़ा सकते हैं ताकि आप उन क्षमताओं को परिभाषित कर सकें जो नुकसान, या चंगा करती हैं, और एक क्षमता में कई नुकसान प्रकार हैं। जब तक आप एक से अधिक स्क्रिप्ट योग्य ऑब्जेक्ट्स का उपयोग नहीं करते हैं और डिस्क पर विभिन्न जटिल क्षति कॉन्फ़िगरेशन फ़ाइलों को संदर्भित करते हैं, तब तक एकमात्र नियम कोई विरासत नहीं है।
आपको अभी भी एबिलिटीएक्टीवेटर मोनोबोहेवियर की ज़रूरत है, लेकिन अब वह थोड़ा और काम करता है।
// AbilityActivator.cs
public class AbilityActivator : MonoBehaviour
{
public void ActivateAbility(string abilityName)
{
var command = (CommandAbilityDescription) Resources.Load(string.Format("Abilities/{0}", abilityName));
ProcessCommand(command);
}
private void ProcessCommand(CommandAbilityDescription command)
{
foreach (var fx in command.visualEffects) {
fx.PlayEffect();
}
switch(command.damageType) {
// yatta yatta yatta
}
// and so forth, whatever your needs require
// You could even make a copy of the CommandAbilityDescription
var myCopy = Object.Instantiate(command);
// So you can keep track of state changes (ie: damage duration)
}
}
COOLEST भाग
तो पहले दृष्टिकोण में इंटरफ़ेस और सामान्य चालबाजी ठीक काम करेगी। लेकिन वास्तव में एकता से सबसे अधिक पाने के लिए, ScriptableObjects आपको वहीं मिलेगा जहां आप होना चाहते हैं। एकता इस मायने में शानदार है कि यह प्रोग्रामर्स के लिए बहुत सुसंगत और तार्किक वातावरण प्रदान करती है, लेकिन गेममेकर, यूडीके, ईटी से आपको प्राप्त होने वाले डिजाइनरों और कलाकारों के लिए सभी डेटा एंट्री निकेट्स भी हैं। अल।
पिछले महीने, हमारे कलाकार ने एक पावरअप ScriptableObject प्रकार लिया, जो कि विभिन्न प्रकार की होमिंग मिसाइलों के लिए व्यवहार को परिभाषित करने वाला था, इसे एक एनिमेशनक्रूव और एक ऐसे व्यवहार के साथ जोड़ा गया, जिससे मिसाइलें जमीन पर मंडराने लगीं, और इस पागल स्पिनिंग-हॉकी-पुक- मौत का हथियार
मुझे अभी भी वापस जाने की ज़रूरत है और इस व्यवहार के लिए विशिष्ट समर्थन जोड़ने के लिए सुनिश्चित करें कि यह कुशलतापूर्वक चल रहा है। लेकिन क्योंकि हमने इस सामान्य डेटा विवरण इंटरफ़ेस को बनाया था, वह इस विचार को पतली हवा से बाहर निकालने में सक्षम था और इसे हमारे बिना प्रोग्रामर के गेम में डाल दिया, यहां तक कि यह जानते हुए भी कि वह ऐसा करने की कोशिश कर रहा था जब तक वह ऊपर नहीं आया और कहा, "अरे दोस्तों, देखो इस शांत बात पर! " और क्योंकि यह स्पष्ट रूप से भयानक था, मैं इसके लिए और अधिक मजबूत समर्थन जोड़ने के लिए उत्साहित हूं।