Demox #5 - Destruction
For those of you who’ve either played my previous game or have seen my previous dev logs regarding Demox, it should come as no surprise that there is quite alot of blood in my games- and Demox will be no different. I’ll spend this article on trying to describe some of the methods I’m using for Demox.
.AVATAR DAMAGE MODELS
Starting off with character dismemberment and damage models, I spent alot of time writing the dismemberment system I used for LBKR, which at the time suited my needs however, I didn’t want to use it due to some quite annoying issues- also managing and editing the code was a pure pain. The foremost reasons for discarding this system was
- Dismembered character models ended up with texture anomalies that could be visible when examined closely
- Dismemberment models were generated at runtime and caused a huge load time when a new map was loaded.
- Generated dismemberment models allocated unnecessary amounts of memory.
- Gore fills/models would rarely connect the vertices bordering the character’s mesh, making it possible to see through the character
- Rigging and setup of the character when implemented to the dismemberment system was complicated and quirky.
For Demox, I initially began experimenting with shaders to cut up meshes. I’ve seen this done in other games, and I currently use a similar technique to hide objects obstructing the camera view, but I never got it to work very well for characters, and there was still the issue of rendering the gore-model properly that should replace the dismembered limbs.
I soon began testing to make pre-cut meshes in Blender3D and discovered that there weren’t much performance cost at all, compared to my LBKR system it was as if comparing day and night. It is also an approach that I feel work well enough for the game.
On the downside of using this technique though is that any dismemberment event is final, the character can’t be dismembered any more afterwards. Well… technically it could, but that would require a massive amount of extra meshes and likely some mad code-nesting.
The damage models are very similar to those used in LBKR, each limb of a character is included but in Demox there’s also a damage model for non-dismembered corpses and a mid-slice damage model.
The idea behind the non-dismembered model is that damage done with bare hands or blunt weapons should not tear limbs of a character for obvious reasons, the mid-slice model is basicly the character split in half- it’s used by very specific attacks and weapons.
As mentioned in dev log #4 – Water Behaviour, corpses float in water in Demox. This also required me to add some buoyancy code for the corpses and limbs.
And just as in LBKR, bodies can be fully gibbed ( shred to pieces ) in Demox. In LBKR this happened if the character was killed with a critical hit but for this project I use a value to determine how much additional damage was applied to the character, if it exceed a specified amount the body will be gibbed.
public float gibThreshold = -25f; //Amount of health on death required to gib, set to negative 25 just as example public void OnActivateCorpse( DeathInfo info ) { if( info.finalHealth < gibThreshold ) { FullyGibCorpse(); //Fully dismember the corpse if conditions are met return; } }
.GIBS
The gibs ( dismembered limbs of the character. ) work exactly as they did in LBKR, each damage model has a limb type and character type defined in order for the Corpse component to determine what limb to pull from the object pool.
Most limbs can be picked up in-game and used as weapons though, it was originally just a weird feature I added for fun while prototyping the game but I found this feature to fit really well with the gameplay, also it made the dismembered limbs serve a purpose for the player.
.ENVIRONMENTAL DESTRUCTION
Just as in LBKR I intend to make alot of the environment destructible, and I’m using a similar approach this time aswell. Each destructible object hold a minimum of 1 intact mesh and 1 fully destroyed copy.
When the object is destroyed, the destroyed copy will be activated- which is a collection of the objects gib models.
Some more detailed objects may also hold additional ”partially damaged” models that are enabled when the object has sustained enough damage.
.DECAL PROJECTION IMPLEMENTATION
Another aspect, adding to the havoc, is the use of decals to project blood splatter, or dirt left after an explosion etc. I will once again make a reference to my old project Loot Burn Kill Repeat, I used a similar system for projecting (some) decals in-game however, it was a third-party plugin so I didn’t have that much options to modify it to my needs. It only worked for dynamic decals, furthermore the system was not well optimized and more or less broke Unity’s occlusion culling and could lead to quite extreme frame drops. Another slightly annoying thing about it was the setup of assets. It was rather time-consuming and confusing to create and implement assets for use within the system and to apply settings.
I did like the idea of the plugin and how the decals were projected, instead of simple Quads placed at exact distance from the surface a decal should affect so I was determined to create something similar, but less complicated and more adaptable to my needs.
Goals:
- New shader that projects a texture within a 3D volume
- Enable projections to be animated
- Possibility to use both with dynamic decals pulled from the object pool aswell as decals pre-positioned in the game environment
First of all, I’ve come to understand that this method of projecting decals is quite common in game development, but I weren’t sure how to actually write the shader (I’m still new to writing shaders) but after some searching around in Google-land I did find some reference material on how something like this could be achieved. So once I had created my shader the rest was relatively easy to set up!
A class was created for DynamicDecalProjections that handled animation and default behaviour of the objects, behaviour was also implemented in the object pool for dynamic instantiation of important decals such as blood splatters among other things.
For the dynamic decal projections I wanted, as mentioned earlier, the possibility to animate the projections. Either, dynamic scaling, rotation over lifetime, movement or to shift the texture offset as a 2D sprite sheet.
public void OnManagedUpdate(){ if( !_update ){ return; //Don't update this instance when inactive } if( _parent != null ){ if( !_parent.gameObject.activeInHierarchy ){ StopManagedUpdate(); return; //Stop updating if the current parent is no longer active } //Parent is cached within the class and continuously updates the position //I avoid placing this instance within the parent object's hierarchy in case the parent //object is disabled transform.position = _parent.position; } //Determine how much of the animation has been played float aDist = ( Time.time - _startTime ) * sharedData.animationSpeed; float fraction = aDist / sharedData.animationLength; //Animate the object Vector3 size = Vector3.Lerp( Vector3.zero, new Vector3( _targetSize.x, _targetSize.y, _targetSize.z ), fraction ); if( sharedData.lockYSize ) { size.y = _targetSize.y; //Set fixed size along y-axis, if intended } transform.localScale = size; //Apply current scale if( fraction >= 1f ) { StopManagedUpdate(); //Stop updating, animation playback has finished } }
Above is an example of how I animate the scale of the decal projection while active. Other animations are handled in similar fashion. Since the 3D volume is what is beeing animated (Except in the case of texture sheet animation, which is handled by the objects material.) it is wise to not attach colliders to the volume, since the Unity Engine does not handle scaling colliders very well, or atleast not in the version I’m using, Dunno if it has been improved after Unity5 or not.
I noticed quite fast however, that the textures of the decal volumes were awkwardly stretched on vertical surfaces, this is due to the volume’s uv beeing projected flat and in object space. I initially considered making the shader in a Triplanar fashion however I discovered that the issue was slightly (Not entirely though) reduced when using a sphere volume instead of a cube.
What about implementation and use of these projections then? It’s as easy a a few lines of code which can be seen below.
DecalProjection splat = DecalManager.Current.PullDecal( DynamicDecalNames.Blood_Splatter ); if( splat != null ){ splat.DeployDecal( transform.position + -info.atkDir ); //Deploy splat decal if found }
Demox
Status | On hold |
Author | Crumblin' Cookie |
Genre | Action, Adventure |
Tags | 3D, Fantasy, flat-shading, Top-Down, Unity, Violent |
More posts
- Demox #6: New AI SensorsAug 28, 2021
- Demox #4 - Water BehaviourApr 12, 2021
- Demox #3 - AI IntroductionMar 21, 2021
- Demox #2 - A new worldMar 04, 2021
- Demox #1 - IntroductionFeb 27, 2021
Leave a comment
Log in with itch.io to leave a comment.