Scripting
Everything in Puddlecraft follows the rain state on the controller. A small API on top of that lets gameplay and audio
code read the water and add to it. The runtime types live in the DFA.Puddlecraft namespace; the
API reference has everything else.
Driving the weather
active is the scene's controller, and its rain is the RainState. That's where the weather lives:
- intensity: how hard it's raining, from 0 (dry) to 1 (a downpour). It sets how fast the ground soaks and the puddles fill, not how full they get. Any rain at all keeps them growing until it stops.
- fill and wetMark: how full the placed puddles are, and the high-water mark that leaves damp rings as they drain.
- dampness and groundWater: how wet the ground is, and how far procedural puddles have spread over it.
These advance on their own in Play mode. Usually you'll only set the intensity, from your weather system. You can also set the water levels directly, to start a scene mid-storm or just after one.
using DFA.Puddlecraft;
using UnityEngine;
public class Weather : MonoBehaviour
{
[Range(0, 1)] public float rain = 0.8f;
void Start()
{
// Start the scene just after a storm: puddles full, ground still damp.
var controller = PuddlecraftController.active;
if (controller == null)
return;
controller.rain.fill = 1f;
controller.rain.dampness = 0.6f;
}
void Update()
{
var controller = PuddlecraftController.active;
if (controller != null)
controller.rain.intensity = rain;
}
}
Wind comes from the scene's directional Wind Zone. PuddlecraftWind reads it back for you: direction, strength with gusts, and steady strength.
Gameplay and audio API
TryGetPuddleAt
(position, out PuddleHit hit, verticalTolerance)tells you, at a point, how wet the ground is (wetness), how much of it is under standing water (water, with isWater true above half), and the ground height (groundHeight). It covers placed and procedural puddles alike. Use it for footsteps, tyre spray and gameplay.It returns false where there's no puddle data, or no ground within verticalTolerance of the point (0.3 m by default), so query from a character's feet. Procedural puddles are found with a raycast to the ground below. For that to work, the ground needs a collider on one of the controller's Gets Wet layers and a material with a Puddles value (
_PuddlecraftPuddles, which Puddlecraft/Lit (Wet) has; in Shader Graph, add a float property with that reference).Splash
(position, radius, strength)and AddTrail(from, to, radius, strength)push ripples into standing water. Unless you pass others, a splash has a radius of 0.08 m and a strength of 1, which is about a footstep. The Low quality tier has no ripples.PuddleRippleEmitter: put one on feet or wheels for wakes. For wheels, raise Contact Height, since their centre sits above the ground. It has onEnterPuddle and onExitPuddle events, and inWater and current tell you whether it's in water and what it's standing in.
dripLanded: fires for every drip from a drip edge that lands, and says whether it landed in water. In Play mode, when the controller's Simulate Within is above 0, only drips that close to a camera the rain falls around (the main camera when no rain is running) count.
currentFlow: how much a spout is pouring right now.
Footsteps
using DFA.Puddlecraft;
using UnityEngine;
public class Footsteps : MonoBehaviour
{
public AudioSource source;
public AudioClip dry, wet, splash;
// Call from an animation event when a foot lands.
public void OnFootstep()
{
Vector3 foot = transform.position;
if (PuddleQuery.TryGetPuddleAt(foot, out PuddleHit hit) && hit.isWater)
{
source.PlayOneShot(splash);
PuddlecraftRipples.Splash(foot);
}
else
{
source.PlayOneShot(hit.wetness > 0.5f ? wet : dry);
}
}
}
For a fuller example, see DemoPlayer in the Demo sample. Each step presses one small, round Splash into the water
under the middle of the foot, plus a wider, raised Splash holding the same amount of water, so the step sends out a
few clean rings instead of a soft swell. Jump landings press harder the faster the robot was falling.
Wet tracks
PuddlecraftTracks leaves wet footprints (Stamp) and tyre tracks (AddTrail) on dry ground.
Wet Tracks covers the calls, how to drive them from a Puddle Ripple Emitter's events, and a minimal
tyre script.
Reacting to drips
using DFA.Puddlecraft;
using UnityEngine;
public class DripCounter : MonoBehaviour
{
void OnEnable() => PuddlecraftEvents.dripLanded += OnDrip;
void OnDisable() => PuddlecraftEvents.dripLanded -= OnDrip;
void OnDrip(Vector3 position, bool inWater)
{
if (inWater)
Debug.Log($"Drip landed in a puddle at {position}");
}
}
Audio
Add Puddlecraft > Puddlecraft Audio (PuddlecraftAudio) to the scene for procedural rain. It's built from ten crossfading frequency bands, shaped by preset curves (light, medium, heavy, covered) that blend by intensity and by how sheltered the listener is. Shelter comes only from Cover Volumes, so without one the rain sounds open everywhere. It also plays drips and spouts from recorded CC0 clips, turned down under cover.
exposure tells you how exposed the listener is (1 minus the cover).
Cover Volumes
using DFA.Puddlecraft;
using UnityEngine;
public class Shutter : MonoBehaviour
{
[SerializeField] CoverVolume m_Window;
// 0 shut, 1 wide open: the volume's cover moves from coverClosed to coverOpen.
public void SetOpen(float amount) => m_Window.openness = amount;
void Update()
{
float cover = CoverVolume.CoverAt(transform.position); // 0 out in the rain, 1 fully indoors
var room = CoverVolume.InnermostAt(transform.position); // the volume that wins here, or null
}
}
Editor scripting
PuddlecraftSetup (namespace DFA.PuddlecraftEditor) handles scripted setup for build
scripts and CI: getting or creating the controller, adding renderer features, baking the rain cover and rebaking
puddles. See Getting Started for an example.