मैं उपलब्धियों से निपटने के लिए एक लचीला ढांचा कैसे स्थापित कर सकता हूं?


54

विशेष रूप से, यह एक ऐसी उपलब्धि प्रणाली इतनी छूट सरल आंकड़ों पर ही आधारित जैसे उपलब्धियों से परे जा रहा संभालने के लिए लागू करने के लिए सबसे अच्छा तरीका क्या है "को मारने एक्स दुश्मन।"

मैं एक सांख्यिकी आधारित प्रणाली की तुलना में अधिक मजबूत और कुछ और अधिक संगठित और बनाए रखने के लिए देख रहा हूं "स्थितियों के रूप में उन सभी को हार्डकोड"। कुछ उदाहरण जो एक सांख्यिकी आधारित प्रणाली में असंभव या अस्पष्ट हैं: "एक स्ट्रॉबेरी के बाद एक तरबूज का टुकड़ा", "अजेय रहते हुए एक पाइप नीचे जाओ", आदि।

जवाबों:


39

मुझे लगता है कि वस्तु उन्मुख तरीके से जाने के लिए एक तरह का मजबूत समाधान होगा।

आप किस प्रकार की उपलब्धि का समर्थन करना चाहते हैं, इसके आधार पर, आपको अपने खेल की वर्तमान स्थिति और / या क्रियाओं के इतिहास / खेल की वस्तुओं (खिलाड़ी की तरह) की घटनाओं के लिए एक तरीका चाहिए।

मान लीजिए कि आपके पास एक आधार उपलब्धि वर्ग है जैसे:

class AbstractAchievement
{
    GameState& gameState;
    virtual bool IsEarned() = 0;
    virtual string GetName() = 0;
};

AbstractAchievementखेल की स्थिति का संदर्भ देता है। इसका उपयोग उन चीजों को क्वेरी करने के लिए किया जाता है जो हो रही हैं।

फिर आप ठोस कार्यान्वयन करते हैं। आइए अपने उदाहरणों का उपयोग करें:

class MasterSlicerAchievement : public AbstractAchievement
{
    string GetName() { return "Master Slicer"; }
    bool IsEarned()
    {
        Action lastAction = gameState.GetPlayerActionHistory().GetAction(0);
        Action previousAction = gameState.GetPlayerActionHistory().GetAction(1);
        if (lastAction.GetType() == ActionType::Slice &&
            previousAction.GetType() == ActionType::Slice &&
            lastAction.GetObjectType() == ObjectType::Watermelon &&
            previousAction.GetObjectType() == ObjectType::Strawberry)
            return true;
        return false;
    }
};
class InvinciblePipeRiderAchievement : public AbstractAchievement
{
    string GetName() { return "Invincible Pipe Rider"; }
    bool IsEarned()
    {
        if (gameState.GetLocationType(gameState.GetPlayerPosition()) == LocationType::OVER_PIPE &&
            gameState.GetPlayerState() == EntityState::INVINCIBLE)
            return true;
        return false;
    }
};

फिर यह तय करना है कि IsEarned()विधि का उपयोग करके आपको कब जांचना है । आप प्रत्येक गेम अपडेट पर जांच कर सकते हैं।

उदाहरण के लिए, किसी प्रकार का इवेंट मैनेजर होने के लिए एक अधिक कुशल तरीका होगा। और फिर (जैसे घटनाओं रजिस्टर PlayerHasSlicedSomethingEventया PlayerGotInvicibleEventया बस PlayerStateChangedएक विधि है कि पैरामीटर में उपलब्धि ले जाएगा के लिए)। उदाहरण:

class Game
{
    void Initialize()
    {
        eventManager.RegisterAchievementCheckByActionType(ActionType::Slice, masterSlicerAchievement);
        // Each time an action of type Slice happens,
        // the CheckAchievement() method is invoked with masterSlicerAchievement as parameter.
        eventManager.RegisterAchievementCheckByPlayerState(EntityState::INVINCIBLE, invinciblePiperAchievement);
        // Each time the player gets the INVINCIBLE state,
        // the CheckAchievement() method is invoked with invinciblePipeRiderAchievement as parameter.
    }
    void CheckAchievement(const AbstractAchievement& achievement)
    {
        if (!HasAchievement(player, achievement) && achievement.IsEarned())
        {
            AddAchievement(player, achievement);
        }
    }
};

13
शैली nitpick: if(...) return true; else return false;रूप में ही हैreturn (...)
डैनी Pflughoeft - BlueRaja

2
यह एक उपलब्धि प्रणाली को लागू करने के लिए एक बहुत अच्छा टेम्पलेट है। इसके अलावा, यह अभी भी इस विचार को प्रदर्शित करता है कि आपके पास गेम-स्टेट्स को ट्रैक करने का एक तरीका है। मुझे लगता है कि शायद सबसे जटिल विचार है।
ब्रायन हैरिंगटन

@Spio आप एक मास्टर पुरुष हैं ...! : डी सरल और सुरुचिपूर्ण समाधान। Congrat।
डिएगो पालोमर

+1 मुझे लगता है कि इस समस्या से निपटने के लिए ईवेंट एमिट / कलेक्ट सिस्टम एक शानदार तरीका है।
ashes999

14

ठीक है, संक्षेप में, एक निश्चित शर्त पूरी होने पर उपलब्धियों को अनलॉक किया जाता है। इसलिए यदि आप चाहते हैं कि स्थिति की जांच करने के लिए बयान देने के लिए आपको उत्पादन करने में सक्षम होना चाहिए।

उदाहरण के लिए, यदि आप यह जानना चाहते हैं कि एक स्तर पूरा हो गया था या एक बॉस को हरा दिया गया था, तो इन घटनाओं के होने पर आपको बूलियन फ्लैग सच होने की आवश्यकता होगी।

फिर:

if(GlobalFlags.MasterBossDefeated == true && AchievementClass.MasterBossDefeatedAchievement == false)
{
    AchievementClass.MasterBossDefeatedAchievement = true;
    showModalPopUp("You defeated the Master Boss!  30 gamerscore");
}

आप इसे उस स्थिति से मेल खाने के लिए आवश्यकतानुसार जटिल या सरल बना सकते हैं, जिसे आप चाहते हैं।

Xbox 360 उपलब्धियों पर कुछ जानकारी यहाँ मिल सकती है


2
+1 महान लेख, और अनिवार्य रूप से मैं जो सुझाव देने जा रहा था। हालांकि मैं मोडल को अपना पाठ उपलब्धि से ही बनाऊंगा ... यदि आप कुछ बदलना चाहते हैं तो बस पाठ शिकार से बचें।
जेसी डोरसी

@ नोक्ट्रीन - यह मत भूलना कि यहां पोस्ट किए गए किसी भी कोड को छद्म कोड के रूप में माना जाना चाहिए - बिंदु को पाने के लिए सरलीकृत कोड का उपयोग करना अक्सर आवश्यक होता है।
क्रिस एफएल

1
Xbox 360 उपलब्धियों लिंक मृत है।
हेंगी


8

क्या होगा यदि आप खिलाड़ी द्वारा किए गए हर कार्य के लिए संदेश भेजते हैं AchievementManager? फिर प्रबंधक आंतरिक रूप से जांच कर सकता है कि क्या कुछ शर्तों को पूरा किया गया है। पहले ऑब्जेक्ट संदेश पोस्ट करते हैं:

AchievementManager::PostMessage("Jump", "162");

AchievementManager::PostMessage("Slice", "Strawberry");
AchievementManager::PostMessage("Slice", "Watermelon");

AchievementManager::PostMessage("Kill", "Goomba");

और फिर AchievementManagerअगर कुछ भी करने की जरूरत है तो चेक:

if (!strcmp(m_Message.name, "Slice") && !strcmp(m_LastMessage.name, "Slice"))
{
    if (!strcmp(m_Message.value, "Watermelon") && !strcmp(m_LastMessage.value, "Strawberry"))
    {
        // achievement unlocked!
    }
}

आप शायद तार के बजाय गणना के साथ ऐसा करना चाहते हैं। ;)


यह मैं क्या सोच रहा था की पंक्तियों के साथ है, लेकिन यह अभी भी एक फ़ंक्शन में हार्डकोड किए जा रहे सामान के एक समूह पर निर्भर करता है। एक तरफ रख-रखाव, कम से कम हर उपलब्धि को फंक्शन के माध्यम से हर बार पात्रता के लिए जाँचना होता है।
लाटी

2
क्या यह? आप एक बाहरी स्क्रिप्ट में सशर्त डाल सकते हैं, जब तक आपके पास खेल में क्या हुआ है, इसे ट्रैक करने का कुछ तरीका है।
1966 में नाइट 226

6
-1 यह खराब डिजाइन का गला। यदि आप सीधे AchivementManager को कॉल करने जा रहे हैं, तो बस उन "संदेशों" में से प्रत्येक को एक अलग फ़ंक्शन बनाएं। यदि आप संदेशों का उपयोग करने जा रहे हैं, तो एक संदेश-प्रबंधक बनाएं ताकि अन्य वर्ग भी संदेशों का उपयोग कर सकें (मुझे यकीन है कि गोम्बा को यह जान लेने में रुचि होगी कि वह मारा गया है), और AchievementManagerहर में उस युग्मन को हटा दें वर्ग (जो ओपी पूछ रहा था कि पहली जगह में कैसे बचें)। और अपने संदेशों के लिए एक एनुम या अलग वर्गों का उपयोग करें, स्ट्रिंग-शाब्दिकों का नहीं - राज्य के चारों ओर से गुजरने के लिए स्ट्रिंग शाब्दिक का उपयोग करना हमेशा एक बुरा विचार है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

4

मेरे द्वारा उपयोग किया गया अंतिम डिज़ाइन प्रति-उपयोगकर्ता लगातार काउंटर का एक सेट होने के आसपास आधारित था और फिर एक निश्चित मूल्य को मारते हुए एक निश्चित काउंटर से उपलब्धियों की कुंजी है। अधिकांश एक एकल उपलब्धि / काउंटर जोड़ी थी जहां काउंटर केवल 0 या 1 होगा (और उपलब्धि ट्रिगर => 1 पर), लेकिन आप इसका उपयोग "मारे गए एक्स दोस्तों" या "एक्स एक्स चेस्ट" के लिए भी कर सकते हैं। इसका मतलब यह भी है कि आप काउंटरों को किसी ऐसी चीज के लिए सेटअप कर सकते हैं जिसकी कोई उपलब्धियां नहीं हैं, और इसे अभी भी भविष्य में उपयोग के लिए ट्रैक किया जाएगा।


3

जब मैंने अपने आखिरी गेम में उपलब्धियां लागू कीं, तो मैंने इसे सभी सांख्यिकी आधारित बना दिया। जब हमारे आँकड़े एक निश्चित मूल्य तक पहुँचते हैं तो उपलब्धियाँ अनलॉक हो जाती हैं। आधुनिक युद्ध 2 पर विचार करें: खेल आँकड़ों के टन को ट्रैक कर रहा है! SCAR-H के साथ आपने कितने शॉट लिए हैं? लाइटवेट पर्क का उपयोग करते हुए आपने कितने मील का छिड़काव किया है?

इसलिए मेरे कार्यान्वयन में, मैंने बस एक आँकड़ों का इंजन बनाया, फिर एक उपलब्धि प्रबंधक बनाया जो कि पूरे गेमप्ले में उपलब्धियों की स्थिति की जाँच करने के लिए वास्तव में सरल प्रश्न चलाता है।

जबकि मेरा कार्यान्वयन बहुत सरल है, यह काम पूरा करता है। मैंने इसके बारे में लिखा और अपने प्रश्नों को यहाँ साझा किया ।


2

इवेंट कैलकुलस का प्रयोग करें । फिर कुछ पूर्व शर्त और कार्य करें जो पूर्व शर्त के पूरा होने के बाद लागू होते हैं:

  • पूर्व शर्त: आपने 1000 दुश्मनों को मार डाला, आपके 2 पैर हैं
  • क्रियाएँ: मुझे लालीपॉप दें, मुझे सुपर-डुपर-शॉटगन -13 दें
  • पहली बार कार्रवाई: कहते हैं "आप बहुत बढ़िया हैं!"

इसे उपयोग करें (गति के लिए गैर-अनुकूलित!):

  • सभी आँकड़े संग्रहीत करें।
  • पूर्व शर्त के लिए क्वेरी आँकड़े।
  • क्रियाएं लागू करें।
  • एक बार की क्रियाओं को एक बार करें।

यदि आप इसे तेजी से बनाना चाहते हैं:

  • कैश जो भी आप चाहते हैं, उसके कुछ हिस्सों को कुछ पेड़ों, हैश में स्टोर करें ...
  • परिवर्तन में वृद्धि करें ताकि आप हर समय सभी कार्यों को लागू न करें लेकिन ये जो नए हैं ...)

ध्यान दें

सभी चीजों के पेशेवरों और विपक्षों के बाद से सर्वोत्तम सलाह देना कठिन है ।

  • "सबसे अच्छा डेटास्ट्रक्चर क्या है?" तात्पर्य "आप इसके साथ क्या संचालन करना चाहते हैं? खोज, हटाना, जोड़ना ..."
  • आप मूल रूप से इन गुणों में सोचते हैं: कोडिंग में आसानी, गति, स्पष्टता, आकार ...

0

उपलब्धि की घटना होने के बाद एक IF जाँच में क्या गलत है?

if (Cinimatics.done)
   Achievement.get(CINIMATICS_SEEN);

if (EnemiesKiled > 200)
   Achievement.get(KILLER);

if (Damage > 2000 && TimeSinceFirstDamage < 2000)
   Achievement.get(MEAT_SHIELD);

InvitationAccepted = Invite.send(BestFriend);
if (InvitationAccepted)
   Achievement.get(A_FRIEND_IN_NEED);

3
'मैं उन स्थितियों की तुलना में "अधिक हार्डकोड" की तुलना में कुछ अधिक संगठित और बनाए रखने योग्य हूं। " '। हालांकि इस निश्चित रूप से एक छोटा सा खेल के लिए एक अच्छा KISS तरीका है।
कम्युनिस्ट डक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.