sql >> Database >  >> RDS >> Database

MMO-games en database-ontwerp

Laten we eerlijk zijn:we spelen allemaal graag games, vooral op onze computers. Totdat internet wijdverbreid werd, speelden de meesten van ons alleen computerspellen, meestal tegen AI-tegenstanders. Het was leuk, maar zodra je je realiseerde hoe de gameplay-mechanica werkte, verloor de game het grootste deel van zijn magie.

De ontwikkeling van het internet verplaatste games online. Nu kunnen we tegen menselijke tegenstanders spelen en onze vaardigheden testen tegen die van hen. Nooit meer uit het hoofd spelen!

Toen kwamen er massale multiplayer online (MMO)-spellen op en veranderde alles. Duizenden spelers bevonden zich in dezelfde game-universums, wedijverden om middelen, onderhandelen, handelen en vechten. Om dergelijke spellen mogelijk te maken, was een databasestructuur nodig waarin alle relevante informatie kon worden opgeslagen.

In dit artikel zullen we een model ontwerpen dat de meest voorkomende elementen uit MMO-games bevat. We zullen bespreken hoe het te gebruiken, de beperkingen en de mogelijke verbeteringen.

Een inleiding tot datamodellen voor MMO-games

Er zijn tegenwoordig tal van zeer populaire MMO-spellen en ze omvatten allerlei scenario's. Ik zal me hier concentreren op strategiespellen zoals Ogame , Travian , Sparta :War of Empires en Imperia Online . Deze spellen gaan meer over plannen, bouwen en strategiseren, en minder over directe actie.

MMO-games spelen zich af in verschillende universums, zijn visueel verschillend en gebruiken min of meer verschillende gameplay-opties. Toch zijn sommige ideeën hetzelfde. Spelers strijden om locaties, vechten ervoor en vormen allianties met (en tegen) andere spelers. Ze bouwen structuren, verzamelen middelen en onderzoeken technologieën. Ze bouwen eenheden (zoals krijgers, tanks, handelaren, enz.) en gebruiken deze om te handelen met bondgenoten of om met tegenstanders te vechten. Dat alles moet in onze database worden ondersteund.

We kunnen deze spellen zien als online bordspellen met veel geïndexeerde vierkanten. Aan elk vierkant kunnen veel verschillende acties zijn gekoppeld; sommige acties zullen meerdere vierkanten bevatten - b.v. wanneer we eenheden of middelen van de ene naar de andere locatie verplaatsen.




De database is verdeeld in vijf hoofdgebieden:

  • Players / Users
  • Alliances
  • Locations and Structures
  • Research and Resources
  • Units

De overige zeven niet-gegroepeerde tabellen hebben betrekking op eenheden en beschrijven de positie van eenheden en bewegingen in het spel. We zullen elk van deze gebieden veel gedetailleerder bekijken, te beginnen met Spelers en Allianties .

Spelers en allianties

Zonder twijfel zijn spelers het belangrijkste onderdeel van elk spel.

De player tabel bevat een lijst van alle geregistreerde spelers die deelnemen aan een spelinstantie. We slaan de gebruikersnamen, wachtwoorden en schermnamen van de spelers op. Deze worden opgeslagen in de user_name , password , en nickname respectievelijk attributen.

Nieuwe gebruikers moeten tijdens de registratie een e-mailadres opgeven. Er wordt een bevestigingscode gegenereerd en naar hen verzonden, waarop ze zullen antwoorden. We updaten de confirmation_date attribuut wanneer de gebruiker zijn e-mailadres verifieert. Deze tabel heeft dus drie unieke sleutels:user_name , nickname en email .

Elke keer dat een gebruiker inlogt, wordt een nieuw record toegevoegd in de login_history tafel. Alle attributen in deze tabel spreken voor zich. De logout_time is specifiek. Het kan NULL zijn wanneer de huidige sessie van de gebruiker actief is of wanneer gebruikers het spel afsluiten (zonder uit te loggen) vanwege technische problemen. In de login_data kenmerk, slaan we inloggegevens op, zoals de geografische locatie van een speler, het IP-adres en het apparaat en de browser die ze gebruiken.

De meeste MMO-spellen laten ons samenwerken met andere spelers. Een van de standaard vormen van samenwerking tussen spelers is de alliantie. Spelers delen hun in-game "privégegevens" (online status, plannen, locatie van hun steden en kolonies, enz.) met anderen om te profiteren van geallieerde acties en voor de pure lol ervan.

De alliance tabel bevat basisinformatie over spelallianties. Elk heeft een unieke alliance_name die we zullen opslaan. We hebben ook een veld, date_founded , die opslaat wanneer de alliantie werd opgericht. Als een alliantie wordt ontbonden, slaan we die informatie op in de date_disbanded attribuut.

Het alliance_member tabel relateert spelers met allianties. Spelers kunnen meer dan eens lid worden en dezelfde alliantie verlaten. Hierdoor is de player_idalliance_id paar is geen unieke sleutel. We bewaren informatie over wanneer een speler lid wordt van de alliantie en wanneer (indien) ze vertrekken in de date_from en date_to velden. De membership_type_id attribuut is een verwijzing naar het membership_type woordenboek; het slaat het huidige niveau van spelersrechten in de alliantie op.

De rechten van spelers in een alliantie kunnen in de loop van de tijd veranderen. De membership_actions , membership_type en actions_allowed tabellen definiëren samen alle mogelijke rechten voor alliantieleden. Dit model staat spelers niet toe om hun eigen niveaus van rechten in een alliantie te definiëren, maar dat zou gemakkelijk genoeg kunnen worden bereikt door nieuwe records toe te voegen in het membership_type woordenboek en het opslaan van informatie over aan welke allianties ze gerelateerd zijn.

Samenvattend:de waarden die in deze tabellen zijn opgeslagen, worden door ons gedefinieerd tijdens de eerste configuratie; ze veranderen alleen als we nieuwe opties introduceren.

De membership_history table slaat alle gegevens op met betrekking tot de rollen of rechten van spelers binnen een alliantie, inclusief het bereik wanneer deze rechten geldig waren. (Hij kan bijvoorbeeld een maand "beginners"-rechten hebben en vanaf dat moment "volledig lidmaatschap".) De date_to attribuut is NULLable omdat de huidige actieve rechten nog niet zijn beëindigd.

De membership_actions woordenboek bevat een lijst van alle acties die spelers in een alliantie kunnen ondernemen. Elke actie heeft zijn eigen action_name en spellogica is rond deze namen gebouwd. We kunnen waarden verwachten zoals “bekijk ledenlijst” , “bekijk de status van leden” en “bericht verzenden” hier.

Het membership_type woordenboek bevat de unieke namen van de actiegroepen die in het spel worden gebruikt. De actions_allowed tabel wijst acties toe aan lidmaatschapstypen. Elke actie kan slechts één keer aan een type worden toegewezen. Daarom is de membership_action - membership_type paar vormt de unieke sleutel voor deze tafel.

Locaties en structuren

Spellocaties zijn gebieden waar spelers middelen verzamelen en structuren en eenheden bouwen. Sommige games hebben een vooraf gedefinieerd bereik van mogelijke locaties, terwijl andere gebruikers hun eigen locaties kunnen definiëren.

In een 3D-ruimte kunnen locaties worden gedefinieerd met [x:y:z]-coördinaten. Als een game een vooraf gedefinieerd bereik heeft, is het mogelijk dat spelers geen locatie buiten het bereik [0:1000] voor alle drie de assen mogen gebruiken, dus we zijn beperkt tot een 1000 * 1000 * 1000 ruimte.

Aan de andere kant willen we misschien spelers toestaan ​​om de exacte coördinaten van hun nieuwe locatie in te voeren - b.v. [1001:2073:4] – en we willen dat de game het voor hen verwerkt.

We houden een lijst bij van alle locaties die worden gebruikt in een instantie van onze game op de location tafel. Elke locatie heeft zijn eigen naam, maar de namen zijn niet uniek. Aan de andere kant, de coordinates attribuut mag alleen unieke waarden bevatten. Locatiecoördinaten worden opgeslagen als tekstwaarden, dus we kunnen coördinaten voor 3D-games opslaan als [112:72:235]. Coördinaten voor 2D-spellen kunnen worden opgeslagen als <1102:98>.

In sommige spellen hebben locaties een aantal vierkanten die worden gebruikt om gebouwen of eenheden te huisvesten. We houden die informatie in de dimension attribuut, dat een tekstveld is. Een dimensie kan eenvoudig een aantal vierkanten in een 2D- of 3D-raster zijn. De player_id attribuut slaat informatie op over de huidige eigenaar van die locatie. Het kan NULL zijn wanneer locaties vooraf zijn gedefinieerd en spelers strijden om ze te bezetten.

De structure tabel bevat een lijst van alle structuren die we op verschillende spellocaties kunnen bouwen. Structuren vertegenwoordigen verbeteringen die ons in staat stellen betere eenheden te produceren, nieuwe soorten onderzoek uit te voeren, meer middelen te produceren, enz. Elke structuur die in het spel wordt gebruikt, heeft zijn eigen unieke structure_name . Enkele mogelijke structure_name waarden zijn "boerderij", "ertsmijn", "zonne-installatie" en "onderzoekscentrum".

We kunnen verwachten dat elke structuur meerdere keren wordt geüpgraded, dus we slaan ook informatie op over het huidige niveau. Elke upgrade verbetert de output van structuren, dus het produceert meer middelen of stelt ons in staat om nieuwe functies in het spel te gebruiken. We kunnen het maximale upgradeniveau niet van tevoren weten, dus we zullen alle niveaugerelateerde zaken (kosten, upgradetijd en productie) met formules definiëren. Alle formules die in de database zijn opgeslagen, vormen de kern van de spelmechanica en hun aanpassing is cruciaal voor de spelbalans en de gameplay in het algemeen.

Dat is ook het geval met de upgrade_time_formula attribuut. Een voorbeeldwaarde voor dit veld is * 30 min” , waar staat voor het niveau waarnaar we willen upgraden.

In de meeste gevallen zijn er vereisten waaraan moet worden voldaan voordat spelers bepaalde acties ondernemen. Misschien moeten we een bepaalde hoeveelheid onderzoek voltooien voordat we nieuwe structuren kunnen bouwen of omgekeerd. We slaan het onderzoeksniveau dat nodig is om structuren te bouwen op in de prerequisite_research tafel. Relaties en het structuurniveau dat nodig is om verschillende onderzoeken te starten, worden bijgehouden in de prerequisite_structure tafel. In beide tabellen zijn de refererende sleutels research_id en structure_id zijn gekoppeld om een ​​unieke sleutel te vormen. De level_required attribuut is de enige waarde.

Deze twee tabellen, prerequisite_research en prerequisite_structure , vormen ook de kern van het spel.

Voor elke structuur zullen we een lijst met vereisten definiëren:andere structuren en hun minimumniveaus die spelers moeten hebben om te beginnen met bouwen. We slaan deze gegevens op in de structure_required tafel. Hier, structure_id vertegenwoordigt de structuur die we willen bouwen; structure_required_id is een verwijzing naar de vereiste structuur(en), en level is het vereiste niveau.

De structure_built tabel slaat informatie op over de huidige structuurniveaus op een bepaalde locatie. De upgrade_ongoing kenmerk wordt alleen ingesteld als er momenteel een upgrade gaande is, terwijl de upgrade_end_time attribuut zal een tijdstempel bevatten zodra de upgrade is voltooid.

De structure_formula tabel heeft betrekking op structuren en middelen. Het externe sleutelpaar van deze tabel vormt zijn unieke sleutel. Deze tabel heeft ook twee tekstattributen met formules met als parameter. We zullen deze formules definiëren, een voor kosten en de andere voor het genereren van middelen, in de database. Ze zullen vergelijkbaar zijn met de upgrade_time_formula . We hebben ze nodig omdat we de middelen moeten definiëren die worden besteed aan het bouwen van elke structuur. We moeten ook de productie van hulpbronnen definiëren na de upgrade, als de structuur enige hulpbronnen genereert (d.w.z. ertsmijn zal * 20 produceren erts per dag).

Onderzoek en bronnen

Onderzoek (of technologieën) in games zijn meestal vereist voor het creëren van andere functies. Zonder bepaalde niveaus van onderzoek kunnen er geen nieuwe structuren of eenheidstypes worden gebouwd. Onderzoek kan ook zijn eigen vereisten hebben. Een van de meest voorkomende is het niveau van een bepaalde structuur, meestal een "onderzoekslab" genoemd. Of misschien moeten spelers een bepaald niveau van onderzoek voltooien voordat ze nieuw onderzoek kunnen starten. Al deze vereisten worden in deze sectie behandeld. Hieronder kunnen we het datamodel voor Onderzoek en Middelen vinden:

Het research tabel bevat een lijst van alle mogelijke onderzoeksacties in ons spel. Het gebruikt dezelfde logica als de structure tafel. De research_name attribuut is de unieke sleutel van de tabel, terwijl de upgrade_time_formula veld bevat een tekstweergave van de formule voor onderzoekstijdvereisten, met als parameter. Alle resources die nodig zijn voor upgrades worden gedefinieerd in de upgrade_formula opgeslagen in de research_formula tafel.

Net als bij structuren, zullen we de lijst met alle andere onderzoeken en hun niveaus definiëren die moeten worden voltooid voordat we een ander type onderzoek kunnen starten. We slaan deze gegevens op in de research_required tabel, waar research_id staat voor het gewenste onderzoek; research_required_id is een verwijzing naar het vooronderzoek, en level is het vereiste niveau.

Onderzoek is gerelateerd aan individuele spelers, en voor elke speler – onderzoek ch-paar moeten we het huidige onderzoeksniveau van een speler en eventuele lopende upgradestatussen opslaan. We slaan deze informatie op met behulp van het research_level tabel op dezelfde manier waarop we de structure_built tafel.

Hulpbronnen zoals hout, erts, edelstenen en energie worden gewonnen of verzameld en later gebruikt om structuren en andere verbeteringen te bouwen. We slaan een lijst op met alle bronnen in de game in de resource woordenboek. Het enige kenmerk hier is de resource_name veld, en het is ook de unieke sleutel van de tabel.

Om de huidige hoeveelheid bronnen op elke locatie bij te houden, gebruiken we de resources_on_location tafel. Nogmaals, een buitenlands sleutelpaar (resource_id en location_id ) vormt de unieke sleutel van de tabel, terwijl het number attribuut slaat de huidige resourcewaarden op.

Eenheden en bewegingen

Middelen worden gebruikt om eenheden te produceren. Eenheden kunnen worden gebruikt om grondstoffen te vervoeren, andere spelers aan te vallen of in het algemeen te plunderen en te verbranden.

De lijst met eenheidstypes die in onze game worden gebruikt, is opgeslagen in de unit woordenboek met slechts één waarde, unit_name; dat attribuut is de unieke sleutel van deze tabel. Enkele veelvoorkomende speleenheden zijn "zwaardvechter", "gevechtskruiser", "griffin", "straaljager", "tank", enz.

We moeten elke eenheid beschrijven met specifieke kenmerken. Een lijst met alle mogelijke kenmerken wordt opgeslagen in de characteristic woordenboek. De characteristic_name veld een unieke waarde bevat. Waarden in dit veld kunnen zijn:"aanval", "verdediging" en "hitpunten". We zullen kenmerken toewijzen aan eenheden met behulp van de unit_characteristic relatie. Het externe sleutelpaar van unit_id en characteristic_id vormen de unieke sleutel van de tafel. We zullen slechts één attribuut gebruiken, value , om de gewenste waarde op te slaan.

De research_unit tabel bevat een lijst van alle onderzoeksactiviteiten die moeten worden afgerond voordat we kunnen beginnen met de productie van een bepaald type eenheid. De unit_cost tabel definieert de middelen die nodig zijn om een ​​enkele eenheid te produceren. Beide tabellen hebben unieke sleutels die zijn samengesteld uit het externe sleutelpaar (research_id of resources_id gecombineerd met unit_id ) en één waardeveld (cost en level_required ).

En nu het leuke gedeelte. Productie is leuk, maar eenheden verplaatsen en actie ondernemen is nog beter. We hebben de unit tabel, maar we houden het hier omdat het verband houdt met andere tabellen.

Ofwel eenheden zijn gestationeerd op een locatie of ze verplaatsen zich tussen locaties. Het toevoegen van de player_id veld bepaalt wie de eigenaar is van de locatie of de groep die zich tussen de locaties verplaatst.

Als eenheden net op de opgegeven locatie zijn gestationeerd, slaan we die locatie op en het aantal eenheden dat daar is gestationeerd. Hiervoor gebruiken we de units_on_location tafel.

Als eenheden niet gestationeerd zijn, verplaatsen ze zich. We moeten hun vertrekpunt en hun bestemming opslaan. Daarnaast moeten we mogelijke acties tijdens bewegingen definiëren. Al dergelijke acties worden opgeslagen in de movement_type woordenboek. De type_name kenmerk is uniek terwijl de allows_wait attribuut bepaalt of een actie wachten op het bestemmingspunt toestaat.

We kunnen een enkel type eenheid verplaatsen, maar in bijna alle gevallen zullen we veel eenheden van verschillende typen eenheden verplaatsen. Die groep deelt gemeenschappelijke gegevens en we slaan ze op in de group_movement tafel. In deze tabel definiëren we de volgende items:

  • de speler die die actie heeft gestart
  • het actietype
  • het startpunt
  • het bestemmingspunt
  • de arrival_time op de bestemming
  • de return_time naar het startpunt
  • de wait_time op de bestemming

De return_time attribuut kan NULL zijn als dit een enkele reis is, en wait_time wordt bepaald door de speler. Eenheden die tot een groep behoren, worden gedefinieerd door waarden die zijn opgeslagen in de units_in_group tafel. Het externe sleutelpaar van units_id en group_moving_id vormt de unieke sleutel van de tafel. Het aantal eenheden van hetzelfde type binnen een groep wordt gedefinieerd in het number attribuut.

Elke beweging kan middelen van de ene locatie naar de andere transporteren. Daarom definiëren we een veel-op-veel-relatie tussen de group_movement en de resources tafels. Naast de primaire en externe sleutels, is de resources_in_group tabel bevat alleen het number attribuut. In dit veld wordt de hoeveelheid middelen opgeslagen die spelers van het startpunt naar hun bestemming verplaatsen.

In de meeste gevallen kunnen spelers anderen bellen om mee te doen aan hun avontuur. Om dat te ondersteunen gebruiken we twee tabellen:allied_movement en allied_groups . Eén speler zal een gezamenlijke actie ondernemen en dat zal een nieuw record creëren in de allied_movement tafel. Alle groepen eenheden die deelnemen aan een geallieerde actie worden gedefinieerd door waarden die zijn opgeslagen in de allied_groups tafel. Elke groep kan slechts één keer aan een geallieerde actie worden toegewezen, dus buitenlandse sleutels vormen de unieke sleutel van deze tabel.

Dit model geeft ons de basisstructuur die nodig is om een ​​MMO-strategiespel te bouwen. Het bevat de belangrijkste spelfuncties:locaties, structuren, middelen, onderzoek en eenheden. Het brengt ze ook met elkaar in verband, laat ons vereisten definiëren in de database en slaat ook de meeste spellogica op in de database.

Nadat deze tabellen zijn gevuld, is de meeste spellogica gedefinieerd en verwachten we niet dat er nieuwe waarden worden toegevoegd. Bijna elke tabel heeft een unieke sleutelwaarde, ofwel een functienaam of een extern sleutelpaar. Door de kenmerken van eenheden en productie-/kostenformules te wijzigen, kunnen we de spelbalans in de databaselaag wijzigen.

Hoe zou je dit model veranderen? Wat vind je leuk en wat zou je anders doen? Vertel het ons in het commentaargedeelte!


  1. NoClassDefFoundError krijgen tijdens het gebruik van Proguard en SQLcipher in Android

  2. Altijd een database nodig voor je app?

  3. Hoe meerdere kolommen zoeken in MySQL?

  4. Geavanceerde partitie-matching voor partitiegewijze join