Tweaking The Water Behavior

Water Simulation Preview

We tweak all the water behavior properties in the water component inspector.

Water Simulation Properties

Tip

We can use the simulation mode to quickly and easily tweak and test the water system simulation properties, in realtime, right in the edit mode without the need to switch to play mode. All we need to do is to press the Enter Simulation Mode button.

Water Simulation Mode

Buoyancy Effector Properties

Water Simulation Buoyancy Effector Properties

Under the Simulation Properties*, the Buoyancy Level*** property controls the surface location of the buoyancy effector. When rigidbodies are intersecting or below the surface level, buoyancy forces are applied to them.

We can set the Buoyancy Level to an arbitrary value between 0 (water's top edge) and 1 (water's bottom edge), or you can match it to one of the following options:

  • Water Top Edge
  • Surface Level: only available when the surface is enabled in the material inspector.
  • Submerge Level: Only available when the fake perspectve effect is enabled in the material inspector.

Water Simulation Buoyancy Effector Properties Options Preview

Script Reference

1
2
3
4
5
6
using Game2DWaterKit.AttachedComponents;

...

waterObject.AttachedComponentsModule.BuoyancyEffectorSurfaceLevelLocation = WaterAttachedComponentsModule.BuoyancyEffector2DSurfaceLevelLocation.Custom;
waterObject.AttachedComponentsModule.BuoyancyEffectorSurfaceLevel = 0.02f;

Wave Properties

Water Simulation Custom Boundaries

The Stiffness property controls the frequency of the wave vibration (how fast the water oscillates). A low value make the water oscillate slowly, while a high value make it oscillate quickly.

The Spread property controls how fast the waves propagate.

The Damping property controls how fast the water stops oscillating. The lower the damping value is, the longer the water keeps oscillating.

Script Reference

1
2
3
waterObject.SimulationModule.Stiffness = 50f;
waterObject.SimulationModule.Spread = 50f;
waterObject.SimulationModule.Damping = 0.05f;

When a wave reaches a boundary, it bounces back. And by default, the simulation boundaries are the left and the right water edges. But, we could define our own boundaries by checking the "Use Custom Boundaries" property, and defining the custom boundaries locations.

Water Simulation Custom Boundaries

Tip

We can visualize the simulation boundaries positions in the scene view by toggling the 'eye icon' on.

Script Reference

1
2
3
waterObject.SimulationModule.IsUsingCustomBoundaries = true;
waterObject.SimulationModule.FirstCustomBoundary = 0.5f;
waterObject.SimulationModule.SecondCustomBoundary = -0.5f;

On-Collision Ripples Properties

On-Collision Ripples are created when a rigidbody falls into or gets out of the water.

Water Simulation On-Collision Ripples Properties

Collision Properties

Collision Filtering

Water Simulation On-Collision Ripples Collision Properties

Under the Collision Properties*, the Collision Mask*** property controls which objects layers are able to create on-collision ripples.

We can also filter the rigidbodies by their depth (z-position), and as such they should have a depth value between the Minimum Depth and the Maximum Depth properties values to be able to create on-collision ripples.

Next, the Maximum Distance property controls the maximum distance from the water surface over which to check for collisions.

Lastly, the Ignore Triggers property controls whether or not a collider that is marked as "Is Trigger" can create on-collision ripples.

Script Reference

1
2
3
4
5
waterObject.OnCollisionRipplesModule.CollisionMask = LayerMask.GetMask("Default", "TransparentFX");
waterObject.OnCollisionRipplesModule.CollisionMinimumDepth = -10f;
waterObject.OnCollisionRipplesModule.CollisionMaximumDepth = 10f;
waterObject.OnCollisionRipplesModule.CollisionRaycastMaximumDistance = 0.5f;
waterObject.OnCollisionRipplesModule.CollisionIgnoreTriggers = false;

2D Box Collider

Water Simulation On-Collision Ripples Collision 2D Box Collider Properties

The water object has an attached 2D Box Collider. This collider is configured as a Trigger and has the same size as the water object. By default, the collider's top edge matches the water's top edge, so when a rigidbody crosses the water's top edge, it generates on-collision ripples.

We can match the collider's top edge to one of the following options:

  • Water Top Edge
  • Surface Level: Only available when the surface is enabled in the material inspector.
  • Submerge Level: Only available when the fake perspective effect is enabled in the material inspector.

Water Simulation Buoyancy Effector Properties Options Preview

Disturbance Properties

Water Simulation On-Collision Ripples Disturbance Properties

The Minimum Disturbance and the Maximum Disturbance properties control the minimum and the maximum displacement of the water surface, respectively, when a rigidbody gets into or out of water. The greater the velocity of the rigidbody, the greater the disturbance.

The Minimum Velocity property controls the minimum velocity that a rigidbody hitting the water should have to cause the Maximum Disturbance to the water surface.

Script Reference

1
2
3
waterObject.OnCollisionRipplesModule.MinimumDisturbance = 0.1f;
waterObject.OnCollisionRipplesModule.MaximumDisturbance = 0.6f;
waterObject.OnCollisionRipplesModule.MinimumVelocityToCauseMaximumDisturbance = 5f;

On-Water-Enter And On-Water-Exit Ripples Properties

On-Collision Ripples On-Water-Enter On-Water-Exit Ripples Properties

Script Reference

1
2
waterObject.OnCollisionRipplesModule.IsOnWaterEnterRipplesActive = true;
waterObject.OnCollisionRipplesModule.IsOnWaterExitRipplesActive = true;

On-Water-Enter And On-Water-Exit Events

On-Collision Ripples On-Water-Enter Ripples Events

The OnWaterEnter event is triggered when a rigidbody falls into water.

Script Reference

1
waterObject.OnCollisionRipplesModule.OnWaterEnter.AddListener(OnWaterEnterCallback);

On-Collision Ripples On-Water-Exit Ripples Callbacks

The OnWaterExit event is triggered when a rigidbody gets out of water.

Script Reference

1
waterObject.OnCollisionRipplesModule.OnWaterExit.AddListener(OnWaterExitCallback);

On-Water-Enter And On-Water-Exit Sound Effect

On-Collision Ripples On-Water-Enter On-Water-Exit Ripples Sound Effect

It is possible to specify an Audio Clip to play when a rigidbody falls into or gets out of the water.

The Pool Size property controls the number of audio sources to pool when the game starts playing.

The Can Expand property controls whether or not the number of pooled audio sources can increase at runtime if needed.

The Volume property controls the audio clip volume when played.

Concerning the audio clip pitch (playback speed), we can use a constant audio pitch by toggling the Constant Pitch property on and setting the constant audio clip pitch value.

But, if we would like to vary the audio clip pitch depending on the velocity of the rigidbody hitting the water, we keep the Constant Pitch property toggled off and provide a Minimum Pitch and a Maximum Pitch values instead. And in this case, the greater the rigidbody's velocity, the lower the pitch value.

Script Reference

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// On-Water-Enter Sound Effect
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.IsActive = true;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.AudioClip = audioClip;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.PoolSize = 10;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.CanExpandPool = true;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.Volume = 0.1f;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.IsUsingConstantAudioPitch = false;
//waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.AudioPitch = 1f;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.MinimumAudioPitch = 0.85f;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesSoundEffect.MaximumAudioPitch = 1.15f;

// On-Water-Exit Sound Effect
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.IsActive = true;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.AudioClip = audioClip;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.PoolSize = 10;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.CanExpandPool = true;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.Volume = 0.1f;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.IsUsingConstantAudioPitch = false;
//waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.AudioPitch = 1f;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.MinimumAudioPitch = 0.85f;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesSoundEffect.MaximumAudioPitch = 1.15f;

On-Water-Enter And On-Water-Exit Particle Effect

On-Collision Ripples On-Water-Enter On-Water-Exit Ripples Particle Effect

It is possible to specify a Particle System to play when a rigidbody falls into or gets out of the water.

The Pool Size property controls the number of particle systems to pool when the game starts playing.

The Can Expand property controls whether or not the number of pooled particle systems can increase at runtime if needed.

The Spawn Offset property controls how much to shift the particle system spawn position.

Lastly, the StopAction event is triggered whenever a particle system ends playing.

Script Reference

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// On-Water-Enter Particle Effect
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesParticleEffect.IsActive = true;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesParticleEffect.ParticleSystem = particleSystem;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesParticleEffect.PoolSize = 10;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesParticleEffect.CanExpandPool = true;
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesParticleEffect.SpawnOffset = new Vector3(0f, -0.55f, 0.03f);
waterObject.OnCollisionRipplesModule.OnWaterEnterRipplesParticleEffect.StopAction.AddListener(OnParticleEffectStopAction);

// On-Water-Exit Particle Effect
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesParticleEffect.IsActive = true;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesParticleEffect.ParticleSystem = particleSystem;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesParticleEffect.PoolSize = 10;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesParticleEffect.CanExpandPool = true;
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesParticleEffect.SpawnOffset = new Vector3(0f, -0.55f, 0.03f);
waterObject.OnCollisionRipplesModule.OnWaterExitRipplesParticleEffect.StopAction.AddListener(OnParticleEffectStopAction);

Constant Ripples

Constant Ripples are created at regular time intervals.

Water Simulation Constant Ripples Properties

The Continue creating ripples when off-screen property controls whether or not the water script keeps creating ripples even when the water object is not visible to any camera.

Script Reference

1
2
waterObject.ConstantRipplesModule.IsActive = true;
waterObject.ConstantRipplesModule.UpdateWhenOffscreen = false;

Constant Ripples Time Interval

Water Simulation Constant Ripples Time Interval Properties

We could specify a fixed time interval, or just provide the minimum and the maximum time intervals and let the water script pick a random time interval each time ripples are created.

Script Reference

1
2
3
4
waterObject.ConstantRipplesModule.RandomizeTimeInterval = true;
//waterObject.ConstantRipplesModule.TimeInterval = 0.5f;
waterObject.ConstantRipplesModule.MinimumTimeInterval = 0.5f;
waterObject.ConstantRipplesModule.MaximumTimeInterval = 1f;

Source Properties

A constant ripple originates from the disturbance of a surface vertex, which we will refer to as the ripple source.

Water Simulation Constant Ripples Time Interval Properties

If the Randomize Source property is toggled on, the water script will randomly pick "Ripples Source Count" surface vertices, and disturb them.

Script Reference

1
2
waterObject.ConstantRipplesModule.RandomizeRipplesSourcePositions = true;
waterObject.ConstantRipplesModule.RandomRipplesSourceCount = 8;

Water Simulation Constant Ripples Time Interval Properties

But if the Randomize Source property is left toggled off, we select the surface vertices ourselves in the scene-view.

Water Simulation Constant Ripples Source Positions Selection In Scene View

Info

The green and the red dots in the scene-view represent the water mesh surface vertices. Clicking the green dot adds the surface vertex to the ripples source positions list, and clicking the red dot removes it from the list.

The Allow Duplicate Positions property controls whether or not to disturb a surface vertex, that is present in ripples source positions list multiple times, more than once.

Script Reference

1
2
3
waterObject.ConstantRipplesModule.RandomizeRipplesSourcePositions = false;
waterObject.ConstantRipplesModule.SourcePositions.Add(new Vector3(-5.35f, 0.87f, 0f));
waterObject.ConstantRipplesModule.AllowDuplicateRipplesSourcePositions = false;

Constant Ripples Disturbance Properties

Water Simulation Constant Ripples Disturbance Properties

We could specify a fixed disturbance value, or just provide the minimum and the maximum disturbance values and let the water script pick a random disturbance value each time ripples are created.

If the Smooth Ripples is toggled on, the ripple source as well as its neighbor surface vertices are disturbed to form a smoother ripple. The Smoothing Factor property controls the amount of disturbance to apply to neighbor vertices, and then how smooth the created ripple looks.

Script Reference

1
2
3
4
5
6
waterObject.ConstantRipplesModule.RandomizeDisturbance = true;
//waterObject.ConstantRipplesModule.Disturbance = 0.10f;
waterObject.ConstantRipplesModule.MinimumDisturbance = 0.08f;
waterObject.ConstantRipplesModule.MaximumDisturbance = 0.12f;
waterObject.ConstantRipplesModule.SmoothRipples = true;
waterObject.ConstantRipplesModule.SmoothingFactor = 0.125f;

Constant Ripples Sound And Particle Effects

Water Simulation Constant Ripples Sound And Particle Effect

As was the case with on-collision ripples, we could activate a sound and a particle effects to play whenever a constant ripple is created.

The description of the constant ripples sound and particle effects properties is exactly the same as the on-collision ripples, as discussed here.

Script Reference - Sound Effect Properties

1
2
3
4
5
6
7
8
9
waterObject.ConstantRipplesModule.SoundEffect.IsActive = true;
waterObject.ConstantRipplesModule.SoundEffect.AudioClip = audioClip;
waterObject.ConstantRipplesModule.SoundEffect.PoolSize = 10;
waterObject.ConstantRipplesModule.SoundEffect.CanExpandPool = false;
waterObject.ConstantRipplesModule.SoundEffect.Volume = 1f;
waterObject.ConstantRipplesModule.SoundEffect.IsUsingConstantAudioPitch = false;
//waterObject.ConstantRipplesModule.SoundEffect.AudioPitch = 1f;
waterObject.ConstantRipplesModule.SoundEffect.MinimumAudioPitch = 0.75f;
waterObject.ConstantRipplesModule.SoundEffect.MaximumAudioPitch = 1.25f;

Script Reference - Particle Effect Properties

1
2
3
4
5
6
waterObject.ConstantRipplesModule.ParticleEffect.IsActive = true;
waterObject.ConstantRipplesModule.ParticleEffect.ParticleSystem = particleSystem;
waterObject.ConstantRipplesModule.ParticleEffect.PoolSize = 10;
waterObject.ConstantRipplesModule.ParticleEffect.CanExpandPool = false;
waterObject.ConstantRipplesModule.ParticleEffect.SpawnOffset = Vector3.zero;
waterObject.ConstantRipplesModule.ParticleEffect.StopAction.AddListener(OnParticleEffectStopAction);

Script-Generated Ripples

Water Simulation Script Generated Ripples Properties

Script-Generated ripples are created in code by calling the GenerateRipple() method.

Example

 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
namespace Game2DWaterKit.DemoTutorial
{
    using UnityEngine;

    public class RipplesGenerator : MonoBehavior
    {
        private Camera _mainCamera;

        public Game2DWater waterObject;

        [Range(0f,1f)] public float disturbanceFactor = 0.5f;
        public bool pullWaterDown = true;
        public bool playSoundEffect = false;
        public bool playParticleEffect = false;
        public bool smoothRipple = true;
        [Range(0f,1f)] public float smoothingFactor = 0.5f;

        private void Awake()
        {
            _mainCamera = Camera.main;
        }

        private void Update()
        {
            if (Input.GetMouseButtonDown(0) && waterObject != null)
            {
                Vector2 position = _mainCamera.ScreenToWorldPoint(Input.mousePosition);

                // Create ripple
                waterObject.ScriptGeneratedRipplesModule.GenerateRipple(position, disturbanceFactor, pullWaterDown, playSoundEffect, playParticleEffect, smoothRipple, smoothingFactor);
            }
        }
    }
}

The GenerateRipple() method takes 7 parameters:

  • Position: [Vector2] controls the position where we would like to create the ripple. The nearest surface vertex to this position is disturbed.
  • Disturbance Factor:* [Float, Range: 0..1] controls the amount of disturbance to apply to the water surface. The actual applied disturbance is computed by interpolating the Minimum Disturbance and the Maximum Disturbance*** by this factor.

    Info

    The Minimum Disturbance and the Maximum Disturbance are set in the inspector. We'll see them shortly.

  • PullWaterDown: [Bool] controls whether the water surface is pulled down or pushed up when creating the ripple. This mimics an object falling into water or getting out of water, respectively.

  • PlaySoundEffect: [Bool] controls whether or not to play the sound effect.
  • PlayParticleEffect: [Bool] controls whether or not to play the particle effect.

    Info

    The sound and the particle effects properties are set in the inspector. We'll see them shortly.

  • SmoothRipple: [Bool] controls whether or not to disturb neighbor surface vertices in order to create a smoother ripple.

  • Smoothing Factor: [Float, range: 0..1] controls the amount of disturbance to apply to neighbor vertices.

Script-Generated Ripples Disturbance Properties

Water Simulation Script Generated Ripples Disturbance Properties

We set the Minimum Disturbance and the Maximum Disturbance properties in the inspector.

Script Reference

1
2
waterObject.ScriptGeneratedRipplesModule.MinimumDisturbance = 0.1f;
waterObject.ScriptGeneratedRipplesModule.MaximumDisturbance = 0.75f;

Script-Generated Ripples Sound And Particle Effects Properties

Water Simulation Script Generated Ripples Sound And Particle Effects Properties

The description of the script-generated ripples sound and particle effects properties is exactly the same as the on-collision ripples, as discussed here.

Script Reference - Sound Effect Properties

1
2
3
4
5
6
7
8
9
waterObject.ScriptGeneratedRipplesModule.SoundEffect.IsActive = true;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.AudioClip = audioClip;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.PoolSize = 10;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.CanExpandPool = false;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.Volume = 1f;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.IsUsingConstantAudioPitch = false;
//waterObject.ScriptGeneratedRipplesModule.SoundEffect.AudioPitch = 1f;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.MinimumAudioPitch = 0.75f;
waterObject.ScriptGeneratedRipplesModule.SoundEffect.MaximumAudioPitch = 1.25f;

Script Reference - Particle Effect Properties

1
2
3
4
5
6
waterObject.ScriptGeneratedRipplesModule.ParticleEffect.IsActive = true;
waterObject.ScriptGeneratedRipplesModule.ParticleEffect.ParticleSystem = particleSystem;
waterObject.ScriptGeneratedRipplesModule.ParticleEffect.PoolSize = 10;
waterObject.ScriptGeneratedRipplesModule.ParticleEffect.CanExpandPool = false;
waterObject.ScriptGeneratedRipplesModule.ParticleEffect.SpawnOffset = Vector3.zero;
waterObject.ScriptGeneratedRipplesModule.ParticleEffect.StopAction.AddListener(OnParticleEffectStopAction);

Water Size Animation

It's possible to animate the water size in code using the method AnimateWaterSize(targetSize, duration, constraint, wrapMode).

  • targetSize: [Vector2] sets the water target size.
  • duration: [float] sets the animation duration in seconds.
  • constraint: [enum WaterAnimationConstraint] constraints the position of one/multiple water edge(s)

    WaterAnimationConstraint enum

    None, Top, Bottom, Left, Right, TopLeft, TopRight, BottomLeft, BottomRight

    • wrapMode: [enum WaterAnimationWrapMode]

    WaterAnimationWrapMode enum

    • Once: Stops playing the animation once the target size is reached.
    • Loop: The water size is reset to the initial size and the animation is restarted once the target size is reached.
    • PingPong: When the target size is reached, the initial size is set to the new target size and the animation restarts. So the water size will ping-pong back and forth between the initial size and the target size.

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
using Game2DWaterKit.Animation;

....

var targetSize = waterObject.MainModule.WaterSize + new Vector2(0f, 3f); // increase the water height by 3 units
var duration = 2f; // 2 seconds
var constraint = WaterAnimationConstraint.Bottom; // constraints the position of the bottom edges, so only the top edge "moves"
var wrapMode = WaterAnimationWrapMode.Once; // play the animation once

waterObject.AnimationModule.AnimateWaterSize(targetSize, duration, constraint, wrapMode);