• Register

Demox is to be an action-adventure game in which the player will take on the role of a small demon, forced to destroy the human realm but after several years of fighting finally had enough of it and need to put his best efforts into finding a way back to his beloved underworld.

His demon masters does not take kindly to his actions though, and pits his former allies against him.

  • View media
  • View media
  • View media
  • View media
  • View media
  • View media
Post article RSS Articles

My previous projects have contained water however, I’ve never put any effort into making it behave like water would. In LBKR for instance the water was purely a decoration, it would not react to objects colliding with it’s surface nor would said objects be manipulated by the water in any way- this made it feel very artificial and, in lack of a better word, un-watery… ( Please excuse my word-slaughtering, keep in mind that english is not my native language ;P )

.WATER INTERACTION

For Demox I aim to make the water less of an illusion, and have it actually react to collisions and affect objects that enter the ”water volume”. This actually involves multiple object behaviours considering the code, and a whole lot of different particle effects among other things.

.VOLUME COLLISION BEHAVIOUR

So what did I actually want to happend when something collides with the water? That depends on what type of object actually hit the water of course, but let’s have a look at the goals I had set in mind.

  • Corpses, limbs and some types of objects / items should float when in a water volume.
  • Character’s should have reduced movement speed when moving through water, to simulate a sort of resistance / drag. The speed reduction should depend on the depth of the current position.
  • Projectiles hitting the water should use water-impact effects instead of their default hit effect.
  • Everything that enter the volume should visualize it by playing ripple or splash effects.
  • Water should react to elemental damage effects, ie. extinguish fire, and become electrified by electricity attacks.

Starting with the water volume itself, there were some important properties to keep in mind. For starters, the depth of the volume which is required to determine what ripple effect to use, small water puddles would for obvious reasons create smaller splashes than if an object fell into a large pond or river. I simply set this property to be the height of the water volumes bounds, and then adjust the volume size in the editor to fit the terrain or water container.
The next property required is the world position along the y-axis that the volume’s surface is located at, this is required when calculating the depth of the volume at a specific location. (Which is done to determine current speed penalty for avatars moving in the volume.)

Water impact effect, played when a body hits the water volume.


float vDepth;    //Depth of the current water volume
float vSurfacePoint; //World position along y-axis of the current water volume's surface
float speedPenalty;  //The velocity reduction of this instance
Transform vSurface;  //Current water volume

//Water volumes are identified through the OnTriggerEnter method
public void OnTriggerEnter( Collider other ) {
    if( target.IsDead || _update || !other.CompareTag( Tags.SurfaceWater )) {
        return;
    }

    vSurface = other.transform;   //Assign colliding volume as current water volume
    target.InWater = true;        //Flag target avatar as inside a water volume

    //Determine if the current water surface is deep enough to swim/drown in
    vDepth = MapMaster.Current.FindWaterVolume( vSurface).VolumeDepth;
    if( vDepth >= SharedGlobalProps.SwimDepth ) {
        ControlledFx splash = GameObjectPool.Current.PullCommonFx(     CommonFxNames.W_Impact_Avatar );    //Pull a water-splash effect from the ObjectPool

        if( splash != null ) {    //Play the water splash effect if found
            splash.FireFxCheap( transform.position );
        }
    }

    StartManagedUpdate();         //Starts a custom Update-method
    target.RefreshMoveSpeed();    //Refresh move speed of the avatar
}

//Only viewing a fraction of the OnManagedUpdate method since alot of it's content is irrelevant for this post
public void OnManagedUpdate() {
    ....
    if( Time.time - _lastDepth >= _DepthThreshold ) {
        CalculateWaterDrag();    //Update the depth drag applied to the avatar at regular intervals ( ie. move speed penalty )
        _lastDepth = Time.time;
    }

    if( vDepth >= SharedGlobalProperties.SwimDepth && !target.CanSwim ) {
        if( _curFx == null ) {
            RetrieveFx();    //Pull an appropriate FX from the Object Pool
            return;
        }

        //Play the FX at the avatars position, but lock y-axis position to the surface point
        Vector3 pos = new Vector3( transform.position.x, vSurfacePoint, transform.position.z );
        _curFx.transform.SetPositionAndRotation( pos, transform.rotation );

        if( !_drowning ) {
            _drowning = true;
            _lastDrowned = Time.time;
        }

        target.OnDrown();
        return;
    }
    ....
}

public void CalculateWaterDrag() {
    //Determine how far beneath the surface the avatar currently is located
    Vector3 xzSurf = new Vector3( transform.position.x, vSurfacePoint, transform.position.z );
    float avDist = Vector3.Distance( transform.position, xzSurf );
    
    //Assign current drag / speed penalty
    speedPenalty = ( avDist / vDepth ) * _DepthDragMultiplier;
}

As you can see I simply determine the penalty by calculating how far along the way to the bottom of the volume the avatar has reached. Since this return a value in the range from 0 to 1 I also multiply it by a constant value ”DepthDragMultiplier”, in order to get a value suitable for actual speed reduction.

As can be seen in the code, the depth will also determine what type of water ripple effects to play while the avatar is moving around. This also ensures that the correct effect is played if the terrain under the water is sloped and the character is moving from deep to shallow waters or vice verca.

///<summary>
/// Retrieves a water-ripple FX from the object pool and starts playback
///</summary>
private void RetrieveFx(){
    ControlledFx fx = null;

    //Select appropriate particle system
    if( vDepth < _SmallRipplesDepth ){
        //Play a smaller style of ripple effect
        fx = GameObjectPool.Current.PullCommonFx( CommonFxNames.W_PuddleRipples );
    }
    else if( vDepth < SharedGlobalProperties.SwimDepth ){
        //Play common water ripples effect
        fx = GameObjectPool.Current.PullCommonFx( CommonFxNames.W_Ripples );
    }
    else{
        if( target.CanSwim ){
            //Play ripples effect of type "SwimRipples"
            fx = GameObjectPool.Current.PullCommonFx( CommonFxNames.W_SwimRipples );
        }
        else{
            //Play ripple effect of type "DrownRipples"
            fx = GameObjectPool.Current.PullCommonFx( CommonFxNames.W_DrownRipples );
        }
    }

    if( fx == null ){
        Debug.LogWarning("WaterTracker could not retrieve a VFX");
        StopManagedUpdate();
        return;
    }

    _curFx = fx;            //Cache the located effect
    _curFx.FireFxCheap();   //Play the located effect
}

Water ripple effects in action


For ripple and water trail effects there are constant depth values as limits of when to select each type of effect, and each effect has three base variations. There are more variations aswell but for other purposes, such as larger objects or projectiles hitting the surface etc.

Common Water Ripple effect


What impact / splash effect to use when a collision with the surface occur is determined within the water volume’s code, unlike the ripple effects as described above. It’s a really simple setup of checking the tag of the object hitting the surface, for now this works nice since most objects with the same tag are of similar sizes (ie. characters, items, etc). I already know now that some monsters will be alot larger than average though so in the near future I’ll need to adjust this to scale the splash effect to look good if the large monsters fall in the water aswell.

Dead body and limb floating in water


. BUOYANCY

One of the most important things in my own opinion are that bodies and some objects should float in water, as they do in reality. I don’t think I’ll go into detail of exactly how this is done since I’m quite certain there are a whole lot of information to gather on the subject out there in Google-land, but to cover some basics- everything that floats will require multiple properties to determine their behaviour in water.

First, the buoyancy of the object, how well does it float in water?
Each object also required values to limit their movement in the water volume, my first iteration of the floating behaviour had the objects jump out of the water over and over again, as if displaying their acrobatic grace- to adress this issue I added two limiters / thresholds. ”Float Pivot”, and ”Surface Range”, the float pivot is a Vector3 that describes a point relative to the object’s position that symbolizes the most buoyant part, eg. objects that contain air compartments tend to be most buoyant in the compartment where the air is located. The surface range will be used to compare how much beneath or above the surface the object is and adapt force applied in an appropriate manner.

I also added a property of ”water drag”, this property is modified by the current submergence of the object and the end product will be used to manipulate the power of the force or gravity applied to the Rigidbody of the object, objects in water usually have alot more velocity if floating up from the bottom but when at the surface the velocity is no longer as agressive- this was the behaviour that I intended to simulate with the help of this property.

Additionally, a reference to the water volume affecting the object was also required since the depth at the object’s position is compared alot.

.MOVING WATER

While creating effects for the water system, one of the assets created was a waterfall- it looked really stupid though to have a waterfall but when looking at the source, or volume from which the water came from there was no movement. For obvious reasons I decided to create some assets for moving water. This could be achieved by writing a shader to handle I guess, but for example, rivers or streams can often bend and turn alot, and I don’t know how to make a really adaptable shader for this so I decided to try using particle systems for the moving water instead. I’ve only created a prototype effect this far but I like the result, with some more experimenting it could turn out quite nice I believe.

Bodies and objects beeing swept away by a river, using ‘Constant Force‘-triggers


The particles are rendered as simple 3D meshes instead of 2D billboards, and currently use Unity’s refractive water material. As I liked the style of this effect I modified all other water effects to use a similar technique.

But back on track, the moving water presented an obstacle that I hadn’t thought of, objects floating in the water volume would not follow the water flow, but instead just float near the same position. This was easily fixed though by creating triggers that apply constant force to objects within it’s bounds if those objects are in a floating state, and then positioning those triggers along the water’s path.

Example of the ConstantForce script can be seen below:

public Vector3 forceDir; //Direction of the force, relative to this object's rotation
public float force; //Power of the force applied
private List< Rigidbody > _bodies; //List to hold all updated rigidbodies

public void OnTriggerExit( Collider other ) {
     if( (other.CompareTag( Tags.Corpse ) || other.CompareTag( Tags.Item )) && _bodies.Contains( other.attachedRigidbody )) {
         //Remove the target from the list of updated bodies
         _bodies.Remove( other.attachedRigidbody );
     }
 }
public void OnTriggerEnter( Collider other ) {
     if( (other.CompareTag( Tags.Corpse ) || other.CompareTag( Tags.Item )) && !_bodies.Contains( other.attachedRigidbody )) {
         //Add the target to the list of updated bodies if it has correct object tag
         _bodies.Add( other.attachedRigidbody );
     }
 }
public void FixedUpdate() {
    if( _bodies.Count == 0 ) {
         return;
     }
     for( int i = 0; i < _bodies.Count; i++ ) {
         if( _bodies[i ]!= null ) {
             _bodies[ i ].AddForce( transform.TransformDirection( forceDir ) * force, ForceMode.Force );
         }
     }
 } 

(Pictures above are the final result of water volumes after a custom shader was written for water surfaces)


.SWIMMING

Among the final touches for the water interactions I made it possible for characters to swim in deep water, I were able to make use of alot of the code I had already written for the other aspects concerning water interaction behaviour, only some minor adjustments and tweaks had to be made to implement it for the character classes. I did consider some possible obstacles before putting it all together though.

  • How to determine when a character is swimming and when simply walking in shallow water? Water volumes will rarely have flat bottoms so depth will differ within the same volume.
  • How to stop the player from swimming out of the map in cases where the map borders consist of ocean?
  • How to get the player out of the water if no ramp or beach is within the volume’s bounds?

The first obstacle was easy (actually, all obstacles were easy to solve…) to sort out by using a similar technique to what I did for retrieving FX as included in a code snippet earlier in this post.

float submergence = vSurfacePoint - transform.position.y;  //Determine how deep beneath surface avatar is
if( submergence >= SharedGlobalProperties.SwimDepth ) {}   //Do some stuff

If the avatar is a defined distance beneath the surface I can thereby either flag the avatar as swimming, or if not able to swim have the avatar drown from within the if() block.

To stop the player from swimming into infinity, or reaching areas far away that were not intended to reach I added a stamina vital to the player character’s statistics. While swimming the stamina will drain and when out of stamina the avatar will drown. This obviously help when limiting the player’s swim range.

Since the avatar is not allowed to jump when swimming, it was critical to find a way to leave water volumes if there were no ramps or shallow water within the volume that would allow the avatar to start walking on the bottom of the water volume.
I’m making use of the code for mounting obstacles while not in water, by casting a ray in front of the player I can detect if there are any climbable geometry, and if so allow the player to mount said geometry and leave the volume by climbing.

Swimming behaviour in-game


An obstacle I had not anticipated were with floating platforms, as the player jumped or climbed on them they would not make any motion at all, this made it look like they were actually static objects just positioned above a water volume. I weren’t satisfied with this.

I made a quite simple work-around for this issue by attaching a trigger volume to the floating platform objects, when the trigger is activated by player motion a force impulse will be sent to the rigidbody component of the floating platform, making it move.

By the way, since I'm also posting these logs to describe to other developers who read my website or twitter you might've noticed that I add alot of nonsense and code-excerpts about the game, and perhaps geeking a bit too much about how certain aspects have been developed and designed. Is this appreciated by you as a reader or should I strip this content and stick to less developer-geeky information about my progress? Let me know what you think by dropping a comment! :)

And to end this lengthy article, feel free to follow me on Twitter @CrumblinGames, if you feel that the time between my updates here on IndieDB are too long I do post more images, videos and smaller info regarding the development on Twitter!

Demox #3 - AI Introduction

Demox #3 - AI Introduction

News

Welcome back for another Demox log entry!This time I’m going to talk some more about the AI for the game and what I aim to achieve- or atleast what...

Demox #2 - A new world

Demox #2 - A new world

News

Hello again, today I will go through some of the ideas regarding the game world, and some of the game content, both planned features and ideas and already...

Demox - Reintroduction Post-prototype

Demox - Reintroduction Post-prototype

News

It’s been very quiet recently regarding my new project, (sorry about that!) but I’ve had so many other projects (non-computer-related) going on this...

New Project: Demonic Quarrel

New Project: Demonic Quarrel

News

It's been a while since I released the final update for LBKR, and since then I've kept myself busy with my new project.

Comments
NicksonV
NicksonV

I saw one of your devlogs and loved the visuals! Can't wait to see more!

Reply Good karma Bad karma+2 votes
Kakburk Creator
Kakburk

Thanks! And thank you for the follow! :)

Reply Good karma+1 vote
booman
booman

A new game??? Awesome! I was hoping you would create something fresh and new.
Keep up the hard work... following now!
Are you planning to release a Linux version just like Loot Burn Kill Repeat?

Reply Good karma Bad karma+2 votes
Kakburk Creator
Kakburk

Hello again! Thanks for the follow, and it's nice to see you lurking around my pages again ;)
Considering how, more or less, effortless it was to build a Linux version I see no reason not to. ( So yes, there'll be a Linux version ^__^)

Reply Good karma+2 votes
booman
booman

I was just surprised to find your new game... I just stumbled on it. You may want to advertise it on your Loot Burn Kill Repeat page. You will gain more watchers.

I'll post it on Reddit as well.
I love your development style and sci-fi/horror based games.
Keep up the amazing work!

Reply Good karma Bad karma+2 votes
Kakburk Creator
Kakburk

I know '._. Marketing my projects is sort of my achilles heel, I'm having a hard time finding time to advertise- but I try to do it as often as possible But needless to say, there's a whole lot of room for improvements xD

Thanks! And thanks for helping me out! :)

Reply Good karma+2 votes
booman
booman

No problem as always. I love RPGs and top-down action games... horror themes are always welcome as well!

Keep developing and let me know if you need a tester for your Linux ports.

Reply Good karma Bad karma+2 votes
Post a comment
Sign in or join with:

Only registered members can share their thoughts. So come on! Join the community today (totally free - or sign in with your social account on the right) and join in the conversation.

Follow Profile
Icon
Demox
Platforms
Windows, Linux
Creator
Kakburk
Engine
Unity
Contact
Send Message
Release date
Game watch
Follow
Share
Style
Genre
Adventure
Theme
Fantasy
Players
Single Player
Project
Indie
Twitter

Latest tweets from @crumblingames

Kept workin on #ai smell detection. Red circles=avatar's scent (trail) beeing registered, colored rects = environme… T.co

1hour ago

Updated my clip shader to smooth the transition over time instead of having the vertices be instantly clipped when… T.co

Apr 14 2021

Added an animation for the new monster to play when it detects an enemy #indiegamedev #indiegames #indiegameT.co

Apr 13 2021

Mr.Frog has entered the game! #indiegamedev #indiedev #indiegame #indiegames #gamedev #blender3D #b3d #unity3dT.co

Apr 12 2021

Creating a character without eyes, so needed to create new AI sensors for detecting enemies by sound and smell. Lef… T.co

Apr 11 2021

Solotility #5 Lootburnkillrepeat.wordpress.com

Apr 9 2021

New Dev. Log posted for Demox concerning water interactions, visuals and behaviour! #indiegamedev #indiegameT.co

Apr 8 2021

Created a wolf for Demox! Little Red Riding Hood appear to have some trouble with her spine though. #indiegamedevT.co

Apr 7 2021

Embed Buttons
Link to Demox by selecting a button and using the embed code provided more...
Demox
Statistics
Last Update
Watchers
7 members
Articles
5
You may also like