attempt at a river.

this river work is approximately the first thing i’ve tried to do in unity. i’ve glanced at tutorials and help files; i’ve done spot searches for water/bobbing/bouyancy/river/current and not been successful.

‘Submerged vessels… displacing water?’ (perhaps the precedent setting post) seems to have a broken link. I found another really simple one in the forum that made a ‘water physics material’ that was just a spring with .4 for the frictions, but can’t relocate it for the life of me.

I am unfashionably new to unity, and love the community already. no need to post ‘welcome!’… i already feel it, and thank this place for existing.

http://www.zaru.org/River%20Fun.html
is what i’ve done so far. basically, the river is an empty object with both a physic box collider and a daylight water gameobject in it. oncollisionstay / collider box is a function that uses the ‘addforce’ member. i add a force that is the square of the mass of the object. the collider has a spring component (as i read elsewhere) with dynamic friction of .2, static of 0. as best as i understand, the spring component seems to only work [why?] in the up/down direction (y, in this case). but if you play it long enough, you see the smaller objects accelerate past the raft. this is bad. how do i make a constant river flow? forces and max speed?

i’ve tried it with a plane below the river that’s material ‘ice’ and a small force. but it has the same issues. i cannot control it.

i’ve tweaked the forces about as much as i can. do ‘drag’ and ‘force’ have units? i’d love to do some actual mathematics.

also, if i have a collider box or a plane of water, how do i attach the other to it in such a way that it’s right on top, such that when someone ‘touches’ the top of the water, they are entering the spring constant collider box.

i have the sense the my ramblings aren’t making sense:

1- how do i make a river?
it’s a constant velocity medium that has a force and spring component. it does not seem like ‘oncollisionstay’ is infallible when using a spring constant. also, the spring constant has to vary if you care about differing masses. any ideas?

2- if i have a collider box, and a plane that has no mesh (like a daylight water gameobject), how do i combine them such that the mesh is affixed to one side of the collider box (that can have varying height) without guessing at numbers?

ahh, further questions.

ok, so what is drag as opposed to dynamic friction in an object? is static/dynamic friction only observed if the collider is a mesh, or otherwise the action is along a plane, and not through a medium (collider)?

if i need to rtfm anywhere, please just say so.

For this case you are going to want to do some more scripting of the physics. I believe I did a water physics test some time ago so I will try to dig it up.

Here it is. It doesn’t do anything with rotations, but gives you the general idea of how to script this. For spheres it works fine :slight_smile:

An example of more detailed water physics can be found on the boat here:

http://forum.unity3d.com/viewtopic.php?t=4685&start=0

// place this on an object with a box collider that is a trigger. The top of the box is the water level. The box collider should represent the area where the water is

var curBodies = Array();
var curBodiesVolume = Array();

var densityOfWater = 1000.00;
var waterVelocity : Vector3;

private var surfaceYPos = 0.00;

function Start ()
{
	surfaceYPos = transform.position.y + (GetComponent(BoxCollider).size.y / 2) * transform.lossyScale.y;
}

function OnTriggerEnter (collider : Collider)
{
	body = collider.rigidbody;
	if(body)
	{
		alreadyHave = false;
		for(b in curBodies)
		{
			if(b == body) alreadyHave = true;
		}
		
		if(!alreadyHave)
		{
			curBodies.Add(body);
			
			// calculate the volume once per object only and store it in a sister array
			volume = 0.00;
			colliders = body.GetComponentsInChildren(Collider);
			for(c in colliders)
			{
				volume += c.bounds.size.x * c.bounds.size.y * c.bounds.size.z;
			}
			curBodiesVolume.Add(volume);
		}
	}
}

function OnTriggerExit (collider : Collider)
{
	print("lol");
	body = collider.rigidbody;
	if(body)
	{
		i = 0;
		removeIndex = -1;
		for(b in curBodies)
		{
			if(b == body) removeIndex = i;
			i ++;
		}
		
		if(removeIndex > -1)
		{
			curBodies.RemoveAt(removeIndex);
			curBodiesVolume.RemoveAt(removeIndex); // handle the sister array too
		}
	}
}

function FixedUpdate ()
{
	i = 0;
	for(b in curBodies)
	{
		bottom = b.ClosestPointOnBounds(Vector3(b.position.x, b.position.y - 100, b.position.z)).y;
		
		if(bottom > surfaceYPos)  // early out if not touching the water
		{
			i ++;
			continue; 
		}
		
		radius = Mathf.Abs(bottom - b.position.y);
		toCenter = surfaceYPos - b.position.y;
		depth = (Mathf.Clamp(toCenter / radius, -1, 1) + 1) / 2;

		displacement = curBodiesVolume[i] * depth;
		
		// density here is killograms per cubic meter. Unity's world units are meters and mass is commonly assumed to be killograms
		// Density of wood: 600 kg / cu.m
		// Density of water 1000 kg / cu meter
		// Density of iron 7000 kg / cu meter
		// densityOfBody = b.mass / curBodiesVolume[i];
		
		floatForce = displacement * densityOfWater * -Physics.gravity.y * depth;
		
		dragForce = (transform.TransformDirection(waterVelocity) - b.velocity) * densityOfWater * displacement * depth;
		
		b.AddForce((Vector3.up * floatForce) + dragForce);
		
		i ++;
	}	
}

ahh, thank you. i’m still messing with the script trying to get some of the finer points to work. the main problem i’m running into is that i’m not using spheres.

i have a couple more questions.

  1. what units are rigibody’s ‘drag’ in?

  2. is there a way to find out what type of collider i’m looking at. i’d like to know if the rigibody i’m messing with is a sphere or a box (or mesh, capsule, etc)

I don’t know what units the drag is in. But to find the different types of collider you can do this:

if(GetComponent(Collider))
{
	if(GetComponent(SphereCollider)) type = 0;
	else if(GetComponent(CapsuleCollider)) type = 1;
	else if(GetComponent(BoxCollider)) type = 2;
	else if(GetComponent(MeshCollider)) type = 3;
}