एक भूमिका खेल खेल में मुकाबला अनुक्रम प्रोग्रामिंग


13

मैं एक छोटा "खेल" लिखने की कोशिश कर रहा हूं जहां एक खिलाड़ी घूमता है और राक्षसों से लड़ता है लेकिन मुझे नहीं पता कि मुकाबला कैसे संभालना है।

उदाहरण के लिए, मान लें कि मेरे पास "योद्धा" और "ट्रोल" है। दोनों एक दूसरे से कैसे लड़ते हैं? मुझे पता है कि मैं ऐसा कुछ कर सकता हूं

Conan = Warrior.new();
CaveTroll = Troll.new();
Conan.attack(CaveTroll);
CaveTroll.attack(Conan);

लेकिन खेल का कौन सा हिस्सा राक्षस को नियंत्रित करता है? क्या मैं सिर्फ उपरोक्त अनुक्रम को एक लूप में चिपकाता हूं जब तक कि उनमें से एक मर नहीं जाता है? या खेल "इंजन" के लिए विशेष रूप से मुकाबला करने वाले एक हिस्से की आवश्यकता है? या यह ट्रोल की कृत्रिम बुद्धि का एक पहलू है जिसे इसके कार्यों की देखभाल करने की आवश्यकता है?

इसके अलावा, कौन / क्या उन कार्यों को निर्धारित करता है जो राक्षस लेता है? हो सकता है कि एक ट्रोल बैश, किक, बाइट, कास्ट मंत्र, पीने के गुण, एक जादुई वस्तु का उपयोग कर सकता है। क्या गेम इंजन यह निर्धारित करता है कि ट्रोल क्या कार्रवाई करता है या यह है कि ट्रोल वर्ग का प्रबंधन करता है?

क्षमा करें, मैं अधिक विशिष्ट नहीं हो सकता लेकिन मुझे इस दिशा में जाने के लिए कुछ मार्गदर्शन की आवश्यकता है।


ठंडा! उस साइट का अस्तित्व नहीं था। क्या कोई रास्ता है जिससे मैं अपना प्रश्न वहाँ ले जा सकूँ? या मैं बस वहाँ काट / पेस्ट करना चाहिए?

कोई चिंता नहीं, एक मॉड इसे बहुत जल्द स्थानांतरित करना चाहिए! या आप यहां प्रश्न हटा सकते हैं और खेल देव
LiamB

@ मैं पूछने के लिए माफी माँगता हूँ, लेकिन आप किस साइट से मतलब रखते हैं? गेम डेवलपर?
user712092

जवाबों:


12

मैं आपके खेल के भीतर एक लड़ाई के क्रम की कल्पना करता हूं। अपडेट टिक (या टिक्स को चालू करें) इन घटनाओं को संभालने वाले घटक को निर्देशित किया जाता है। यह दृष्टिकोण एक अलग वर्ग में लड़ाई अनुक्रम तर्क को कूटबद्ध करता है, जिससे आपका मुख्य गेम लूप खेल राज्यों के बीच संक्रमण से मुक्त हो जाता है।

void gameLoop() {
    while(gameRunning) {
        if (state == EXPLORATION) {
            // Perform actions for when player is simply walking around
            // ...
        }
        else if (state == IN_BATTLE) {
            // Perform actions for when player is in battle
            currentBattle.HandleTurn()
        }
        else if (state == IN_DIALOGUE) {
            // Perform actions for when player is talking with npcs
            // ...
        }
    }

}

लड़ाई अनुक्रम वर्ग इस तरह दिखेगा:

class BattleSequence {
    public:
        BattleSequence(Entity player, Entity enemy);
        void HandleTurn();
        bool battleFinished();

    private:
        Entity currentlyAttacking;
        Entity currentlyReceiving;
        bool finished;
}

आपका ट्रोल और योद्धा दोनों को एंटिटी नामक एक सामान्य सुपरक्लास से विरासत में मिला है। हैंडलटर्न के भीतर, हमलावर इकाई को स्थानांतरित करने की अनुमति है। यह एआई थिंक रूटीन के बराबर है।

void HandleTurn() {
    // Perform turn actions
    currentlyAttacking.fight(currentlyReceiving);

    // Switch sides
    Entity temp = currentlyAttacking;
    currentlyAttacking = currentlyReceiving;
    currentlyReceiving = temp;

    // Battle end condition
    if (currentlyReceiving.isDead() || currentlyAttacking.hasFled()) {
        finished = true;
    }
}

लड़ाई विधि यह तय करती है कि इकाई क्या करने जा रही है। ध्यान दें कि इसके लिए विरोधी संस्था को शामिल करने की आवश्यकता नहीं है, जैसे कि पोशन पीना या भाग जाना।

अपडेट: कई राक्षसों और एक खिलाड़ी पार्टी का समर्थन करने के लिए, आप एक समूह वर्ग का परिचय देते हैं:

class Group {
    public:
        void fight(Group opponents) {
            // Loop through all group members so everyone gets
            // a shot at the opponents
            for (int i = 0; i < memberCount; i++) {
                Entity attacker = members[i];
                attacker.fight(opponents);
            }
        }

        Entity get(int targetID) {
            // TODO: Bounds checking
            return members[targetID];
        }

        bool isDead() {
            bool dead = true;
            for (int i = 0; i < memberCount; i++) {
                dead = dead && members[i].isDead();
            }
            return dead;
        }

        bool hasFled() {
            bool fled = true;
            for (int i = 0; i < memberCount; i++) {
                fled = fled && members[i].hasFled();
            }
            return fled;
        }

    private:
        Entity[] members;
        int memberCount;
}

ग्रुप क्लास बैटलसेंस में एंटिटी की सभी घटनाओं की जगह लेगा। चयन और हमला एंटिटी वर्ग द्वारा ही संभाला जाएगा, इसलिए एआई बेहतरीन कार्रवाई का चयन करते समय पूरे समूह को ध्यान में रख सकता है।

class Entity {
    public:
        void fight(Group opponents) {
            // Algorithm for selecting an entity from the group
            // ...
            int targetID = 0; // Or just pick the first one

            Entity target = opponents.get(targetID);

            // Fighting algorithm
            target.applyDamage(10);
        }
}

मैं मान रहा हूं कि यह केवल एक खिलाड़ी बनाम एक राक्षस के लिए काम करेगा। या एक खिलाड़ी बनाम कई राक्षसों के लिए काम करने के लिए इसे अपडेट करना आसान होगा?
हार्व

खिलाड़ी पक्ष के रूप में दोनों तरफ के समूहों के लिए समर्थन जोड़ना काफी आसान है (आपकी स्थिति में, खिलाड़ी समूह में केवल एक सदस्य होगा: खिलाड़ी चरित्र)। मैंने इस परिदृश्य के लिए उत्तर अपडेट कर दिया है।
भूत

1

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

किए गए कार्यों के लिए, आप निश्चित रूप से इसे यादृच्छिक बना सकते हैं, लेकिन यह एक हीलिंग राक्षस बनाने के लिए पूर्ण एचपी के साथ एक राक्षस के लिए बहुत कम समझ में आता है। यह निर्धारित करने के लिए कि कौन सी कार्रवाई करनी है, उसके लिए कुछ बुनियादी तर्क देने का भुगतान करता है। उदाहरण के लिए, कुछ कार्यों में दूसरों की तुलना में अधिक प्राथमिकता हो सकती है (जैसे समय का 30% ट्रोल kicks), साथ ही लड़ाई को अधिक रोचक बनाने के लिए अन्य शर्तें (जैसे जब एचपी को पूर्ण एचपी के 10% से कम है, तो 20% है कास्टिंग हीलिंग का मौका, अन्यथा मौका 1% है)। यह आपकी तरह जटिल हो सकता है।

मुझे लगता है कि राक्षस वर्ग को यह चुनना चाहिए कि क्या कार्रवाई करनी है, लड़ाई की वस्तु राक्षस को कार्रवाई के लिए कहती है और राक्षस एक विकल्प बनाता है और फिर उसे लागू करने के लिए आगे बढ़ता है। एक विचार एक रणनीति वस्तु है जिसे आप राक्षसों में प्लग करते हैं और जो प्रत्येक लड़ाई कार्रवाई को सौंपी गई प्राथमिकताओं, श्रेणियों और शर्तों के आधार पर संभावित राक्षस क्रियाओं की सूची से चयन करता है। तब आपके पास एक आक्रामक प्रजाति श्रेणी हो सकती है उदाहरण के लिए जो रक्षात्मक कौशल पर हमलों को प्राथमिकता देती है, और एक अन्य CautiousStrategy जो चंगा होने की अधिक संभावना है। एक बॉस अपनी वर्तमान स्थिति के आधार पर रणनीति को गतिशील रूप से बदलने में सक्षम हो सकता है।

एक अंतिम बात। आप चाहते हैं कि या तो खिलाड़ी वर्ण और राक्षस दोनों एक ही वर्ग से विरासत में मिले हों, एक ही वर्ग (उदाहरण के लिए अभिनेता या लड़ाकू) के उदाहरण हों, या एक सामान्य वस्तु साझा करें जो सामान्य कार्यक्षमता को ध्वस्त कर दे। यह कोड के दोहराव को कम करता है और यह आपको अपनी तरफ से AI- नियंत्रित NPCs की भी अनुमति देगा जो उन्हीं रणनीतियों को लागू कर सकता है जिन्हें आप पहले से ही राक्षसों के लिए कोडित करते थे।


1

हां, आपको अपने इंजन में एक विशेष भाग की आवश्यकता है जो युद्ध से निपटता है।

मैं नहीं जानता कि आप वास्तव में अपना मुकाबला कैसे कर रहे हैं, लेकिन मुझे लगता है कि खिलाड़ी खेल की दुनिया में घूमेंगे, राक्षसों से मिलेंगे और लड़ाई वास्तविक समय में होगी। यदि ऐसा है, तो ट्रोल को एक निश्चित क्षेत्र के भीतर आसपास के बारे में जानने की जरूरत है, शायद यह परिभाषित करता है कि ट्रोल इसके सामने कुछ कैसे देख सकता है (ट्रोल इसे संभालता है)।

एआई के बारे में, मुझे लगता है कि इंजन को खुद को संभालने की जरूरत है, ताकि मान लें कि आपके पास एक से अधिक प्रकार के दुश्मन हैं जो एक ही काम कर सकते हैं (काटने), आप बस एआई को एक और राक्षस को सौंप सकते हैं और वहां आप जा सकते हैं!


0

आपका खिलाड़ी और आपका ट्रोल कुछ और नहीं बल्कि डेटा के सेट हैं, जिसे हम डेटा मॉडल कहते हैं जो आपकी दुनिया का वर्णन करता है। जीवन, सूची, हमले की क्षमता, दुनिया का उनका ज्ञान - यहां तक ​​कि सभी डेटा मॉडल में शामिल हैं।

एक एकल, मुख्य मॉडल ऑब्जेक्ट रखें जो आपकी दुनिया का वर्णन करने वाले सभी डेटा को रखता है। यह सामान्य दुनिया की जानकारी जैसे कि कठिनाई, भौतिकी मापदंडों आदि को धारण करेगा । जैसा कि मैंने ऊपर वर्णित किया है, यह विशिष्ट संस्थाओं के डेटा की एक सूची / सरणी भी रखेगा । इस मुख्य मॉडल में आपकी दुनिया का वर्णन करने के लिए कई उप-विषय शामिल हो सकते हैं। आपके मॉडल में कहीं भी आपके पास कोई कार्य नहीं होना चाहिए जो गेम लॉजिक या डिस्प्ले लॉजिक को नियंत्रित करता है; गेटर्स एकमात्र अपवाद हैं, और इसका उपयोग केवल मॉडल से डेटा को अधिक आसानी से प्राप्त करने की अनुमति देने के लिए किया जाएगा (यदि सार्वजनिक सदस्य पहले से ही चाल नहीं करते हैं)।

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

class Main
{

//...members variables...
var model:GameModel = new GameModel();

//...member functions...
function realTimeUpdate() //called x times per second, on a timer.
{
    for each (var entity in model.entities)
    {
        //command processing
        if (entity == player)
            decideActionsFromPlayerInput(entity);
        else //everyone else is your enemy!
            decideActionsThroughDeviousAI(entity);

        act(entity);
    }
}
//OR
function turnBasedUpdate()
{
    if (model.whoseTurn == "player")
    {
        decideActionsFromInput(model.player); //may be some movement or none at all
        act(player);
    }
    else
    {
        var enemy;
        for each (var entity in model.entities)
        {
            if (entity != model.player)
            {
                enemy = entity;
                decideActions(enemy);
                act(enemy);
            }
        }
    }
}

//AND THEN... (common to both turn-based and real-time)
function decideActionsThroughDeviousAI(enemy)
{
    if (distanceBetween(enemy, player) <= enemy.maximumAttackDistance)
        storeAttackCommand(enemy, "kidney punch", model.player);
    else
        storeMoveCommand(player, getVectorFromTo(enemy, model.player));

}

function decideActionsFromPlayerInput(player)
{
    //store commands to your player data based on keyboard input
    if (KeyManager.isKeyDown("A"))
        storeMoveCommand(player, getForwardVector(player));
    if (KeyManager.isKeyDown("space"))
        storeAttackCommand(player, "groin slam", currentlyHighlightedEnemy);
}
function storeAttackCommand(entity, attackType, target)
{
    entity.target = target;

    entity.currentAttack = attackType;
    //OR
    entity.attackQueue.add(attackType);
}
function storeMoveCommand(entity, motionVector)
{
    entity.motionVector = motionVector;
}
function act(entity)
{
    entity.position += entity.motionVector;
    attack(entity.target, entity.currentAttack);
}
}

class GameModel
{
    var entities:Array = []; //or List<Entity> or whatever!
    var player:Entity; //will often also appear in the entity list, above
    var difficultyLevel:int;
    var globalMaxAttackDamage:int;
    var whoseTurn:Boolean; //if turnbased
    //etc.

}

एक अंतिम नोट यह है कि आपके डिस्प्ले लॉजिक को आपके गेम लॉजिक से अलग रखना भी उपयोगी है। प्रदर्शन तर्क होगा, "मैं इसे स्क्रीन पर और किस रंग में खींचता हूं?" बनाम खेल तर्क मैं ऊपर छद्म में उल्लिखित किया जा रहा है।

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


1
"एक एकल, मुख्य मॉडल ऑब्जेक्ट रखें जो आपकी दुनिया का वर्णन करने वाले सभी डेटा को रखता है। यह सामान्य दुनिया की जानकारी जैसे कि कठिनाई, भौतिक विज्ञान की डिग्री आदि को रखेगा।" कठिनाई और भौतिकी पैरामीटर? चिंताओं के टकराव के बारे में बात करो! -1।

2
@ जो - क्या आप चाहते हैं कि मैं उनके साथ पूरे विन्यास पदानुक्रम की रूपरेखा तैयार करूँ? हम इसे यहाँ सरल रख रहे हैं, क्या हम नहीं हैं? मैं सराहना करता हूं कि क्या आप डाउनवोटिंग से पहले सोचेंगे।
इंजीनियर

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

1
@ जो: मैं मानता हूं कि एमवीसी एक खेल के लिए एक मोटा विकल्प है, लेकिन मुझे पूरा यकीन है कि यहां वी की भूमिका स्पष्ट है।
Zach कॉन

4
@Zach: जब "एफपी इज द अल्टीमेट एमवीसी" जैसे दावे किए जाते हैं, तो कुछ भी स्पष्ट नहीं होता है, सिवाय इसके कि पोस्टर एमवीसी और कार्यात्मक प्रोग्रामिंग दोनों को समझने में विफल रहता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.