====== Scripting API ======
Brief description of the most important classes and functions.
\\ Almost every parameter in every component can be changed runtime from code.
\\ For exact behaviour and more - check source code.
===== DragonWaterManager =====
This is main singleton class that controls everything about the water.
public class DragonWaterManager
{
// static getter to get singleton instance
public static DragonWaterManager Instance { get; }
// acces to configuration scriptable object
public DragonWaterConfig Config { get; }
public float Time { get; set; } // current simulation time - if you disable auto simulation, you''ll have to update this value manually every frame
public WaterSurface UnderwaterSurface { get; } // surface that main camera is currently below; null if none
public WaterSampler.HitResult CameraHitResult { get; } // last camera hit test against water, used for auto snapping and underwater detection
public Camera MainCamera { get; } // refers to Camera.Main
// subscribe to this event to receive callback when camera changes underwater state
// both, from and to param can be null depending on if you dive, resurface, or change between surface under water
public delegate void UnderwaterChangedCallback(WaterSurface from, WaterSurface to);
public event UnderwaterChangedCallback OnUnderwaterChanged;
// collections
public IReadOnlyList Surfaces { get; } // currently active surfaces
public WaterSurface DefaultSurface { get; } // current default and active surface, null if not set
public IReadOnlyList { get; } // currently active ripple projectors
public IReadOnlyList { get; } // currently active local wave areas
// culling - used internally by WaterSampler
public void CullWaterSurfaces(ref Bounds bounds, ref List list);
public void CullCutoutColliders(ref Bounds bounds, ref List list);
// sampling water
public WaterSampler.HitResult SampleWater(Vector3 position); // calls SampleWater with considerCutouts=true as default
public WaterSampler.HitResult SampleWater(Vector3 position, bool considerCutouts);
}
----
===== WaterSampler =====
The most usefull class.
\\ Create it's object to sample water.
\\ You can reuse this object (keep calling Schedule and Complete) but **always remember to Dispose() when no longer needed.**
public class WaterSampler : IDisposable
{
public static IReadOnlyList ActiveSamplers { get; } // access to all currently active samplers
public enum SurfaceDetectionMode
{
Default, // use default surface, if its null then fallbacks to AutoCull
AutoCull, // automatically scans nearby surfaces
Custom // tests only aainst provided surfaces in SurfaceDetectionCustom list
}
public enum CutoutDetectionMode
{
AutoCull, // automatically scans nearby colliders to cutout
DontCutout, // do not care about cutouts at all - always sample
Custom // tests only against provided cutouts in CutoutDetectionCustom list
}
public int Precision = 0; // amount of iterations; 0 refers to Constants.DefaultSamplerPrecision and 3-4 is most cases is more than enough
public SurfaceDetectionMode SurfaceDetection = SurfaceDetectionMode.Default; // how nearby surfaces are detected
public CutoutDetectionMode CutoutDetection = CutoutDetectionMode.AutoCull; // how to to process cutout volumes
public List SurfaceDetectionCustom = null; // you NEED to assign it in case of Custom mode
public List CutoutDetectionCustom = null; // you NEED to assign it in case of Custom mode
public Bounds CullingBox = default; // if left default, it will automatically create bounding box for all points before scheduling
public int MaxSize { get; }; // maximum amount of points this sampler can process; assigned via constructor
public bool IsRunning { get; }; // if its running, you shouldn't modify anything here
public HitResult[] Results { get; } // access to array of results of last scan - it's size is always MaxSize even if you ran it for less points
public int ResultCount { get; } // actual amount of available results in Results array
public WaterSampler(int maxSize = 1); // construction - you have to specify max size
public void Dispose(); // ALWAYS remember to dispose no longer needed sampler
public void Resize(int newMaxSize); // resize to new MaxSize
// fill points to test against water
public void SetPoint(int index, Vector3 point); // set single point and specified index
public void SetPoints(IReadOnlyList points); // set points since index 0
public void SetPoints(ArraySegment points); // set points since index 0
// schedule
public void Schedule(); // calls Schedule with MaxSize
public void Schedule(int pointsCount); // amount of points to process starting from index 0; can't be larger than MaxSize
public void Complete(); // complete processing - recommended to call next frame
// caching auto culls
// be default AutoCull modes are very expensive - with this functions you can temporarily cache their result so it will act like Custom options
public void CacheAutoCull(); // calls CacheAutoCull with MaxSize
public void CacheAutoCull(int points);
public void ClearAutoCullCache();
// clears sampler until next scheduling, so it acts like not scheduled yet at all with no results
public void ClearState();
}
----
==== WaterSampler.HitResult ====
Struct that contains sampling result of a single point against water.
public struct HitResult
{
public Vector3 sampledPoint;
public WaterSurface surface; // null if no surface detected
public Vector3 hitPoint; // actual position on water surface, possibly very closely to sampledPoint
public Vector3 hitNormal; // normal vector of water here
public bool HasHit => surface != null;
public bool IsUnderwater => sampledPoint.y < hitPoint.y;
public float Depth => hitPoint.y - sampledPoint.y; // positive when under water
public float Height => sampledPoint.y - hitPoint.y; // positive when above water
public float WaterLevel => hitPoint.y;
}
----
===== WaterBehaviour =====
Abstract MonoBehaviour class than can be used as utility for easier water sampling from your game object component.
\\ You can treat is as a MonoBehaviour facade to WaterSampler.
\\ It uses WaterSampler asyncrhonously, so it always generates one frame delay while sampling water, which is totally fine in most cases.
public abstract class WaterBehaviour : MonoBehaviour
{
// used to configure component from inspector
[Serializable]
public class WaterSamplerConfig { /* .. */ }
// access to config that is exposed for configuration via inspector
public WaterSamplerConfig SamplerConfig {get; };
public int FrameDividerOffset { get; };
// check this inside InnerFixedUpdate if you want to schedule
protected bool isSchedulingFrane { get; };
// direct access to array with points you are going to sample
protected Vector3[] samplingPoints { get; };
// Unity callbacks
protected virtual void Awake();
protected virtual void OnEnable();
protected virtual void OnDisable();
protected virtual void OnDestroy();
protected virtual void OnFixedUpdate(); // in most cases, do not override this function (see InnerFixedUpdate)
// prepare sampler side before settingg any points
protected void PrepareSamplingPointsSize(int size);
protected void SetSamplingPoint(int index, Vector3 point);
protected void SetSamplingPoints(Vector3[] points);
protected int GetResultCount(); // return amount of available results
protected WaterSampler.HitResult GetResult(int index);
protected void GetResults(out ArraySegment results);
// override this function for actual fixed update behaviour
// only inside this function you can schedule points
protected virtual void InnerFixedUpdate() { }
}
----
==== FloatingBody ====
FloatingBody is built-in implementation of WaterBehaviour.
public class FloatingBody : WaterBehaviour
{
// getters and setters for all properties you see in the inspector
public Vector3 CenterOfMass { get; set; }
public float BuoyancyForce { get; set; }
public bool IgnoreMass { get; set; }
public float NormalAlignment { get; set; }
public float Instability { get; set; }
public float SubmergeDrag { get; set; }
public float SubmergeAngularDrag { get; set; }
public float CurrentSubmergeLevel { get; } // range 0-1 thats means fraction of points that are under water
public Rigidbody Rigidbody { get; } // return attached rigidbody
// modify contact points (all in local space of game object)
public Vector3 GetContactPoint(int index);
public void SetContactPoint(int index, Vector3 point);
public void RemoveContactPoint(int index);
public void AddContactPoint(Vector3 point);
// return last hit result for point with given index
// useful e.g. to check if given part of body is above or under water without creating additional sampler or object for that
public WaterSampler.HitResult GetContactPointHit(int index);
}