Egy massively multiplayer online stratégiai játék blogja a fejlesztés kezdetétől a játék indulásáig, és túl...

Utolsó kommentek

  • devDavid: Közérdekű közlemény #1 Készítettem egy kisebb adatbázis dump-ot, amivel könnyebb dolgozni (fejles... (2012.12.24. 14:11) Letölthető Zandagort
  • cu2: @devDavid: Lehet, hogy én voltam félreérthető, mert nem vettem rossz néven a(z egyébként jogos) kr... (2012.12.23. 17:42) Letölthető Zandagort
  • devDavid: @cu2: ne érts félre, nem kritizálni akarom, nagyon nagy dolog - szerintem - hogy egy ilyen projekt... (2012.12.23. 17:24) Letölthető Zandagort
  • Utolsó 20

Címkék

It's the economy, stupid

2008.07.29. 15:35 cu2

Szinte minden stratégiai játék alapja a gazdaság. A klasszikus Dune II-féle modell roppant egyszerű: bemegy a spice, kijön a tank.

Bár ez így nagyon primitívnek tűnik, a "valóság" vagyis inkább csak egyes közgazdasági modellek sem sokkal bonyolultabbak. Vannak erőforrások (a fenti példában a spice és a tank) meg gyáraink (tankgyár), és egy nagy mátrix, ami megadja, hogy az egyes gyárak az egyes erőforrásokból mennyit használnak fel vagy állítanak elő egységnyi idő alatt.

TANKGYÁR
SPICE-5
TANK+1

Ennek az egyszerűségnek több előnye is van. Egyrészt könnyű felfogni. Márpedig ha nem kifejezetten gazdaságszimulátorral játszik valaki, nem biztos, hogy el akar merülni akár a számvitel, akár a derivatívák rejtelmeiben.

Másrészt könnyű megvalósítani. A játék PHP+MySQL+AJAX-alapú, maga a gazdaság MySQL-ben készül. Ez elsőre talán furcsának tűnik, de ha azt nézzük, hogy a játékosok nagy számban egymással párhuzamosan kérdezik le és módosítják (építkezéssel, háborúval) a gazdaság állapotát, akkor máris jól jön egy rendes adatbáziskezelő, ami ezeket gond nélkül elintézi. Szemben egy C-ben barkácsolt modullal, ahol ezeket mind le kell programozni a gazdasági magon kívül.

Tehát

A fenti modellből kiindulva három lényeges táblánk van:

  • bolygo_eroforras (bolygo_id, eroforras_id, db): megadja, hogy melyik bolygón melyik erőforrásból hány darab van
  • bolygo_gyar (bolygo_id, gyar_id, db): megadja, hogy melyik bolygón melyik gyár(típus)ból hány darab van (vagyis két tankgyár egy bolygón az egy bejegyzés, ahol db=2)
  • gyar_eroforras (gyar_id, eroforras_id, io): megadja, hogy melyik gyár(típus) melyik erőforrásból mennyit állít elő vagy használ fel (input/output)

Ez alapján roppant egyszerűnek tűnik összedobni egy lekérdezést, ami kiszámolja, hogy melyik bolygón melyik erőforrásból mekkora növekedés vagy csökkenés megy végbe. Csakhogy van egy bökkenő. Ha hiány van egy erőforrásból, mondjuk nincs 5 spice, akkor a tankgyár nem tud termelni, hiszen negatívba egyik erőforrásból sem mehetünk (per pill nincsenek bankok). Oké, akkor várjuk meg, amíg összejön az 5 spice, addig álljon le a gyár. De mi van, ha több gyár is használ egy erőforrást, amiből részleges hiány van? Vagyis van 5 spice-unk, de a tankgyáron kívül egy másik üzem is felhasználna spice-ot. Melyik termeljen? Várjuk meg, amíg mindenki számára elég input összegyűlik, és akkor egyszerre termelhet az összes egy kört?

Először pontosan így volt leprogramozva a dolog. Aztán Arthur bá elküldte a tutit. Ha egy erőforrást több gyár is használ inputnak, akkor osszuk fel köztük olyan arányban, amilyen arányban igénylik. És mindegyik gyár olyan teljesítménnyel üzemeljen, amennyi inputja van a teljes igényéhez képest. Vagyis ha van 4 tankgyár és 2 barakk, amik 3 spice-ból csinálnak egy katonát, akkor a spice 6/26-od része megy a barakkoknak, 20/26-ad része a tankgyáraknak. Így 13 spice esetén 3 spice-ot kapnak a barakkok (és termelnek 1 katonát), 10-et pedig a tankgyárak (és termelnek 2 tankot).

És hogy néz ki ez a gyakorlatban?

  1. Előállítunk egy bolygo_gyar_eroforras táblát, ami bolygónként megadja, hogy melyik gyárból hány van, ezek az egyes erőforrásokból mennyit használnak fel, és milyen arányban osztoznak rajta:
    select bgy.bolygo_id,bgy.gyar_id,gye.eroforras_id,bgy.aktiv_db,gye.io,if(gye.io>=0,0,floor(100*bgy.aktiv_db*gye.io/sumiotabla.sumio)) as reszarany
    from (
    	select bgy.bolygo_id,gye.eroforras_id,sum(bgy.aktiv_db*if(gye.io>=0,0,gye.io)) as sumio
    	from bolygo_gyar bgy,gyar_eroforras gye
    	where bgy.gyar_id=gye.gyar_id
    	group by bgy.bolygo_id,gye.eroforras_id
    ) sumiotabla,bolygo_gyar bgy,gyar_eroforras gye
    where bgy.gyar_id=gye.gyar_id and bgy.bolygo_id=sumiotabla.bolygo_id and gye.eroforras_id=sumiotabla.eroforras_id
  2. A következő a bgy_eff tábla, ami bolygónként megadja a gyárak effektív számát, vagyis hogy hány működik közülük az adott körben (a fenti példában 4 tankgyárból 2 működik):
    select bgye.bolygo_id,bgye.gyar_id,min(if(bgye.io>=0,bgye.aktiv_db,if(bgye.aktiv_db*bgye.io*100+be.db*bgye.reszarany>=0,bgye.aktiv_db,floor(-be.db*bgye.reszarany/100/bgye.io)))) as effektiv_db
    from bolygo_gyar_eroforras bgye,bolygo_eroforras be
    where bgye.bolygo_id=be.bolygo_id and bgye.eroforras_id=be.eroforras_id
    group by bgye.bolygo_id,bgye.gyar_id
  3. Ebből már meghatározható, hogy melyik bolygón melyik erőforrás mennyivel változik (deltatabla):
    select be.bolygo_id,be.eroforras_id,sum(gye.io*bgy_eff.effektiv_db) as delta
    from bgy_eff,bolygo_eroforras be,gyar_eroforras gye
    where be.eroforras_id=gye.eroforras_id and be.bolygo_id=bgy_eff.bolygo_id and bgy_eff.gyar_id=gye.gyar_id
    group by be.bolygo_id,be.eroforras_id
  4. És végül update-eljük a bolygo_eroforras táblát:
    update bolygo_eroforras be,deltatabla
    set be.db=be.db+deltatabla.delta
    where be.bolygo_id=deltatabla.bolygo_id and be.eroforras_id=deltatabla.eroforras_id

Megjegyzés: a bolygo_gyar tábla aktiv_db mezője azt adja meg, hogy hány gyárat működtetünk (ennek akkor lehet szerepe, ha valamiért vissza akarjuk fogni a gazdaságunkat gyárrombolás nélkül). A bolygo_gyar_eroforras táblát ténylegesen is előállítjuk, mert ez csak akkor változik, ha épül vagy lerombolódik egy gyár. A többi hármat viszont össze lehet pakolni egyetlen összetett lekérdezésbe.

És hogy mennyire gyors?

A legkorábbi változat egy E6300 Core 2 Duo-n, 5 erőforrással, 5 gyárral és 10ezer bolygóval 3,4s alatt futott le. MEMORY táblákkal (ezek állandóan a memóriában vannak, így nem kell szarakodni az I/O-műveletekkel, viszont ha kifagy a gép, akkor elveszik a tartalma) ugyanez csak 0,8s. A fenti javított verzió pedig 0,5s.

Mivel a játék várhatóan hónapokig fog tartani, nem kell másodpercenként termelnie a gyáraknak, hiszen úgysem ülnek ott a játékosok folyamatosan, hogy reagáljanak. Ezt majd a tesztfázisban lehet rendesen belőni, de nagyságrendileg az 5-10 percenkénti frissítés jónak tűnik. Ez alapján pedig a fél másodperc futási idő teljesen elfogadható.

Szólj hozzá!

Címkék: sql gazdaság mysql dune2

A bejegyzés trackback címe:

http://zandagort.blog.hu/api/trackback/id/tr78591157

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben.

Nincsenek hozzászólások.