Thursday, February 19, 2015

Combat And Problems Therein

CombatMover Components
I finally worked my way through a problem that I'd been skirting around.  This had to do with combat, ship statistics, and the links between those two.

Ships exist in the general game structure as Ship objects, which have a Class (which describes size, item loadout, hit points, etc) and a Pattern (describes the actual 3D model used and thus turret and item placement).

Meanwhile, in the combat scene there was an extensive set of prefabs spawned for each combatant.  This was a prefab loaded up at runtime that included the following components:

Component Use
Box ColliderVery tiny, needs to be on root object in order for collision events from colliders on model to bubble up
Rigidbody Sets the physics system mass of the unit
Base Combat MobDerived from BaseCombatObject.  This is pretty much the basic info needed to exist on the board.  BaseCombatMob extends BaseCombatObject, adding thrust/speed/etc. ...Object would be a largely static object
Selectable ObjectHandles clicking or drag selecting of the unit.  Also highlighting on mouseover
Highlightable ObjectFrom 3rd party Highlighting system.  Makes the visual effect work
Orderable Objectllows a unit to receive commands.  Requres BaseCombatMob and SelectableObject.  Without this a unit could do things, but not get external input.  I.e. it could be a mine or a missile or automated turret
Base Combat ExecutiveMain decision maker.  Given a target decides what to do.  Friendly?  Follow and fire on it's target.  Enemy?  Move toward it and attack it, etc.
Area Target Tracker 3rd Party TriggerEventPro item.  Vastly superior replacement for my original target detection code.  Basically detects, sorts and categorizes targets that have...
Targetable 3rd Party TriggerEventPro item. Component lets target trackers know this is (or may be) a valid target for the system
Ignore ModifierTriggerEventPro again.  May hold a list of targets that will be ignored
Base Fire DirectorGets targets from BaseCombatExecutive, or if none chooses available targets.  Direct individual weapon mounts to track individual targets.  Note that I may make a variant of this a Defense Fire Director, that will work only on point defence type weapons and ignore all else

So, that's quite a lot of moving parts. That isn't even counting the code for, say, turrets rotating and tracking their targets.  Or ship movement behavior (to targets, to waypoints, etc.) or local avoidance for ships (i.e. don't run into other ships, or static objects like asteroids etc.)  Oh, and all the visual effects and particle systems for the actual weapons fire.


All of that worked smashingly.  The Combat scene generated all the ships it was told, you could click them and move them around, and they'd target enemies and fire nicely.

However this was really just window dressing.  Sure the turrets tracked the enemy objects and sent out projectiles and laser shots.  But none of it had any actual effect... the actual ship stats were in no way linked with the live objects being spawned (other than ship name, owner and number of ships).

This was where I bogged down for a couple of weeks.  There was a lot needing to be done connecting the dots.  When ships objects were spawned, it needed to look at the linked game-data-ship and get the appropriate info.

The first item I addressed was choosing the right model  I'd just been using a default hard-wired one at first (well, just cubes and capsules at the VERY first).  Now you needed to look up, based on the ship's class and find it's Hull Pattern (for each size of ship, destroyer, heavy cruiser, battleship, etc there may be multiple Hull Patterns, which determine the model and weapon layout.  So two ships might both be battleships, but look and behave slightly differently).  The Hull Pattern has a path to another prefab, this being of the model to load.  The model prefab also includes markers for where weapons and equipment are mounted on the hull.  These can be bones from the 3D modelling program used (i.e. Blender), or empty game objects tacked on later.  I started with the former but have switched to the latter largely.   They both amount to the same, but the latter is easier.

Hull Pattern editor screen.  Ignore the funny gun on the front;
the missile launcher item there simply isn't defined yet.

So now we have the physical model with the orientation and location of item mounts.  Note that orientation is important.  Think of a sea-going battleship.  Some turrets point forward, some aft, some even to the sides.  So like I said, you have to track starting orientation as well as position.

 Now comes a tricky part.  You need to link up SPECIFIC weapons on the ship with SPECIFIC objects on your model. That's to say that specific weapons go on specific turrets, and are limited by the turning arc and speed of that turret.

When a ship class is made (the in-game editor for that isn't done yet, thus far starting ship classes are ginned up by code), each 'module' of equipment the ship gets has a mount point.  I named this 'WeaponMount', but that's a bit of a misnomer as it could be any item, not just a weapon.

The trick to all of this is that in the database (static game data is stored in a in-proc SQLLite database) there's tables HullPattern, WeaponMount and ShipPartResource.  HullPattern is basically just a list of the available HullPatterns, plus stat modifiers, etc.  Oh, and the resource path to load up the model associated with this HullPattern.

WeaponMount entries are keyed to a specific hull pattern.  WeaponMount covers the item's display name, the ModelBoneName (which must match the empty gameObject marking the position on the model), min and max fire arcs, turret turn speed, etc.  It also has a reference to ShipPartResource.

ShipPartResource is basically a name and a resource load path.  It might point to a specific turret, or radar antenna model, etc.

Combat screen. Three on three battle.
So knowing the ship Class you know the HullPattern.  Then you can iterate all the equipment modules on the Class and find the matching WeaponMounts.  Then get the ShipPartResource for that mount and bingo, you can now attach a certain turret model to a certain location of the ship model.  Oh, and then knowing the type of weapon you select a specific visual/audio effects emitter and stick it on the barrel of the turret and link that to the Fire Controller.  The ship's Fire Director component also needs to be informed about every weapon mount created so it can tell it where to target.

There is another component that gets added here, CombatShip.  Basically this is the realtime combat information for the game-data Ship entity. This is where the connection between a specific equipment item in the ship's class and a specific gun turret are made.  Not only physical position, but things like fire rate, accuracy, etc. are calculated here.  For example crew quality affects accuracy.  Weapon quality also affects accuracy, etc.

To it took a lot of work to connect all the dots.  But now ships move around based on their data, and their weapons fire at the correct ranges and rates, doing the correct amount of damage.

It's really pretty to watch.  The movement, weapon effects and sounds are really good so far, I think (note though I have a lot of work in the future on pathing and movement behavior)

Lighting in Unity 5 is very nice.  I'm really liking PBR, even if the texture setup is a bit more work.

No comments:

Post a Comment