2010-11-16 20 views
83

मैं अपनी साइट पर उपयोग के लिए उपलब्धि प्रणाली तैयार करने का सबसे अच्छा तरीका सोच रहा हूं। डेटाबेस संरचना Best way to tell 3 or more consecutive records missing पर पाई जा सकती है और यह धागा वास्तव में डेवलपर्स के विचार प्राप्त करने का एक विस्तार है।उपलब्धियों को कोड करने का सबसे अच्छा तरीका

इस वेबसाइट पर बैज/उपलब्धि सिस्टम के बारे में बहुत सी बातों के साथ मेरी समस्या यह है कि - यह सब बात है और कोई कोड नहीं है। वास्तविक कोड कार्यान्वयन उदाहरण कहां है?

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

कृपया अपने विचारों का योगदान करने के लिए स्वतंत्र महसूस करें।


अपने सिस्टम डिजाइन विचार

ऐसा लगता है आम सहमति एक "घटना आधारित प्रणाली" बनाने के लिए है - जब भी एक ज्ञात घटना एक पोस्ट बनाया जाता है, नष्ट कर दिया की तरह होता है, आदि यह कहता है इसलिए जैसे घटना वर्ग ..

$event->trigger('POST_CREATED', array('id' => 8)); 

घटना वर्ग तो पता चल गया क्या बैज इस घटना के लिए "सुन" रहे हैं, तो यह requires कि फाइल है, और इसलिए की तरह, उस वर्ग का एक उदाहरण बनाता है:

require '/badges/' . $file; 
$badge = new $class; 

फिर यह trigger कहलाते समय प्राप्त डेटा को पास करने वाली डिफ़ॉल्ट घटना को कॉल करता है;

$badge->default_event($data); 

बैज

यह तो जहां असली जादू होता है। बैज को सम्मानित किया जाना चाहिए या नहीं, यह निर्धारित करने के लिए प्रत्येक बैज की अपनी क्वेरी/तर्क होता है। प्रत्येक बैज उदा। इस प्रारूप:

class Badge_Name extends Badge 
{ 
const _BADGE_500 = 'POST_500'; 
const _BADGE_300 = 'POST_300'; 
const _BADGE_100 = 'POST_100'; 

function get_user_post_count() 
{ 
    $escaped_user_id = mysql_real_escape_string($this->user_id); 

    $r = mysql_query("SELECT COUNT(*) FROM posts 
        WHERE userid='$escaped_user_id'"); 
    if ($row = mysql_fetch_row($r)) 
    { 
    return $row[0]; 
    } 
    return 0; 
} 

function default_event($data) 
{ 
    $post_count = $this->get_user_post_count(); 
    $this->try_award($post_count); 
} 

function try_award($post_count) 
{ 
    if ($post_count > 500) 
    { 
    $this->award(self::_BADGE_500); 
    } 
    else if ($post_count > 300) 
    { 
    $this->award(self::_BADGE_300); 
    } 
    else if ($post_count > 100) 
    { 
    $this->award(self::_BADGE_100); 
    } 

} 
} 

award समारोह एक विस्तारित वर्ग Badge जो मूल रूप से देखने के लिए उपयोगकर्ता पहले से ही, कि बिल्ला से सम्मानित किया गया है, अगर नहीं, बिल्ला db तालिका अद्यतन करेगा की जाँच करता है से आता है। बिल्ला वर्ग भी आदि एक उपयोगकर्ता के लिए सभी बैज पुन: प्राप्त करने और एक सरणी में यह लौटने का ख्याल रखता है (ताकि बैज जैसे हो सकता है उपयोगकर्ता प्रोफ़ाइल पर प्रदर्शित)

क्या है जब सिस्टम बहुत पहले एक पहले से ही लागू किया गया है के बारे में लाइव साइट?

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

class Badge_Name_Cron extends Badge_Name 
{ 

function cron_job() 
{ 
    $r = mysql_query('SELECT COUNT(*) as post_count, user_id FROM posts'); 

    while ($obj = mysql_fetch_object($r)) 
    { 
    $this->user_id = $obj->user_id; //make sure we're operating on the right user 

    $this->try_award($obj->post_count); 
    } 
} 

} 

ऊपर क्रॉन वर्ग मुख्य बिल्ला वर्ग फैली रूप में, यह तर्क समारोह try_award

कारण फिर से उपयोग कर सकते हैं कारण है कि मैं एक विशेष बनाने के लिए: उदाहरण के लिए ऊपर के लिए क्रॉन जॉब कैसा लगेगा इसके लिए पूछताछ हालांकि हम पिछले घटनाओं, यानी "अनुकरण" कर सकते हैंप्रत्येक उपयोगकर्ता पोस्ट के माध्यम से जाएं और इवेंट क्लास को $event->trigger() जैसे ट्रिगर करें, यह बहुत धीमा होगा, खासकर कई बैज के लिए। तो हम इसके बजाय एक अनुकूलित क्वेरी बनाते हैं।

क्या उपयोगकर्ता पुरस्कार हो जाता है? सभी घटना

Badge वर्ग award समारोह user_id पर कार्य करता है के आधार पर देने अन्य उपयोगकर्ताओं के बारे में - वे हमेशा पुरस्कार दिया जाएगा। डिफ़ॉल्ट रूप से बैज उस व्यक्ति को दिया जाता है जिसने घटना होने के कारण सत्र सत्र आईडी (यह default_event फ़ंक्शन के लिए सच है, हालांकि सीआरओएन नौकरी स्पष्ट रूप से सभी उपयोगकर्ताओं और पुरस्कारों के माध्यम से अलग हो जाती है)

तो चलिए लेते हैं एक उदाहरण, एक कोडिंग चुनौती वेबसाइट उपयोगकर्ताओं पर उनकी कोडिंग प्रविष्टि जमा करते हैं। व्यवस्थापक तब प्रविष्टियों का न्याय करता है और पूरा होने पर, परिणाम देखने के लिए चुनौती पृष्ठ पर परिणाम पोस्ट करता है। जब ऐसा होता है, तो POSTED_RESULTS ईवेंट कहा जाता है।

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

यदि आप क्रॉन नौकरी के साथ अद्यतन करने के लिए एक और विशिष्ट क्षेत्र को लक्षित करना चाहते हैं, तो देखते हैं कि क्रॉन जॉब ऑब्जेक्ट में फ़िल्टरिंग पैरामीटर जोड़ने का कोई तरीका है या cron_job प्राप्त करें उनका उपयोग करने के लिए समारोह। उदाहरण के लिए:

class Badge_Top5 extends Badge 
{ 
    const _BADGE_NAME = 'top5'; 

    function try_award($position) 
    { 
    if ($position <= 5) 
    { 
     $this->award(self::_BADGE_NAME); 
    } 
    } 
} 

class Badge_Top5_Cron extends Badge_Top5 
{ 
    function cron_job($challenge_id = 0) 
    { 
    $where = ''; 
    if ($challenge_id) 
    { 
     $escaped_challenge_id = mysql_real_escape_string($challenge_id); 
     $where = "WHERE challenge_id = '$escaped_challenge_id'"; 
    } 

    $r = mysql_query("SELECT position, user_id 
         FROM challenge_entries 
         $where"); 

    while ($obj = mysql_fetch_object($r)) 
    { 
     $this->user_id = $obj->user_id; //award the correct user! 
     $this->try_award($obj->position); 
    } 
} 

पैरामीटर की आपूर्ति नहीं होने पर भी क्रॉन फ़ंक्शन काम करेगा।

+0

संबंधित (शायद नकल): http://stackoverflow.com/questions/1744747/achievements-badges-system – Gordon

+2

यह संबंधित है, लेकिन नकल नहीं। कृपया दूसरा पैराग्राफ पढ़ें। "समस्या मैं बैज के बारे में बात करते हैं की बहुत सारी के साथ है/इस वेबसाइट पर उपलब्धि सिस्टम सिर्फ इतना है कि है - यह सब बात है और कोई कोड कहाँ वास्तविक कोड अंतर्गत प्रयोग उदाहरण है।?" –

+1

अच्छी तरह से, कामकाजी कोड लिखना केवल कुछ हद तक व्यवहार्य है। मैं कहूंगा कि लोगों के लिए केवल सिद्धांत ही आपको सामान्य करना होगा, एक बार जब कोई कार्यान्वयन बहुत जटिल होगा। – Gordon

उत्तर

9

मैं क्या आप एक दस्तावेज़ उन्मुख डेटाबेस कहेंगे में एक इनाम प्रणाली एक बार क्रियान्वित किया है (यह खिलाड़ियों के लिए एक मिट्टी) था। मेरी कार्यान्वयन से कुछ मुख्य बातें, PHP और MySQL के लिए अनुवाद:

  • बिल्ला के बारे में हर विस्तार उन डेटा में संग्रहित है। यदि आप MySQL का उपयोग करते हैं तो मैं यह सुनिश्चित कर दूंगा कि यह डेटा प्रदर्शन के लिए डेटाबेस में प्रति उपयोगकर्ता एक रिकॉर्ड में है।

  • प्रत्येक बार प्रश्न में व्यक्ति कुछ करता है, कोड किसी दिए गए ध्वज के साथ बैज कोड ट्रिगर करता है, उदाहरण के लिए ध्वज ('POST_MESSAGE')।

  • एक घटना भी पदों की संख्या की गिनती उदाहरण के लिए एक काउंटर चालू कर सकते। increase_count ('POST_MESSAGE')। ("300_POST") झंडा: यहाँ में आप एक चेक हो सकता था (या तो एक हुक से, या बस इस विधि में एक परीक्षण कर रहा) है कि अगर POST_MESSAGE गिनती> 300 है तो आप उदाहरण के लिए एक बिल्ला इनाम, होना चाहिए।

  • झंडा विधि में, मैं बैज पुरस्कृत करने के लिए कोड को। उदाहरण के लिए, यदि ध्वज 300_POST भेजा जाता है, तो बैज इनाम_बैज ("300_POST") कहा जाना चाहिए।

  • झंडा विधि में, आप भी उन पिछले झंडे वर्तमान होना चाहिए। तो आप कह सकते हैं आप बिल्ला अनुदान जब उपयोगकर्ता FIRST_COMMENT, FIRST_POST, FIRST_READ है ("नया उपयोगकर्ता"), और जब आप 100_COMMENT, 100_POST, 300_READ मिल आप बिल्ला प्रदान कर सकते हैं ("EXPERIENCED_USER")

  • इन झंडे के सभी और बैज को किसी भी तरह से संग्रहीत करने की आवश्यकता है। कुछ तरीकों का प्रयोग करें जहां आप झंडे के रूप में झंडे के बारे में सोचते हैं। यदि आप इसे वास्तव में कुशलतापूर्वक संग्रहीत करना चाहते हैं, तो आप उन्हें बिट्स के रूप में सोचते हैं और नीचे दिए गए कोड का उपयोग करते हैं: (या यदि आप इस जटिलता को नहीं चाहते हैं तो आप केवल एक नंगे स्ट्रिंग "000000001111000" का उपयोग कर सकते हैं।

$achievments = 0; 
$bits = sprintf("%032b", $achievements); 

/* Set bit 10 */ 
$bits[10] = 1; 

$achievements = bindec($bits); 

print "Bits: $bits\n"; 
print "Achievements: $achievements\n"; 

/* Reload */ 

$bits = sprintf("%032b", $achievments); 

/* Set bit 5 */ 
$bits[5] = 1; 

$achievements = bindec($bits); 

print "Bits: $bits\n"; 
print "Achievements: $achievements\n"; 
  • उपयोगकर्ता के लिए एक दस्तावेज़ भंडारण का एक अच्छा तरीका एक पाठ स्तंभ में json का उपयोग करें और उन डाटा स्टोर करने की है। डेटा को स्टोर/पुनर्प्राप्त करने के लिए json_encode और json_decode का उपयोग करें।

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

+1

बैज सिस्टम में क्लासिक ट्रेंड आपकी तालिका में नई सांख्यिकी के लिए एक नया फ़ील्ड जोड़ना है। मेरे लिए, कि बाहर एक आसान तरीका और बुरा विचार है क्योंकि आपके भंडारण नजर आता डेटा डेटा से गणना की जा सकती है कि पहले से ही) तालिका (शायद एक सरल COUNT (जो MyISAM तालिकाओं पर बहुत तेजी से होता में का एक सा की तरह लगता है, 100% हो जाएगा सटीक)। यदि प्रदर्शन आपका लक्ष्य था, तो आपको एक अपडेट करना होगा और वर्तमान उदाहरण प्राप्त करने के लिए चयन करना होगा। एक बैज से सम्मानित किया जाना चाहिए या नहीं, यह जांचने के लिए post_count मान। आपको केवल एक प्रश्न की आवश्यकता हो सकती है, COUNT (*)। मैं और अधिक जटिल डेटा के लिए सहमत एक क्षेत्र हालांकि –

+5

@Gary ग्रीन यह है न केवल एक आसान तरीका बाहर है, यह भी स्केलेबल रास्ता और दस्तावेज़ डेटाबेस के साथ संगत है जोड़ने के लिए अच्छा कारण नहीं होगा। शुद्धता के लिए, आप सही हैं, हालांकि बैज सिस्टम के लिए मैं इसे जल्दी और 100% से अधिक सही और धीमी गति से सही कर दूंगा। एक सिंगल गिनती शायद तेज़ है, लेकिन जब आपका सिस्टम स्केल करता है और आपके पास बहुत सारे उपयोगकर्ता हैं तो यह रणनीति नहीं दी जाती है। – Knubo

+1

मैं सिर्फ होने बिल्ला परिभाषा तालिका का विचार है, और बैज और उनकी वर्तमान प्रगति के लिए उपयोगकर्ताओं को जोड़ने के लिए एक लिंक तालिका की तरह। ऐसा करने से कोई भी एसक्यूएल उस समय आपको जो भी स्कीमा में लॉक करता है और बैज में अचानक टाइपिंग मिलने पर 1000 नए बैज जोड़े जाने पर बनाए रखने योग्य नहीं होता है। त्वरित बैक्रीवल के लिए आप हमेशा बैच प्रक्रिया को दस्तावेज़ दस्तावेज़ में अधिक कैश कर सकते हैं, लेकिन मैं चीजों को लिंक कर दूंगा। – FlavorScape

2

उपयोगकर्ता इन्फ्यूज़र एक ओपन सोर्स गैमिफिकेशन प्लेटफॉर्म है जो बैजिंग/पॉइंट सेवा लागू करता है। आप यहां अपना एपीआई देख सकते हैं: http://code.google.com/p/userinfuser/wiki/API_Documentation

मैंने इसे कार्यान्वित किया और कार्यों की संख्या को न्यूनतम रखने की कोशिश की। यहाँ एक php ग्राहक के लिए एपीआई है:

class UserInfuser($account, $api_key) 
{ 
    public function get_user_data($user_id); 
    public function update_user($user_id); 
    public function award_badge($badge_id, $user_id); 
    public function remove_badge($badge_id, $user_id); 
    public function award_points($user_id, $points_awarded); 
    public function award_badge_points($badge_id, $user_id, $points_awarded, $points_required); 
    public function get_widget($user_id, $widget_type); 
} 

अंतिम परिणाम विजेट का उपयोग के माध्यम से एक सार्थक तरीके से डेटा दिखाने के लिए है। इन विगेट्स में शामिल हैं: ट्रॉफी केस, लीडरबोर्ड, मील का पत्थर, लाइव नोटिफिकेशन, रैंक और पॉइंट्स।

एपीआई के कार्यान्वयन यहां पाया जा सकता: http://code.google.com/p/userinfuser/source/browse/trunk/serverside/api/api.py

+1

यह PHP आधारित है? प्रश्न PHP – emaillenin

+1

पर आधारित है इसमें PHP बाइंडिंग हैं, लेकिन सर्वर साइड कोड पायथन में लिखा गया है। –

0

उपलब्धियां भारी हो सकता है और इससे भी अधिक अगर आप उन्हें बाद में जोड़ने के लिए, जब तक आप एक अच्छी तरह से गठित Event वर्ग की है।

यह उपलब्धियों को लागू करने की मेरी तकनीक में है।

मैं उन्हें पहले 'श्रेणियों' में विभाजित करना चाहता हूं और उनमें से उपलब्धि के स्तर हैं। एक खेल में अर्थात एक kills श्रेणी पहले मार के लिए, 10 दस मारता, 1000 हजार मारता आदि

तो किसी भी अच्छे आवेदन की रीढ़ की हड्डी में, वर्ग अपने घटनाओं से निपटने 1 में एक पुरस्कार हो सकता है। फिर से मारने के साथ एक खेल की कल्पना; जब कोई खिलाड़ी कुछ मारता है, सामान होता है। हत्या का उल्लेख किया गया है, आदि और यह सबसे केंद्रीकृत स्थान, जैसे Events वर्ग में सबसे अच्छा है, जो शामिल अन्य स्थानों पर जानकारी भेज सकता है।

यह पूरी तरह से जगह पर गिरता है, उचित तरीके से, अपने Achievements कक्षा को तुरंत चालू करें और जांचें कि खिलाड़ी एक कारण है।

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

मैं रेडिस का उपयोग करके बिटफिल्ड में उपयोगकर्ता की उपलब्धियों को स्टोर करना चाहता हूं लेकिन उसी तकनीक का उपयोग MySQL में किया जा सकता है। यही है, आप खिलाड़ी की उपलब्धियों को int और फिर and के रूप में स्टोर कर सकते हैं, जो कि उस उपलब्धि के रूप में परिभाषित किया गया है जिसे आप पहले ही प्राप्त कर चुके हैं या नहीं। इस तरह यह डेटाबेस में केवल एक ही int कॉलम का उपयोग करता है।

इस के नकारात्मक पक्ष यह है कि आप उन्हें अच्छी तरह से आयोजित किया है करने के लिए है और आप की संभावना अपने कोड में कुछ टिप्पणी करने के लिए ताकि आप याद होगा क्या 2^14 के लिए बाद में मेल खाती है की आवश्यकता होगी है। अपनी उपलब्धियों के लिए अपने स्वयं तालिका में प्रगणित रहे हैं तो आप बस जहां pk उपलब्धियों तालिका के प्राथमिक कुंजी है 2^पी कर सकते हैं। यही कारण है कि जैसे

if(((2**$pk) & ($usersAchInt)) > 0){ 
    // fire off the giveAchievement() event 
} 

जांच कुछ इस तरह से आप बाद में उपलब्धियों को जोड़ सकते हैं और यह ठीक सामंजस्य स्थापित होगा, बस कभी उपलब्धियों को पहले से ही सम्मानित की प्राथमिक कुंजी बदलने बनाता है।

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