Objects Floating in Water
By Geep, based on 2019-2020 forum research and experiments done to help create "Away 1 - Air Pocket". Treatment of cadavers is beyond the scope of this article; see Ragdoll Corpses in Water
- 1 Two Methods at a Glance
- 2 Method 1 - Use Moveable Objects
- 3 Method 2 - Bobbing to Simulate Floating
- 4 Advanced Methods
- 5 See More
Two Methods at a Glance
The table below compares the two easy methods to achieve a floating effect. Other methods are mentioned at the end of the page.
|Aspect||Moveable Objects||Bobbing Objects|
|Initial placement important||yes||yes|
|Controlled by||density, via mass||speed,height,phase,axis|
|Moving at worldspawn?||no||yes|
|Player affects motion?||yes||no|
|Stops moving?||on timeout||no|
|Tumbles, rotates, ricochets?||yes||no|
|Can sink to seafloor?||yes, if heavy||not really|
|Can shoot above surface?||yes, if light||not really|
|Has splash/ripple effects||yes||no|
|Player can stand on?||sometimes||yes|
Method 1 - Use Moveable Objects
Entities found in the “Moveables” folder - such as atdm:moveable_crate01, that inherits from moveable_base - will float dynamically in water if their calculated density is light enough. But there are issues.
Adjust the “Mass”, Ignore “Density”
To control floating and underwater behavior (detailed below), you may wish to inspect and override the inherited “mass” spawnarg value. If a mass value is defined (and it always is if you use a standard moveable class), then the “density” spawnarg is algorithmically ignored… so you can ignore it too. Remember that the mass of an object can affect non-water aspects of game play.
Desired Initial Placement of an Object
Here, let's restate general considerations when placing a Moveable in the map, but in a water context.
In the Water, but Above the Sea Floor. By “sea floor”, we just mean the first solid object encountered directly below the object. Place the moveable object where you wish (below, at, or slightly above the water surface), and set its “nodrop” spawnarg to “1”. On worldspawn, it will stay where you placed it, awaiting activation by the player.
On the Sea Floor. Like the above, but make sure nodrop = 0 (the usual default). On worldspawn, the moveable will move immediately to the sea floor (without special effects), awaiting activation by the player.
Far Above the Water. If the object is placed far above the water or any other floor, it just hangs there (awaiting player activation), no matter the nodrop value. If the player is swimming, the object will be out of reach.
Getting the Placed Object to Activate
Unfortunately, the object will not rise off the sea floor, or if at the surface, begin bobbing, until after the player activates it by bumping it (perhaps indirectly) or frobbing it. Clever game design may sometimes get around this. For instance, a floating rowboat (i.e., Moveables/Nautical/atdm:moveable_boat2) could be activated by spawning the player directly into it.
It is unclear if there is a direct way to activate moveable objects by triggers/scripting. An indirect way to so activate and keep them activated is suggested in Func Forcefields: envelop them in a force field. This can be triggered on and off. If the field strength was minimal, object pileup would be delayed. Or perhaps two co-located force fields, only one of which is turned at any time, could be used to slosh activated objects back and forth.
Plausible Behaviors When First Activated
Objects initially placed above the water surface or higher in the water than they would normally float may trigger splash sound and visual effects, and plunge below the surface (before arising if buoyant). Similarly, initially underwater objects that are highly buoyant may pop above the surface, with effects. As in real life, the presence and extent of such behaviors is presumably influenced by the momentum at surface penetration. But the engine likely scants object shape and orientation.
Effect of Mass on Buoyancy and Floating Behavior
The mass divided by the calculated (or estimated) volume gives a calculated density, which affects how high in the water an object sits and (along with mass) how vigorous any bobbing and roll-about may be.
The following summary table gives rules of thumb, based on experiments (not shown). For box-shaped objects it is possible for both you and the physics engine to easily calculate the volume, and from that (given the mass) the density. For other shapes, the engine likely deploys shortcut estimates (perhaps using the collision model) with ad-hoc fudge factors. Rather than attempt to mimic that, or guesstimate appropriate volumes for complex shapes, it is suggested that you use the table as follows:
- Observe the object’s floating behavior, and from that, impute its approximate density.
- Compare that to the desired behavior, and scale the mass value proportionally.
- Iterate until happy.
|Estimated density||Underwater: Sink (-) or Rise (+)||Float Behavior at Surface|
|1.4||(-)||Awash (top at surface)|
|1.2||Rides low (near-awash)|
|1.0||(+)||Rides mid-low (more below water)|
|0.5||++||Rides mid-high (more above water)|
|0.3||+++||Rides high (most above water)|
|0.1||++++||Sits on surface|
The chosen waviness of the water surface can affect surface behavior. For instance, consider the “Wasser” gui texture. The wave chop of this will cause the small cloth package (which rides on the surface if the default mass is unchanged) to be perhaps-unrealistically bouncy. (Aside: Moveables have a “bouncyness” spawnarg, but presumably this does not influence behavior in water.)
When choosing a mass value, larger values affect not only the sink rate, but how easy it is to move the object underwater. Conversely, a very light mass value will not only cause the object to sit on the surface, but also bob too-vigorously to ripples (as mentioned). A mass value of 0 is not recommended, because the object not only “disappears” (launches?) but the subsequent frame rate deteriorates. Amusingly, a negative mass (e.g., -1) creates a special hydrophobic effect – the object has a “toe” (corner) in the water, and can skip around on the surface.
When estimating the density, the physics engine considers only the mass of the floating object alone, not what may be atop of or within it, e.g., contents of a boat, including the player.
The foregoing assumes this is true for the engine:
- The given mass value is always considered; and
- The given density value (i.e., stated, not calculated) is always ignored (when there’s a mass value, per DEF Files)
Experiments conducted by Geep with crates are consistent with that. However, the 2016 “Water” thread did report an effect of changing the “density” spawnarg value for a boat. Reason for this discrepancy of findings is unknown.
Method 2 - Bobbing to Simulate Floating
Instead of a “moveable” entity, we start with a brush or model. There is no “nodrop” to consider in this case, and player activation of motion is not an issue...the motion starts immediately and runs forever. However, since the physics engine is not involved, the bobbing object will not get out of the way of the player; the player can stand and ride on it instead. (Presumably, the bobbing can inflict damage if the player gets pinched between the bobber and some other immoveable.) No splash sound effects or visuals, either. Nor circular ripples emanating.
Starting with a Brush. Imagine a brush textured as a crate (e.g., using Texture Browser/”crate01” and Surface Browser/Texture Operations/Fit). Then with the brush selected, right-click and choose “create entity”.
Starting with a Model. In the Entity inspector, select the classname, and then “Choose entity class…”.
In either case, from the tree of Entities, under “Func” select “func_bobbing”. Spawnargs of particular interest are:
- Speed. Seconds to complete a bob cycle.
- Height. Amplitude of bob
Values of 2 for each is a good starting point. (Oscillating will be axis-aligned; default z-axis is your friend.) Also, you’ll probably want to change the name, e.g., to “func_bobbing_mycrate”.
If you have multiple nearby independent objects bobbing, consider making the movements non-synchronized, by
- varying their speeds (e.g., with non-integers or values that are not multiples of each other)
- playing with the additional spawnarg “phase”.
Conversely, if your func_bobbing entity has something associated with it that should also bob with it (e.g., a sign decal; an object on a raft), remember to use “bind” on the latter to attach it.
Instead of up-and-down motion, func_bobbing can also be used to give slight lateral movement to underwater objects, e.g., a fish, though it is limited to world-axis-aligned X or Y directions. Keep the movement slight... nobody wants to see a fish swimming backwards a long distance.
In the forum thread "Water", Moonbo suggests (in addition to func_bobbing discussed above) the use of func_mover. Func_mover and associated scripting can be considered if a complex programmatic movement is required, such as also having lateral motion due to a current, eddy, or whirlpool. Or having a fish swim a route.
Forum thread "Water", begun by Destined in March, 2016, is the starting point for information here.
Swimmable Water by Angua describes setting up water features.