Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (480)
Games in Android Showcase (110)
games submitted by our members
Games in WIP (547)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Data driving your games?  (Read 3452 times)
0 Members and 1 Guest are viewing this topic.
Offline appel

JGO Wizard


Medals: 50
Projects: 4


I always win!


« Posted 2010-07-19 16:40:42 »

Do you data drive your games? How?

I've been experimenting with this myself, primarily using Spring beans to make available prototype instances of game objects which can be instanced by simply requesting a instance of "whateverGameObject" on demand.
But I've reached a point where I don't think that's a good way of doing it. Although Spring is powerful, I feel like it's really not supposed to be used in this manner, defining data! Also, it seems to be extremely slow at loading up all the bean definition for an entire RTS game, containing maybe 40-50 XML bean files.

Going to something like Xstream, or maybe a in-memory h2 database, might be something worth exploring. But I wanted to hear how others are doing this before I spend a lot of time on this. Not much data on this topic on the interweb. :\

Currently, data driving my game is driving me mad! (ehe, I just had to add that one Wink)

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #1 - Posted 2010-07-19 17:41:38 »

I pretty heavily data drive my games, I used to use Cas' resource system but now I've got Rebirth which is an evolution of the same core ideas. It's kind of like a mix between a DI framework and an XML->Object loading system, with an emphasis on nice, minimal xml.

Here's a peek inside some of Albion's xml to define a Dark Imp monster:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
   <!-- Tag mappings -->
   <map name="BasicBrain" class="albion.brains.BasicBrainTemplate" />
   <map name="CharacterClass" class="albion.character.CharacterClass" />
   <!-- ... -->
   
   <decoder class="albion.character.Attributes" />
   
   <!-- Items implement and Item interface -->
   <HealthVial name="healthVial.item" itemName="Health vial" image="HealthVial.image" hpGain="100" mpGain="0" />
   <HealthVial name="manaVial.item" itemName="Mana vial" image="ManaVial.image" hpGain="0" mpGain="100" />
   <GoldCoins name="goldCoins.item" image="SmallCoins.image" count="10" />
   <BasicWeapon name="startingSword.item" itemName="Basic sword" image="ShortPlainSword.image"
            type="Bladed"
            attackPower="4"
            modifiers="bell2[-2, -2]"
   />

   <!-- Character classes -->
   <CharacterClass name="warrior.class" className="Warrior" icon0="MeleeAttackCursor.image" icon1="DefendCursor.image"
            defaultAttributes="STR7 DEX6 CON5 INTEL3 WILL4 CHA5"
            equipableWeaponType="Bladed"
            hasMagic="false"
            magicScaleFactor="0.0"
            detectionSkillMultiplier="1.0"
            defaultInventory="startingSword.item, healthVial.item"
            defaultMaleNames="Bowie, Scythe, Vyse, Drachma, Ramirez, Higins, Minsc, Kurth, Bartok "
            defaultFemaleNames="Mazzy, Nalia, Josella, Petra, Rosalind, Miyako, Tifa, Scarlet"
            >
      <description>
         Warriors are skilled melee fighters trained to fight at the front of battle. They are comfortable with any non-ranged weapon and may even fight bare handed.
         As strong physical atheletes, a good warrior will have high strength and dexterity to deal damage and a high constitution in order to withstand it.
         Warriors may later specialise further and become skilled swordsmen, or become inspirational leaders, or focus on raw physical combat.
      </description>
   </CharacterClass>
   
   <!-- BasicBrain implements Brain interface -->
   <BasicBrain name="imp.brain" willFlee="true" hpFleeThreshold="0.25" />

   <!-- Dark imp is a regular imp tinted towards dark blue/green -->
   <AvatarSheet name="darkImp.sheet" sheet="Enemies/Imp.png" face="" tint="rgb(50, 140, 200)" />

   <!-- Spawn template for a dark imp -->
   <CharacterTemplate name="darkImp.character"
                     characterName="Dark Imp"
                     characterClass="warrior.class"
                     attributes="STR1 DEX1 CON8 INTEL1 WILL1 CHA1"   <!-- Custom decoder translates this into an Attributes object -->
                     sheet="darkImp.sheet"
                     brain="imp.brain">
      <dropTable>
         <DropTable>
            <oneOf>
               <drop item="basicWeapon.drop" probability="1" />
               <drop item="manaVial.item" probability="1" />
               <drop item="goldCoins.item" probability="1" />
               <drop item="" probability="2" />
            </oneOf>
         </DropTable>
      </dropTable>
   </CharacterTemplate>


There's very little code on the java side since almost all of that xml is automatically parsed via reflection. The important bits are:

1. Actual objects of the correct sub-type (like BasicBrain, or HealthVial) are created, but in game they're just handled via a Brain or Item interface. That's the DI side of things, and means that I can easily configure a SmartImp by swapping in a new brain without changing any of the code. I assume you're doing something similar to this with Spring.

2. All the top-level objects are named so they can be referenced in other objects. Ie. "warrior.class" is shared between most melee monsters and can be chosen by the player as a character class too.

3. Decoders mean it's dead easy to insert custom syntax into attribute and have them spit out objects (like the strength/dexterity/etc. attributes).

4. Not shown, but you can derive one definition from another. That means I can have superToughDarkImp.character derive from darkImp.character and only redefine it to have higher strength. Everything else gets automatically inherited.

5. The whole thing reloads and reparses automatically, so you can tweek the text/attributes/probabilities and see them reflected instantly in game without a restart. That's really, really handy when you're tweeking tiles and images.

It's really powerful when you get your head around it, as I can define whole new items/characters/behaviours/etc. with just new data, or insert new subtypes just by adding the class and references it in the xml. The core of the game stays entirely unaware of all of the subtypes and only has to deal with a few core interfaces.

Hope that's useful. Smiley

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline princec

JGO Kernel


Medals: 361
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #2 - Posted 2010-07-19 19:11:58 »

Er, what he said Smiley All our games work in exactly the same way. I expect the XML is probably even completely compatible too, but he's got a clever system for dynamically updating things at runtime.

Cas Smiley

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline appel

JGO Wizard


Medals: 50
Projects: 4


I always win!


« Reply #3 - Posted 2010-07-19 19:34:42 »

Hey, thanks.

Seems like a fine system, but doesn't fit my requirements.

It's not general purpose enough. I would need to define classes for the types of units I have in my game. That's not good data-driven approach. In my codebase I only have one GameObject class and then just components. There seems to be a lot of glue-related code in your Rebirth system, and it enforces a certain design upon you. If you wanted to swap from Rebirth to e.g. a H2 database, you'd be in trouble. My system is far from being good, and that's why I'm here, but at least it's very easy to change from e.g. Spring to whatever else (at least there's nothing in there enforcing Spring upon you, I can still compose my gameobjects using a hardcoded factory).

What I am looking for is a way to define a gameobject, the components it uses, and its properties. Here's what I have in Spring XML for one of my gameobjects:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
   <bean id="pegasus" class="com.gamadu.gcom.gocs.GameObject" scope="prototype">
      <property name="objectId" value="PEGASUS" />
      <property name="group" value="units" />
      <property name="radius" value="45" />

      <property name="components">
         <list>
            <bean class="com.gamadu.gcom.gocs.components.bounds.CircleBounds">
               <property name="radius" value="45" />
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.fogofwar.RevealRadius">
               <property name="radius" value="600" />
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.selecting.ImageHighlightSelectable">
               <property name="highlightImage">
                  <bean class="org.newdawn.slick.Image">
                     <constructor-arg index="0" value="races/terrans/pegasus_highlight.png" />
                  </bean>
               </property>
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.exhaust.MultipleExhaust">
               <property name="onlyWhenMoving" value="true" />
               <property name="exhaustEmitters">
                  <list>
                     <bean class="com.gamadu.gcom.gocs.components.exhaust.ExhaustEmitter">
                        <property name="name" value="Thrust" />
                        <property name="offsetX" value="-35" />
                        <property name="offsetY" value="-28" />
                     </bean>
                     <bean class="com.gamadu.gcom.gocs.components.exhaust.ExhaustEmitter">
                        <property name="name" value="Thrust" />
                        <property name="offsetX" value="-35" />
                        <property name="offsetY" value="28" />
                     </bean>
                  </list>
               </property>
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.shield.StandardShield">
               <property name="image">
                  <bean class="org.newdawn.slick.Image">
                     <constructor-arg index="0" value="shields.png" />
                  </bean>
               </property>
               <property name="hitImage">
                  <bean class="org.newdawn.slick.Image">
                     <constructor-arg index="0" value="shieldHit.png" />
                  </bean>
               </property>
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.movement.RealisticShipMovement">
               <property name="mass" value="50" />
               <property name="thrust" value="0.005" />
               <property name="maximumSpeed" value="0.06" />
               <property name="surfaceFriction" value="0.10" />
               <property name="turnFactor" value="0.1" />
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.health.RegenerativeHealth">
               <property name="health" value="4500" />
               <property name="maximumHealth" value="4500" />
               <property name="regenerationIncrement" value="0.055" />
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.highlighting.NameHighlighting">
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.visuals.ImageVisuals">
               <property name="image">
                  <bean class="org.newdawn.slick.Image">
                     <constructor-arg index="0" value="races/terrans/pegasus.png" />
                  </bean>
               </property>
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.collision.TagCollidable" />

            <bean class="com.gamadu.gcom.gocs.components.spawn.DestroyedSpawner">
               <property name="associatePlayer" value="false" />
               <property name="spawnObjectNames" value="unitExplosionLarge,disperseProtomatter,disperseProtomatter,disperseProtomatter,disperseProtomatter" />
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.targeting.TotallyTargetable" />

            <bean class="com.gamadu.gcom.gocs.components.targeting.NearestTargeter">
               <property name="targetingRange" value="700" />
            </bean>

            <bean class="com.gamadu.gcom.gocs.components.weapons.CompositionWeapons">
               <property name="weaponControllers">
                  <util:list>
                     <bean class="com.gamadu.gcom.gocs.components.weapons.IntervalShootingWeaponController">
                        <property name="shootInterval" value="2000" />
                        <property name="weapons">
                           <util:list>
                              <bean class="com.gamadu.gcom.gocs.components.weapons.Shooter">
                                 <property name="offsetX" value="41" />
                                 <property name="offsetY" value="-22" />
                                 <property name="armamentName" value="blastBeam" />
                              </bean>
                              <bean class="com.gamadu.gcom.gocs.components.weapons.Shooter">
                                 <property name="offsetX" value="41" />
                                 <property name="offsetY" value="22" />
                                 <property name="armamentName" value="blastBeam" />
                              </bean>
                           </util:list>
                        </property>
                     </bean>
                  </util:list>
               </property>
            </bean>
         </list>
      </property>
   </bean>


Then I simply request a new bean called "pegasus" from the beanFactory instance. I write all the components so they can be used for DI. There's really no "glue" code.

Although this is flexible, and convenient, and enables me to create rather complex gameobjects, it's really a rape of the IoC concept. Loading time has increased dramatically during development, as I need to load up all the bean definitions when I load the game world, and it takes Spring some time to go through nearly 100 bean definitions in 70+ XML files. We're planning on perhaps 200 types of gameobjects.

Spring is supposed to resolve dependencies in your application, and is very good at that, but it's not supposed to store the data for your application. Clearly I didn't anticipate the project growing so much.



Maybe I will need to design my own system to manage this stuff.  Undecided Doesn't seem to be many other alternatives.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #4 - Posted 2010-07-19 19:51:09 »

It's not general purpose enough. I would need to define classes for the types of units I have in my game. That's not good data-driven approach. In my codebase I only have one GameObject class and then just components. There seems to be a lot of glue-related code in your Rebirth system, and it enforces a certain design upon you.

Not really, you could translate that Spring XML to Rebirth without any major problems. You don't have to define a new class for every type of unit either - in fact Albion doesn't do that either. All creatures (which includes the human controlled players) are just Characters. It's semi-component based (in that the body, character class, brain and several other important bits can be swapped in and out, but it's not a full blown component system. Mostly because I haven't yet felt the need for a full component system.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #5 - Posted 2010-07-19 20:25:19 »

For a laugh, I decided to translate your Spring XML and see how it'd look:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
<map name="GameObject" class="com.gamadu.gcom.gocs.GameObject" />
<map name="CircleBounds" class="com.gamadu.gcom.gocs.components.bounds.CircleBounds" />
<map name="RevealRadius" class="com.gamadu.gcom.gocs.components.fogofwar.RevealRadius" />
<map name="ImageHighlightSelectable" class="com.gamadu.gcom.gocs.components.selecting.ImageHighlightSelectable" />
<map name="MultipleExhaust" class="com.gamadu.gcom.gocs.components.exhaust.MultipleExhaust" />
<map name="ExhaustEmitter" class="com.gamadu.gcom.gocs.components.exhaust.ExhaustEmitter"/>
<map name="StandardSheild" class="com.gamadu.gcom.gocs.components.shield.StandardShield" />
<map name="RealisticShipMovement" class="com.gamadu.gcom.gocs.components.movement.RealisticShipMovement" />
<map name="RegenerativeHealth" class="com.gamadu.gcom.gocs.components.health.RegenerativeHealth" />
<map name="NameHighlighting" class="com.gamadu.gcom.gocs.components.highlighting.NameHighlighting" />
<map name="ImageVisuals" class="com.gamadu.gcom.gocs.components.visuals.ImageVisuals" />
<map name="TagCollidable" class="com.gamadu.gcom.gocs.components.collision.TagCollidable" />
<map name="DestroyedSpawner" class="com.gamadu.gcom.gocs.components.spawn.DestroyedSpawner" />
<map name="TotallyTargetable" class="com.gamadu.gcom.gocs.components.targeting.TotallyTargetable" />
<map name="NearestTargeter" class="com.gamadu.gcom.gocs.components.targeting.NearestTargeter">
<map name="CompositionWeapons" class="com.gamadu.gcom.gocs.components.weapons.CompositionWeapons">
<map name="IntervalShootingWeaponController" class="com.gamadu.gcom.gocs.components.weapons.IntervalShootingWeaponController">
<map name="Shooter" class="com.gamadu.gcom.gocs.components.weapons.Shooter">

<decoder class="SlickImageDecoder" />

<GameObject name="BEGASUS"
         group="units"
         radius="45">
      <components>
         <CircleBounds radius="45" />
         <RevealRadius radius="600" />
         <ImageHighlightSelectable highlightImage="races/terrans/pegasus_highlight.png" />
         
         <MultipleExhaust onlyWhenMoving="true">
            <exhaustEmitters>
               <ExhaustEmitter name="Thrust" offsetX="-35" offsetY="-28" />
               <ExhaustEmitter name="Thrust" offsetX="-35" offsetY="+28" />
            </exhaustEmitters>
         </MultipleExhaust>

         <StandardSheild image="sheilds.png" hitImage="sheildHit.png" />
         
         <RealisticShipMovement mass="50" thrust="0.005" maximumSpeed="0.06" surfaceFriction="0.10" turnFactor="0.1" />
         
         <RegenerativeHealth health="4500" maximumHealth="4500" regenerationIncrement="0.055" />
         
         <NameHighlighting />

         <TagCollidable />
         
         <DestroyedSpawner associatePlayer="false" spawnObjectNames="unitExplosionLarge,disperseProtomatter,disperseProtomatter,disperseProtomatter,disperseProtomatter" />
         
         <TotallyTargetable />
         
         <NearestTargeter targetingRange="700" />
         
         <CompositionWeapons>
            <weaponControllers>
               <IntervalShootingWeaponControllers shootInterval="2000">
                  <weapons>
                     <Shooter offsetX="41" offsetY="-22" armamentName="blastBeam" />
                     <Shooter offsetX="41" offsetY="+22" armamentName="blastBeam" />
                  </Weapons>
               </IntervalShootingWeaponControllers>
            </weaponControllers>
         </CompositionWeapons>
      </components>
</GameObject>


And the Java side:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
public GameObject extends AutoParsable
{
   private String units;
   private int radius;
   private Components[] components;
}

public CircleBounds extends AutoParsable
{
   private int radius;
}

private CompositionWeapons extends AutoParsable
{
   private WeaponControllers[] weaponControllers;
}

private IntervalShootingWeaponControllers extends AutoParsable
{
   private int shootInterval;
   private Weapons[] weapons;
}


Note that's not simplified Java code, that's *all* you need - everything gets parsed into attributes automagically with the correct types. The only extra thing you'd have to do is add a decoder (~5 line class) to decode your Slick images and you're done.

Edit: And to answer the inevitable complaint - you don't *have* to inherit from AutoParsable either, you can implement the Resource interface instead (which just consists of getName() and setName()) if you need to derive from a specific type.

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline appel

JGO Wizard


Medals: 50
Projects: 4


I always win!


« Reply #6 - Posted 2010-07-19 20:56:33 »

Looks interesting. Will digest this..

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Offline sproket

Junior Member


Medals: 1



« Reply #7 - Posted 2010-08-10 23:00:57 »

Persist is a simple no nonsense persistence framework.  http://code.google.com/p/persist/

I use this for my games along with basic XML encoding.

Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

atombrot (23 views)
2014-08-19 09:29:53

Tekkerue (22 views)
2014-08-16 06:45:27

Tekkerue (21 views)
2014-08-16 06:22:17

Tekkerue (12 views)
2014-08-16 06:20:21

Tekkerue (19 views)
2014-08-16 06:12:11

Rayexar (57 views)
2014-08-11 02:49:23

BurntPizza (37 views)
2014-08-09 21:09:32

BurntPizza (29 views)
2014-08-08 02:01:56

Norakomi (36 views)
2014-08-06 19:49:38

BurntPizza (66 views)
2014-08-03 02:57:17
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06

List of Learning Resources
by SilverTiger
2014-07-31 11:54:12

HotSpot Options
by dleskov
2014-07-08 01:59:08
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!