2011-03-07 15 views
11

के लिए सामान्य डिजाइन मैं अपने मजेदार और प्रशिक्षण के लिए एक छोटा सा गेम तैयार कर रहा हूं। गेम की वास्तविक पहचान मेरे वास्तविक प्रश्न के लिए काफी अप्रासंगिक है, मान लीजिए कि यह Mastermind गेम है (जो वास्तव में है :)कंसोल और जीयूआई

मेरा असली लक्ष्य यहां इंटरफ़ेस IPlayer है जिसका उपयोग किसी भी प्लेयर के लिए किया जाएगा: कंप्यूटर या मानव, कंसोल या गुई, स्थानीय या नेटवर्क। मैं गेमकंट्रोलर रखने का भी इरादा रखता हूं, जो केवल दो IPlayer एस के साथ सौदा करेगा।

iPlayer इंटरफेस कुछ इस तरह दिखेगा:

class IPlayer 
{ 
public: 
    //dtor 
    virtual ~IPlayer() 
    { 
    } 
    //call this function before the game starts. In subclasses, 
    //the overriders can, for example, generate and store the combination. 
    virtual void PrepareForNewGame() = 0; 
    //make the current guess 
    virtual Combination MakeAGuess() = 0; 
    //return false if lie is detected. 
    virtual bool ProcessResult(Combination const &, Result const &) = 0; 
    //Answer to opponent's guess 
    virtual Result AnswerToOpponentsGuess(Combination const&) = 0; 
}; 

GameController वर्ग कुछ इस तरह करना होगा:

IPlayer* pPlayer1 = PlayerFactory::CreateHumanPlayer(); 
IPlayer* pPlayer1 = PlayerFactory::CreateCPUPlayer(); 

pPlayer1->PrepareForNewGame(); 
pPlayer2->PrepareForNewGame(); 

while(no_winner) 
{ 
    Guess g = pPlayer1->MakeAguess(); 
    Result r = pPlayer2->AnswerToOpponentsGuess(g); 
    bool player2HasLied = ! pPlayer1->ProcessResult(g, r); 
    etc. 
    etc. 
} 

इस डिजाइन से, मैं GameController वर्ग अपरिवर्तनीय बनाने के लिए तैयार हूँ, कि है, मैं इसमें सिर्फ गेम नियमों को प्रस्तुत करता हूं, और कुछ और नहीं, इसलिए जब खेल स्वयं स्थापित होता है, तो इस वर्ग को नहीं बदला जाना चाहिए। एक कंसोल गेम के लिए यह डिज़ाइन पूरी तरह से काम करेगा। मैं HumanPlayer है, जो अपनी MakeAGuess विधि में मानक इनपुट से एक Combination पढ़ता था, और एक CPUPlayer है, जो किसी भी तरह बेतरतीब ढंग से यह उत्पन्न होगा होता आदि

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

क्या आप कृपया मेरे डिजाइन और सिंक्रोनस या असिंक्रोनस डिज़ाइन चुनने के बारे में मेरी चिंताओं पर टिप्पणी करेंगे? साथ ही, मुझे लगता है कि मैंने गेमकंट्रोलर क्लास की तुलना में प्लेयर क्लास पर अधिक ज़िम्मेदारी डाली है। आदि, आदि

अग्रिम में बहुत बहुत धन्यवाद।

पीएस मुझे अपने प्रश्न का शीर्षक पसंद नहीं है। संपादित यह :)

+7

मुझे शीर्षक पसंद है :-) –

+1

मैंने सी # टैग हटा दिया, क्योंकि इस प्रश्न के पास कहीं भी सी # नहीं है। – Puppy

+1

चूंकि भाषा अप्रासंगिक है, इसलिए मैं सी # विशेषज्ञों की राय के साथ-साथ –

उत्तर

11

इसके बजाय विभिन्न IPlayer तरीकों की वापसी मान का उपयोग कर के, IPlayer वस्तुओं के लिए एक पर्यवेक्षक वर्ग को शुरू करने पर विचार, इस तरह के लिए स्वतंत्र महसूस:

class IPlayerObserver 
{ 
public: 
    virtual ~IPlayerObserver() { } 
    virtual void guessMade(Combination c) = 0; 
    // ... 
}; 

class IPlayer 
{ 
public: 
    virtual ~IPlayer() { } 
    virtual void setObserver(IPlayerObserver *observer) = 0; 
    // ... 
}; 

IPlayer के तरीकों उसके बाद उपयुक्त बुलाना चाहिए एक स्थापित IPlayerObserver के तरीकों के बजाय के रूप में एक मूल्य लौटने:

void HumanPlayer::makeAGuess() { 
    // get input from human 
    Combination c; 
    c = ...; 
    m_observer->guessMade(c); 
} 

आपका GameController वर्ग तो तो यह है कि IPlayerObserver को लागू कर सकता है जब भी किसी खिलाड़ी ने कुछ दिलचस्प किया, जैसे अनुमान लगाया जाता है तो अधिसूचित हो जाता है।

इस डिज़ाइन के साथ, यह बिल्कुल ठीक है अगर सभी IPlayer विधियां असीमित हैं। वास्तव में, यह उम्मीद की जा रही है - वे सभी void वापस आते हैं!आपका गेम कंट्रोलर सक्रिय प्लेयर पर makeAGuess पर कॉल करता है (यह परिणाम तुरंत गणना कर सकता है, या यह मल्टीप्लेयर गेम के लिए कुछ नेटवर्क IO कर सकता है, या यह GUI के लिए कुछ करने का इंतजार करेगा) और जब भी खिलाड़ी ने अपनी पसंद की, गेम नियंत्रक आश्वासन दिया जा सकता है कि guessMade विधि कहा जाएगा। फर्टहेमोर, प्लेयर ऑब्जेक्ट्स अभी भी गेम नियंत्रक के बारे में कुछ भी नहीं जानते हैं। वे सिर्फ एक अपारदर्शी 'iplayerObserver' इंटरफ़ेस से निपट रहे हैं।

1

कंसोल की तुलना में जीयूआई के लिए यह अलग करने वाली एकमात्र चीज यह है कि आपका जीयूआई संचालित होता है। वे घटनाएं जीयूआई थ्रेड पर होती हैं, और इसलिए, यदि आप जीयूआई थ्रेड पर गेम कोड होस्ट करते हैं, तो आपको एक समस्या है: खिलाड़ी को GUI थ्रेड को अवरुद्ध करने के लिए आपका कॉल करने का आह्वान होता है, और इसका मतलब है कि आप नहीं प्राप्त कर सकते कॉल रिटर्न तक कोई घटनाएं। [संपादित करें: निम्नलिखित वाक्य डालें।] लेकिन कॉल तब तक वापस नहीं आ सकता जब तक कि यह ईवेंट न हो जाए। तो आप deadlocked हैं।

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

यदि आप सबकुछ एकल-थ्रेडेड रखना चाहते हैं तो आप एक अलग मॉडल पर विचार करना चाहेंगे। खेल खिलाड़ियों को सूचित कर सकता है कि यह एक घटना के साथ उनकी बारी है लेकिन गेम पर संचालन शुरू करने के लिए इसे खिलाड़ियों को छोड़ दें।

संबंधित मुद्दे