{"id":1748,"date":"2021-04-08T22:02:36","date_gmt":"2021-04-08T20:02:36","guid":{"rendered":"https:\/\/lootburnkillrepeat.wordpress.com\/?p=1748"},"modified":"2023-12-25T14:24:01","modified_gmt":"2023-12-25T14:24:01","slug":"demox-4-interactive-water","status":"publish","type":"post","link":"https:\/\/crumblingsoftware.net\/index.php\/2021\/04\/08\/demox-4-interactive-water\/","title":{"rendered":"Water Interaction"},"content":{"rendered":"\n<blockquote class=\"wp-block-quote has-white-color has-text-color has-background has-link-color has-small-font-size wp-elements-2751d638d97c8a0b37584ee2df31282e is-layout-flow wp-block-quote-is-layout-flow\" style=\"background-color:#645449;font-style:italic;font-weight:600\">\n<p>Note!<\/p>\n<cite>This article is part of the, now deprecated, Demox development log. Demox was cancelled and is no longer in active development so this article can be somewhat out of context- however, I felt some information here could still be of use to someone, therefore it&#8217;ll remain for anyone to read.<\/cite><\/blockquote>\n\n\n\n<p>My previous projects have contained water however, I&#8217;ve never put any effort into making it behave like water would. In <strong><em>LBKR <\/em><\/strong>for instance the water was purely a decoration, it would not react to objects colliding with it&#8217;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&#8230; (<em> <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-pale-cyan-blue-color\">Please excuse my word-slaughtering, keep in mind that english is not my native language ;P<\/span><\/em> )<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Water Interaction<\/h2>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>For <strong><em>Demox <\/em><\/strong>I aim to make the water less of an illusion, and have it actually react to collisions and affect objects that enter the &#8220;<em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">water volume<\/span><\/em>&#8220;. This actually involves multiple object behaviours considering the code, and a whole lot of different particle effects among other things.<\/p>\n\n\n\n<p>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&#8217;s have a look at the goals I had set in mind.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<blockquote class=\"wp-block-quote has-cyan-bluish-gray-color has-black-background-color has-text-color has-background has-link-color wp-elements-7c8bb51529e7d9bb6e05227bbc543d28 is-layout-flow wp-block-quote-is-layout-flow\" style=\"font-style:italic;font-weight:100\">\n<p class=\"has-text-align-center has-vivid-red-color has-text-color has-link-color wp-elements-063a47074d7f01d8b7447de3cb8b75ea\"><strong>Volume Collision Goals:<\/strong><\/p>\n<cite><em>&#8211; Corpses, limbs and some types of objects \/ items should float when in a water volume.<\/em><br><em>&#8211; Character&#8217;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.<\/em><br>&#8211; <em>Projectiles hitting the water should use water-impact effects instead of their default hit effect.<\/em><br>&#8211; <em>Everything that enter the volume should visualize it by playing ripple or splash effects.<\/em><br>&#8211; <em>Water should react to elemental damage effects, ie. extinguish fire, and become electrified by electricity attacks.<\/em><\/cite><\/blockquote>\n<\/div>\n<\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"fx waterImpact01\" width=\"500\" height=\"375\" src=\"https:\/\/www.youtube.com\/embed\/ZbqfNof35P8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption class=\"wp-element-caption\"><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">Water impact effect, played when a body hits the water volume.<\/span><\/em><\/figcaption><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>Starting with the <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volume<\/span><\/em> itself, there were some important properties to keep in mind. For starters, the <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">depth <\/span><\/em>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 <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volumes<\/span><\/em> bounds, and then adjust the volume size in the editor to fit the terrain or water container.<br>The next property required is the <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">world position<\/span><\/em> along the y-axis that the volume&#8217;s <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">surface <\/span><\/em>is located at, this is required when calculating the depth of the volume at a specific location. (<em><span class=\"has-inline-color has-pale-cyan-blue-color\">Which is done to determine current speed penalty for avatars moving in the volume.<\/span><\/em>)<\/p>\n<\/div>\n<\/div>\n\n\n\n<pre class=\"wp-block-preformatted\"><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">float <\/span>vDepth;    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Depth of the current water volume<\/strong><\/span>\n<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">float <\/span>vSurfacePoint; <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/World position along y-axis of the current water volume's surface<\/strong><\/span>\n<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">float <\/span>speedPenalty;  <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/The velocity reduction of this instance<\/span><\/strong>\n<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Transform <\/span>vSurface; <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"> <strong>\/\/Current water volume<\/strong><\/span>\n\n<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Water volumes are identified through the OnTriggerEnter method<\/span>\npublic <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">void <\/span>OnTriggerEnter( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Collider <\/span>other ) {\n    if( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">target.IsDead<\/span> || <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_update <\/span>|| !<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">other<\/span>.CompareTag( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">Tags<\/span>.SurfaceWater )) {\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">return<\/span>;\n    }\n\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vSurface <\/span>= <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">other.transform<\/span>;   <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Assign colliding volume as current water volume<\/span><\/strong>\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">target<\/span>.InWater = <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">true<\/span>;        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Flag target avatar as inside a water volume<\/strong><\/span>\n\n    <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Determine if the current water surface is deep enough to swim\/drown in<\/span><\/strong>\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vDepth <\/span>= <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">MapMaster.Current.<\/span>FindWaterVolume( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vSurface<\/span>).<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">VolumeDepth<\/span>;\n    if( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vDepth <\/span>>= SharedGlobalProps.<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">SwimDepth <\/span>) {\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">ControlledFx <\/span>splash = <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">GameObjectPool.Current<\/span>.PullCommonFx(     <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">CommonFxNames<\/span>.W_Impact_Avatar );    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Pull a water-splash effect from the ObjectPool<\/strong><\/span>\n\n        if( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">splash <\/span>!= <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">null <\/span>) {    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\"><strong>\/\/Play the water splash effect if found<\/strong><\/span>\n            <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">splash<\/span>.FireFxCheap( transform.position );\n        }\n    }\n\n    StartManagedUpdate();         <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Starts a custom Update-method<\/strong><\/span>\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">target<\/span>.RefreshMoveSpeed();    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Refresh move speed of the avatar<\/strong><\/span>\n}\n\n<strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Only viewing a fraction of the OnManagedUpdate method since alot of it's content is irrelevant for this post<\/span><\/strong>\npublic <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">void <\/span>OnManagedUpdate() {\n    ....\n    if( Time.time - <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_lastDepth <\/span>>= <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_DepthThreshold <\/span>) {\n        CalculateWaterDrag();    <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Update the depth drag applied to the avatar at regular intervals ( ie. move speed penalty )<\/span><\/strong>\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_lastDepth <\/span>= Time.time;\n    }\n\n    if( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vDepth <\/span>>= SharedGlobalProperties.<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">SwimDepth <\/span>&amp;&amp; !<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">target.CanSwim <\/span>) {\n        if( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_curFx <\/span>== <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">null <\/span>) {\n            RetrieveFx();    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Pull an appropriate FX from the Object Pool<\/strong><\/span>\n            <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">return<\/span>;\n        }\n\n        <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Play the FX at the avatars position, but lock y-axis position to the surface point<\/span><\/strong>\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Vector3<\/span> pos = new <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Vector3<\/span>( transform.position.x, <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vSurfacePoint<\/span>, transform.position.z );\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_curFx<\/span>.transform.SetPositionAndRotation( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">pos<\/span>, transform.rotation );\n\n        if( !<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_drowning <\/span>) {\n            <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_drowning <\/span>= <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">true<\/span>;\n            <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_lastDrowned <\/span>= Time.time;\n        }\n\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">target<\/span>.OnDrown();\n        <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">return<\/span>;\n    }\n    ....\n}\n\npublic <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">void <\/span>CalculateWaterDrag() {\n    <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Determine how far beneath the surface the avatar currently is located<\/span><\/strong>\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Vector3 <\/span>xzSurf = new <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Vector3<\/span>( transform.position.x, <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vSurfacePoint<\/span>, transform.position.z );\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">float <\/span>avDist = <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Vector3<\/span>.Distance( transform.position, <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">xzSurf <\/span>);\n    \n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Assign current drag \/ speed penalty<\/strong><\/span>\n    <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">speedPenalty <\/span>= ( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">avDist <\/span>\/ <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vDepth <\/span>) * <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">_DepthDragMultiplier<\/span>;\n}<\/pre>\n\n\n\n<p>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 &#8220;<em><span class=\"has-inline-color has-vivid-cyan-blue-color\">DepthDragMultiplier<\/span><\/em>&#8220;, in order to get a value suitable for actual speed reduction.<\/p>\n\n\n\n<p>As can be seen in the code, the depth will also determine what type of <em>water ripple effects<\/em> 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.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\"><em><span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/\/&lt;summary&gt;\n\/\/\/<\/span><\/em><strong><span class=\"has-inline-color has-vivid-green-cyan-color\"> Retrieves a water-ripple FX from the object pool and starts playback\n<\/span><\/strong><em><span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/\/&lt;\/summary&gt;<\/span>\n<\/em><strong>private <\/strong><span class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>void<\/strong> <\/span>RetrieveFx<strong>(){\n<\/strong>    <span class=\"has-inline-color has-vivid-red-color\">ControlledFx <\/span>fx = <em><strong><span class=\"has-inline-color has-vivid-red-color\">null<\/span><\/strong><\/em>;\n\n    <strong><span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Select appropriate particle system<\/span>\n<\/strong>    if<strong>(<\/strong> <span class=\"has-inline-color has-luminous-vivid-orange-color\">vDepth <\/span><strong>&lt;<\/strong> <span class=\"has-inline-color has-luminous-vivid-orange-color\">_SmallRipplesDepth <\/span><strong>){<\/strong>\n        <strong><span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Play a smaller style of ripple effect<\/span>\n<\/strong>        <span class=\"has-inline-color has-luminous-vivid-orange-color\">fx <\/span>= <span class=\"has-inline-color has-luminous-vivid-orange-color\">GameObjectPool.Current<\/span>.PullCommonFx<strong>(<\/strong> <span class=\"has-inline-color has-vivid-cyan-blue-color\">CommonFxNames<\/span>.W_PuddleRipples <strong>)<\/strong>;\n    <strong>}\n<\/strong>    else if<strong>(<\/strong> <span class=\"has-inline-color has-luminous-vivid-orange-color\">vDepth<\/span> <strong>&lt;<\/strong> SharedGlobalProperties.<span class=\"has-inline-color has-luminous-vivid-orange-color\">SwimDepth <\/span><strong>){<\/strong>\n       <span class=\"has-inline-color has-vivid-green-cyan-color\"><strong> \/\/Play common water ripples effect<\/strong><\/span><strong>\n<\/strong>        <span class=\"has-inline-color has-luminous-vivid-orange-color\">fx <\/span>= <span class=\"has-inline-color has-luminous-vivid-orange-color\">GameObjectPool.Current<\/span>.PullCommonFx<strong>(<\/strong> <span class=\"has-inline-color has-vivid-cyan-blue-color\">CommonFxNames<\/span>.W_Ripples <strong>)<\/strong>;\n    <strong>}\n<\/strong>    else<strong>{\n<\/strong>        if<strong>(<\/strong> <span class=\"has-inline-color has-luminous-vivid-orange-color\">target.CanSwim <\/span><strong>){<\/strong>\n            <span class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Play ripples effect of type \"SwimRipples\"<\/strong><\/span><strong>\n<\/strong>            <span class=\"has-inline-color has-luminous-vivid-orange-color\">fx <\/span>= <span class=\"has-inline-color has-luminous-vivid-orange-color\">GameObjectPool.Current.<\/span>PullCommonFx<strong>(<\/strong> <span class=\"has-inline-color has-vivid-cyan-blue-color\">CommonFxNames<\/span>.W_SwimRipples <strong>)<\/strong>;\n        <strong>}\n<\/strong>        else<strong>{<\/strong>\n            <span class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/\/Play ripple effect of type \"DrownRipples\"<\/strong><\/span><strong>\n<\/strong>            <span class=\"has-inline-color has-luminous-vivid-orange-color\">fx <\/span>= <span class=\"has-inline-color has-luminous-vivid-orange-color\">GameObjectPool.Current.<\/span>PullCommonFx<strong>(<\/strong> <span class=\"has-inline-color has-vivid-cyan-blue-color\">CommonFxNames<\/span>.W_DrownRipples <strong>)<\/strong>;\n        <strong>}\n    }\n\n<\/strong>    if<strong>(<\/strong> <span class=\"has-inline-color has-luminous-vivid-orange-color\">fx<\/span> == <em><strong><span class=\"has-inline-color has-vivid-red-color\">null<\/span><\/strong><\/em><strong> ){\n<\/strong>        Debug.LogWarning<strong>(<span class=\"has-inline-color has-light-green-cyan-color\">\"WaterTracker could not retrieve a VFX\"<\/span>)<\/strong>;\n        StopManagedUpdate<strong>()<\/strong>;\n        <em><strong><span class=\"has-inline-color has-vivid-red-color\">return<\/span><\/strong><\/em>;\n    <strong>}\n\n<\/strong>    <span class=\"has-inline-color has-luminous-vivid-orange-color\">_curFx <\/span>= <span class=\"has-inline-color has-luminous-vivid-orange-color\">fx<\/span>;            <strong><span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Cache the located effect<\/span><\/strong>\n    <span class=\"has-inline-color has-luminous-vivid-orange-color\">_curFx<\/span>.FireFxCheap<strong>()<\/strong>;   \/<span class=\"has-inline-color has-vivid-green-cyan-color\"><strong>\/Play the located effect<\/strong><\/span>\n<strong>}<\/strong><\/pre>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"fx waterRipples03\" width=\"500\" height=\"375\" src=\"https:\/\/www.youtube.com\/embed\/LqT615UzdbQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption class=\"wp-element-caption\"><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">Water ripple effects in action<\/span><\/em><\/figcaption><\/figure>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c30887&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c30887\" class=\"wp-block-image size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/lootburnkillrepeat.files.wordpress.com\/2021\/02\/fx_waterripples01.png\" alt=\"\" class=\"wp-image-1790\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><figcaption class=\"wp-element-caption\"><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">Common Water Ripple effect<\/span><\/em><\/figcaption><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>For ripple and water trail effects there are <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">constant depth values <\/span><\/em>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.<\/p>\n\n\n\n<p>What impact \/ splash effect to use when a collision with the surface occur is determined within the <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volume&#8217;s<\/span> code<\/em>, unlike the ripple effects as described above. It&#8217;s a really simple setup of checking the <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">tag <\/span><\/em>of the object hitting the surface, for now this works nice since most objects with the same tag are of similar sizes <em>(<span class=\"has-inline-color has-pale-cyan-blue-color\">ie. characters, items, etc<\/span>)<\/em>. I already know now that some monsters will be alot larger than average though so in the near future I&#8217;ll need to adjust this to scale the splash effect to look good if the large monsters fall in the water aswell.<\/p>\n<\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h3 class=\"wp-block-heading\">Buoyancy<\/h3>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>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&#8217;t think I&#8217;ll go into detail of exactly how this is done since I&#8217;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.<\/p>\n\n\n\n<p>First, the <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">buoyancy <\/span>of the object, how well does it float in water?<br>Each object also required values to limit their movement in the <em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">water volume<\/span><\/em>, 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. &#8220;<em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">Float Pivot<\/span><\/em>&#8220;, and &#8220;<em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">Surface Range<\/span><\/em>&#8220;, the float pivot is a <em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Vector3 <\/span><\/em>that describes a point relative to the object&#8217;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. <\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"waterFloat01\" width=\"500\" height=\"375\" src=\"https:\/\/www.youtube.com\/embed\/JcsvzptACNE?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption class=\"wp-element-caption\"><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">Dead body and limb floating in water<\/span><\/em><\/figcaption><\/figure>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c31132&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c31132\" class=\"wp-block-image size-large wp-lightbox-container\"><img decoding=\"async\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" src=\"https:\/\/lootburnkillrepeat.files.wordpress.com\/2021\/02\/fx_floatingobjects.png\" alt=\"\" class=\"wp-image-1782\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>The <em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">surface range<\/span><\/em> will be used to compare how much beneath or above the surface the object is and adapt force applied in an appropriate manner.<\/p>\n\n\n\n<p>I also added a property of &#8220;<em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">water drag<\/span><\/em>&#8220;, 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 <em><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">Rigidbody <\/span><\/em>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.<\/p>\n\n\n\n<p>Additionally, a reference to the <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volume<\/span><\/em> affecting the object was also required since the depth at the object&#8217;s position is compared alot.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Moving Water<\/h2>\n\n\n\n<p>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 <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">moving water<\/span><\/em>. 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&#8217;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&#8217;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.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"fx wFloatStream\" width=\"500\" height=\"375\" src=\"https:\/\/www.youtube.com\/embed\/nEVJD48hkt4?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption class=\"wp-element-caption\"><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">Bodies and objects beeing swept away by a river, using &#8216;<\/span><span class=\"has-inline-color has-vivid-cyan-blue-color\">Constant Force<\/span><span class=\"has-inline-color has-luminous-vivid-amber-color\">&#8216;-triggers<\/span><\/em><\/figcaption><\/figure>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:66.66%\">\n<p>The particles are rendered as simple 3D meshes instead of 2D billboards, and currently use Unity&#8217;s refractive water material. As I liked the style of this effect I modified all other water effects to use a similar technique.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:33.33%\">\n<figure class=\"wp-block-gallery has-nested-images columns-3 wp-block-gallery-1 wp-container-content-29dca9c1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c31a15&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c31a15\" class=\"wp-block-image size-thumbnail wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" data-id=\"2525\" src=\"https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/fx_waterclimb01-150x150.png\" alt=\"\" class=\"wp-image-2525\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c31f70&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c31f70\" class=\"wp-block-image size-thumbnail wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" data-id=\"2526\" src=\"https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/fx_waterimpact02-150x150.png\" alt=\"\" class=\"wp-image-2526\" srcset=\"https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/fx_waterimpact02-150x150.png 150w, https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/fx_waterimpact02-300x300.png 300w, https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/fx_waterimpact02.png 385w\" sizes=\"auto, (max-width: 150px) 100vw, 150px\" \/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/figure>\n<\/div>\n<\/div>\n\n\n\n<p>But back on track, the<em><span class=\"has-inline-color has-vivid-cyan-blue-color\"> moving water<\/span><\/em> presented an obstacle that I hadn&#8217;t thought of, objects floating in the <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volume<\/span><\/em> would not follow the water flow, but instead just float near the same position. This was easily fixed though by creating <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">triggers <\/span><\/em>that apply <em><span class=\"has-inline-color has-luminous-vivid-orange-color\">constant force<\/span><\/em> to objects within it&#8217;s bounds if those objects are in a floating state, and then positioning those triggers along the water&#8217;s path.<\/p>\n\n\n\n<p><em>Example of the <span class=\"has-inline-color has-luminous-vivid-orange-color\">ConstantForce <\/span>script can be seen below:<\/em><\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public <span class=\"has-inline-color has-vivid-red-color\">Vector3 <\/span>forceDir; <span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Direction of the force, relative to this object's rotation<\/span>\npublic <span class=\"has-inline-color has-vivid-red-color\">float <\/span>force; <span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Power of the force applied<\/span>\nprivate List&lt; <span class=\"has-inline-color has-vivid-red-color\">Rigidbody <\/span>&gt; _bodies; <span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/List to hold all updated rigidbodies<\/span>\n\npublic <span class=\"has-inline-color has-vivid-cyan-blue-color\">void <\/span>OnTriggerExit( <span class=\"has-inline-color has-vivid-red-color\">Collider <\/span>other ) {\n     if( (<span class=\"has-inline-color has-luminous-vivid-orange-color\">other<\/span>.CompareTag( Tags.Corpse ) || other.CompareTag( Tags.Item )) &amp;&amp; <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>.Contains( <span class=\"has-inline-color has-luminous-vivid-orange-color\">other<\/span>.attachedRigidbody )) {\n         <span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Remove the target from the list of updated bodies<\/span>\n         <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>.Remove( <span class=\"has-inline-color has-luminous-vivid-orange-color\">other.attachedRigidbody <\/span>);\n     }\n }\npublic <span class=\"has-inline-color has-vivid-cyan-blue-color\">void <\/span>OnTriggerEnter( <span class=\"has-inline-color has-vivid-red-color\">Collider <\/span>other ) {\n     if( (<span class=\"has-inline-color has-luminous-vivid-orange-color\">other<\/span>.CompareTag( Tags.Corpse ) || <span class=\"has-inline-color has-luminous-vivid-orange-color\">other<\/span>.CompareTag( Tags.Item )) &amp;&amp; !<span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>.Contains( <span class=\"has-inline-color has-luminous-vivid-orange-color\">other.attachedRigidbody<\/span> )) {\n         <span class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Add the target to the list of updated bodies if it has correct object tag<\/span>\n         <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>.Add( <span class=\"has-inline-color has-luminous-vivid-orange-color\">other.attachedRigidbody<\/span> );\n     }\n }\npublic <span class=\"has-inline-color has-vivid-cyan-blue-color\">void <\/span>FixedUpdate() {\n    if( <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>.Count == 0 ) {\n         <span class=\"has-inline-color has-vivid-red-color\">return<\/span>;\n     }\n     for( int i = 0; i &lt; <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>.Count; i++ ) {\n         if( <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>[i ]!= null ) {\n             <span class=\"has-inline-color has-luminous-vivid-orange-color\">_bodies<\/span>[ i ].AddForce( transform.TransformDirection( <span class=\"has-inline-color has-luminous-vivid-orange-color\">forceDir <\/span>) * <span class=\"has-inline-color has-luminous-vivid-orange-color\">force<\/span>, <span class=\"has-inline-color has-vivid-red-color\">ForceMode<\/span>.Force );\n         }\n     }\n } \n\n<\/pre>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-3 wp-block-gallery-2 wp-container-content-29dca9c1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c32748&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c32748\" class=\"wp-block-image size-thumbnail wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" data-id=\"2528\" src=\"https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/a_shadwater03-150x150.webp\" alt=\"\" class=\"wp-image-2528\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c32b7f&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c32b7f\" class=\"wp-block-image size-thumbnail wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" data-id=\"2529\" src=\"https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/shadwater01-150x150.webp\" alt=\"\" class=\"wp-image-2529\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n\n\n\n<figure data-wp-context=\"{&quot;imageId&quot;:&quot;69dc272c32f9d&quot;}\" data-wp-interactive=\"core\/image\" data-wp-key=\"69dc272c32f9d\" class=\"wp-block-image size-thumbnail wp-lightbox-container\"><img loading=\"lazy\" decoding=\"async\" width=\"150\" height=\"150\" data-wp-class--hide=\"state.isContentHidden\" data-wp-class--show=\"state.isContentVisible\" data-wp-init=\"callbacks.setButtonStyles\" data-wp-on--click=\"actions.showLightbox\" data-wp-on--load=\"callbacks.setButtonStyles\" data-wp-on-window--resize=\"callbacks.setButtonStyles\" data-id=\"2527\" src=\"https:\/\/crumblingsoftware.net\/wp-content\/uploads\/2023\/12\/shadwater02-150x150.webp\" alt=\"\" class=\"wp-image-2527\"\/><button\n\t\t\tclass=\"lightbox-trigger\"\n\t\t\ttype=\"button\"\n\t\t\taria-haspopup=\"dialog\"\n\t\t\taria-label=\"Enlarge\"\n\t\t\tdata-wp-init=\"callbacks.initTriggerButton\"\n\t\t\tdata-wp-on--click=\"actions.showLightbox\"\n\t\t\tdata-wp-style--right=\"state.imageButtonRight\"\n\t\t\tdata-wp-style--top=\"state.imageButtonTop\"\n\t\t>\n\t\t\t<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"12\" height=\"12\" fill=\"none\" viewBox=\"0 0 12 12\">\n\t\t\t\t<path fill=\"#fff\" d=\"M2 0a2 2 0 0 0-2 2v2h1.5V2a.5.5 0 0 1 .5-.5h2V0H2Zm2 10.5H2a.5.5 0 0 1-.5-.5V8H0v2a2 2 0 0 0 2 2h2v-1.5ZM8 12v-1.5h2a.5.5 0 0 0 .5-.5V8H12v2a2 2 0 0 1-2 2H8Zm2-12a2 2 0 0 1 2 2v2h-1.5V2a.5.5 0 0 0-.5-.5H8V0h2Z\" \/>\n\t\t\t<\/svg>\n\t\t<\/button><\/figure>\n<\/figure>\n\n\n\n<p><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">( Pictures above are the final result of water volumes after a custom shader was written for water surfaces)<\/span><\/em><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Swimming<\/h2>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<p>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.<\/p>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\">\n<blockquote class=\"wp-block-quote has-cyan-bluish-gray-color has-black-background-color has-text-color has-background has-link-color wp-elements-dfc077e30eefef6fa2a0b5543f10117c is-layout-flow wp-block-quote-is-layout-flow\" style=\"font-style:normal;font-weight:100\">\n<p class=\"has-text-align-center has-vivid-red-color has-text-color has-link-color wp-elements-f0a599c06058292af91ba1551c980de4\"><strong>Obstacles<\/strong><\/p>\n<cite><em>&#8211; 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.<br>&#8211; How to stop the player from swimming out of the map in cases where the map borders consist of ocean?<br>&#8211; How to get the player out of the water if no ramp or beach is within the volume&#8217;s bounds?<\/em><\/cite><\/blockquote>\n<\/div>\n<\/div>\n\n\n\n<p>The first obstacle was easy (<span class=\"has-inline-color has-pale-cyan-blue-color\"><em>actually, all obstacles were easy to solve&#8230;<\/em><\/span>) 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.<\/p>\n\n\n\n<pre id=\"block-a70b11b3-ef3b-4e1b-88fe-114df44be957\" class=\"wp-block-preformatted\"><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">float <\/span>submergence = <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vSurfacePoint <\/span>- transform.position.y;  <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Determine how deep beneath surface avatar is<\/span><\/strong>\nif( <span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">submergence <\/span>>= SharedGlobalProperties.<span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">SwimDepth <\/span>) {}   <strong><span style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">\/\/Do some stuff<\/span><\/strong><\/pre>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>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&#8217;s statistics. While swimming the stamina will drain and when out of stamina the avatar will drown. This obviously help when limiting the player&#8217;s swim range.<\/p>\n\n\n\n<p>Since the avatar is not allowed to jump when swimming, it was critical to find a way to leave <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volumes<\/span><\/em> if there were no ramps or shallow water within the volume that would allow the avatar to start walking on the bottom of the <em><span class=\"has-inline-color has-vivid-cyan-blue-color\">water volume<\/span><\/em>.<br>I&#8217;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.<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"wSwim\" width=\"500\" height=\"375\" src=\"https:\/\/www.youtube.com\/embed\/WGZlxGsS1X8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><figcaption class=\"wp-element-caption\"><em><span class=\"has-inline-color has-luminous-vivid-amber-color\">Swimming behaviour in-game<\/span><\/em><\/figcaption><\/figure>\n\n\n\n<p>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&#8217;t satisfied with this.<\/p>\n\n\n\n<p>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.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Topic covering how I created water that interact with objects placed in the game world<\/p>\n","protected":false},"author":1,"featured_media":1781,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_share_on_mastodon":"0"},"categories":[104,105],"tags":[108,31],"class_list":["post-1748","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-code-scribbles","category-design-scribbles","tag-dev-blog","tag-development"],"share_on_mastodon":{"url":"","error":""},"_links":{"self":[{"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/posts\/1748","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/comments?post=1748"}],"version-history":[{"count":4,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/posts\/1748\/revisions"}],"predecessor-version":[{"id":2534,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/posts\/1748\/revisions\/2534"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/"}],"wp:attachment":[{"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/media?parent=1748"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/categories?post=1748"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/crumblingsoftware.net\/index.php\/wp-json\/wp\/v2\/tags?post=1748"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}