Ich denke über den besten Weg nach, ein Leistungssystem für die Verwendung auf meiner Website zu entwerfen. Die Datenbankstruktur finden Sie unter Bester Weg, um 3 oder mehr fehlende aufeinanderfolgende Datensätze zu erkennen, und dieser Thread ist wirklich eine Erweiterung, um die Ideen von Entwicklern zu erhalten.
Das Problem, das ich mit vielen Gesprächen über Abzeichen / Leistungssysteme auf dieser Website habe, ist genau das - es ist alles Gerede und kein Code. Wo sind die tatsächlichen Beispiele für die Codeimplementierung?
Ich schlage hier ein Design vor, zu dem die Leute hoffentlich beitragen und hoffentlich ein gutes Design für die Codierung erweiterbarer Leistungssysteme erstellen können. Ich sage nicht, dass dies das Beste ist, weit davon entfernt, aber es ist ein möglicher Startblock.
Bitte zögern Sie nicht, Ihre Ideen einzubringen.
meine Systemdesign-Idee
Es scheint, dass der allgemeine Konsens darin besteht, ein "ereignisbasiertes System" zu erstellen - wenn ein bekanntes Ereignis auftritt, wie ein Beitrag erstellt, gelöscht usw. wird, wird die Ereignisklasse wie folgt aufgerufen.
$event->trigger('POST_CREATED', array('id' => 8));
Die Ereignisklasse findet dann heraus, welche Badges auf dieses Ereignis "warten", dann auf diese requires
Datei und erstellt eine Instanz dieser Klasse wie folgt:
require '/badges/' . $file;
$badge = new $class;
Anschließend wird das Standardereignis trigger
aufgerufen, das die beim Aufruf empfangenen Daten übergibt .
$badge->default_event($data);
die Abzeichen
Hier geschieht dann die wahre Magie. Jedes Abzeichen hat eine eigene Abfrage / Logik, um zu bestimmen, ob ein Abzeichen vergeben werden soll. Jedes Abzeichen ist zB in folgendem Format angegeben:
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
Die Funktion stammt aus einer erweiterten Klasse, Badge
die im Grunde prüft, ob dem Benutzer dieses Badge bereits zuerkannt wurde. Wenn nicht, wird die Badge-DB-Tabelle aktualisiert. Die Ausweisklasse kümmert sich auch darum, alle Ausweise für einen Benutzer abzurufen und in einem Array usw. zurückzugeben (so können Ausweise z. B. im Benutzerprofil angezeigt werden).
Was ist, wenn das System zum ersten Mal auf einer bereits aktiven Site implementiert wird?
Es gibt auch eine "Cron" -Jobabfrage, die jedem Ausweis hinzugefügt werden kann. Der Grund dafür ist, dass bei der erstmaligen Implementierung und Initiierung des Ausweissystems die bereits erworbenen Ausweise noch nicht vergeben wurden, da es sich um ein ereignisbasiertes System handelt. Daher wird bei Bedarf für jedes Abzeichen ein CRON-Job ausgeführt, um alles zu vergeben, was erforderlich ist. Zum Beispiel würde der CRON-Job für das Obige folgendermaßen aussehen:
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);
}
}
}
Da die obige Cron-Klasse die Haupt-Badge-Klasse erweitert, kann sie die Logikfunktion wiederverwenden try_award
Der Grund, warum ich eine spezielle Abfrage dafür erstelle, ist, dass wir frühere Ereignisse "simulieren" könnten, dh jeden Benutzerbeitrag durchgehen und die Ereignisklasse auslösen, als $event->trigger()
wäre sie sehr langsam, insbesondere für viele Abzeichen. Also erstellen wir stattdessen eine optimierte Abfrage.
Welcher Benutzer erhält die Auszeichnung? Alles über die Vergabe anderer Benutzer basierend auf dem Ereignis
Die Badge
Klassenfunktion award
wirkt auf user_id
- sie erhalten immer die Auszeichnung. Standardmäßig wird der Ausweis an die Person vergeben, die das Ereignis verursacht hat, dh die Sitzungsbenutzer-ID (dies gilt für die default_event
Funktion, obwohl der CRON-Job offensichtlich alle Benutzer durchläuft und separate Benutzer vergibt).
Nehmen wir also ein Beispiel für eine Codierungs-Challenge-Website, auf der Benutzer ihren Codierungseintrag einreichen. Der Administrator beurteilt dann die Einträge und veröffentlicht die Ergebnisse nach Abschluss auf der Herausforderungsseite, damit alle sie sehen können. In diesem Fall wird ein POSTED_RESULTS-Ereignis aufgerufen.
Wenn Sie für alle veröffentlichten Einträge Ausweise für Benutzer vergeben möchten, sollten Sie beispielsweise den Cron-Job verwenden, wenn diese unter den Top 5 stehen (obwohl dies nicht nur für diese Herausforderung, sondern auch für alle Benutzer aktualisiert wird Ergebnisse wurden veröffentlicht für)
Wenn Sie auf einen bestimmten Bereich abzielen möchten, der mit dem Cron-Job aktualisiert werden soll, prüfen Sie, ob es eine Möglichkeit gibt, dem Cron-Jobobjekt Filterparameter hinzuzufügen, und lassen Sie die Funktion cron_job diese verwenden. Beispielsweise:
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);
}
}
Die Cron-Funktion funktioniert auch dann noch, wenn der Parameter nicht angegeben wird.
quelle
Antworten:
Ich habe einmal ein Belohnungssystem in einer so genannten dokumentenorientierten Datenbank implementiert (dies war ein Schlamm für die Spieler). Einige Highlights aus meiner Implementierung, übersetzt in PHP und MySQL:
Jedes Detail des Ausweises wird in den Benutzerdaten gespeichert. Wenn Sie MySQL verwenden, hätte ich sichergestellt, dass sich diese Daten aus Leistungsgründen in einem Datensatz pro Benutzer in der Datenbank befinden.
Jedes Mal, wenn die betreffende Person etwas tut, löst der Code den Ausweiscode mit einem bestimmten Flag aus, beispielsweise einem Flag ('POST_MESSAGE').
Ein Ereignis kann auch einen Zähler auslösen, beispielsweise die Anzahl der Beiträge. erhöhen_anzahl ('POST_MESSAGE'). Hier können Sie überprüfen (entweder durch einen Haken oder nur durch einen Test in dieser Methode), ob Sie bei einem POST_MESSAGE-Wert> 300 ein Abzeichen belohnen sollten, zum Beispiel: flag ("300_POST").
Bei der Flag-Methode habe ich den Code eingegeben, um Abzeichen zu belohnen. Wenn beispielsweise das Flag 300_POST gesendet wird, sollte das Badge Reward_Badge ("300_POST") aufgerufen werden.
In der Flag-Methode sollten auch die vorherigen Flags des Benutzers vorhanden sein. Sie können also sagen, wenn der Benutzer FIRST_COMMENT, FIRST_POST, FIRST_READ hat, gewähren Sie ein Abzeichen ("NEW USER"), und wenn Sie 100_COMMENT, 100_POST, 300_READ erhalten, können Sie ein Abzeichen erteilen ("EXPERIENCED_USER").
Alle diese Flaggen und Abzeichen müssen irgendwie gespeichert werden. Verwenden Sie eine Methode, bei der Sie die Flags als Bits betrachten. Wenn Sie möchten, dass dies wirklich effizient gespeichert wird, stellen Sie sich diese als Bits vor und verwenden den folgenden Code: (Oder Sie können einfach eine bloße Zeichenfolge "000000001111000" verwenden, wenn Sie diese Komplexität nicht möchten.
Eine gute Möglichkeit, ein Dokument für den Benutzer zu speichern, besteht darin, json zu verwenden und die Benutzerdaten in einer einzigen Textspalte zu speichern. Verwenden Sie json_encode und json_decode, um die Daten zu speichern / abzurufen.
Fügen Sie zum Verfolgen der Aktivität einiger Benutzerdaten, die von einem anderen Benutzer bearbeitet wurden, eine Datenstruktur zum Element hinzu und verwenden Sie dort auch Zähler. Zum Beispiel Lesezahl. Verwenden Sie für die Vergabe von Abzeichen dieselbe Technik wie oben beschrieben, aber das Update sollte natürlich in den Beitrag des Besitzers aufgenommen werden. (Zum Beispiel Artikel 1000 mal Abzeichen gelesen).
quelle
UserInfuser ist eine Open-Source-Gamification-Plattform, die einen Badging- / Punktedienst implementiert. Sie können die API hier überprüfen: http://code.google.com/p/userinfuser/wiki/API_Documentation
Ich habe es implementiert und versucht, die Anzahl der Funktionen minimal zu halten. Hier ist die API für einen PHP-Client:
Das Endergebnis ist, dass die Daten mithilfe von Widgets auf sinnvolle Weise angezeigt werden. Diese Widgets umfassen: Trophäenetui, Rangliste, Meilensteine, Live-Benachrichtigungen, Rang und Punkte.
Die Implementierung der API finden Sie hier: http://code.google.com/p/userinfuser/source/browse/trunk/serverside/api/api.py
quelle
Erfolge können lästig sein, und dies umso mehr, wenn Sie sie später hinzufügen müssen, es sei denn, Sie haben eine gut ausgebildete
Event
Klasse.Dies führt zu meiner Technik, Erfolge umzusetzen.
Ich mag es, sie zuerst in "Kategorien" aufzuteilen und innerhalb dieser Kategorien von Leistungen zu haben. dh eine
kills
Kategorie in einem Spiel kann eine Auszeichnung von 1 für den ersten Kill, 10 zehn Kills, 1000.000 Kills usw. erhalten.Dann auf den Rücken jeder guten Anwendung, die Klasse, die Ihre Ereignisse behandelt. Stellen Sie sich wieder ein Spiel mit Kills vor; Wenn ein Spieler etwas tötet, passiert etwas. Der Kill wird notiert usw. und dies wird am besten an einem zentralen Ort wie einer
Events
Klasse gehandhabt , die Informationen an andere beteiligte Orte senden kann.Dort passt es perfekt zusammen, dass Sie in der richtigen Methode Ihre
Achievements
Klasse instanziieren und überprüfen, ob dem Spieler eine fällig ist.Beim Aufbau der
Achievements
Klasse ist es trivial, nur etwas, das die Datenbank überprüft, um festzustellen, ob der Spieler so viele Kills hat, wie für den nächsten Erfolg erforderlich sind.Ich mag es, die Erfolge der Benutzer mit Redis in einem BitField zu speichern, aber die gleiche Technik kann in MySQL verwendet werden. Das heißt, Sie können die Erfolge des Spielers als
int
und dannand
als int mit dem Bit speichern, das Sie als diesen Erfolg definiert haben, um zu sehen, ob er sie bereits erreicht hat. Auf diese Weise wird nur eine einzigeint
Spalte in der Datenbank verwendet.Der Nachteil dabei ist, dass Sie sie gut organisiert haben müssen und wahrscheinlich einige Kommentare in Ihrem Code machen müssen, damit Sie sich später daran erinnern, was 2 ^ 14 entspricht. Wenn Ihre Erfolge in einer eigenen Tabelle aufgeführt sind, können Sie einfach 2 ^ pk ausführen, wobei
pk
der Primärschlüssel der Leistungstabelle ist. Das macht den Scheck so etwas wieAuf diese Weise können Sie später Erfolge hinzufügen, und es passt gut zusammen. Ändern Sie NIEMALS den Primärschlüssel der bereits vergebenen Erfolge.
quelle