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:
<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. :-\ Doesn’t seem to be many other alternatives.