Water: swimming help

I am using a character controller and not a rigid body and have just started thinking about swimming.

I have at the moment a bounding box for the area that is underwater.

When my character’s center touches this he beings to tread the water, however i’d also like to allow the player to dive under the water.

I was wondering how i would:

a) detect when the player is underwater
b) put a blue ting to the camera when you are under water.

The effect i’m after is something like Super Mario 64 where you can tread the water but diveunder as well.

At the moment i was thinking of raycasting like below

var swimmingHit : RaycastHit;
	var swimmingHit2 : RaycastHit;
	if(Physics.Raycast(transform.position, -Vector3.up, swimmingHit, 0.2))
	{
		if(swimmingHit.collider.gameObject.tag == "Water") // swimmingHit2.collider.gameObject.tag != "Water")
		{
			treading = true;
			print("treading");
		}
		if(Physics.Raycast(transform.position, Vector3.up, swimmingHit2, 0.2))
		{
			print(swimmingHit2.collider.gameObject.name);
			if(swimmingHit2.collider.gameObject.tag == "Water")
			{
				treading = false;
				swimming = true;
				print("swimming");
			}
		}

So that if raycast below a bit and you are in water then you are treading the water but if above and below you is water then you are swimming, this didn’t workout though as the raycast up never returns true.

Any help would be great as i am a bit confused on what to do. Thanks!

How about switching between treading water and diving based on whether your point of view is above or below the water line?

As for the blue tinge, there are probably all kinds of fancy shader and post-processing effects you could use for that, but if you want to get something up and running quickly, you could just render an alpha-blended fullscreen quad in OnGUI() when the player is under water (you’ll probably want to fade it in and out to keep the transition from being too jarring).

Hi, could you explain how i could use point of view to check that?

Thankyou for the reply!

All you need is the y value for the water level (assuming you’re sticking with Unity’s ‘y-up’ convention), and the y value of the camera.

The latter is just the y element of the position vector of the transform of the game object to which the camera’s attached. As for the ‘water level’ y, if the water is represented using a bounding box, then it’s probably the y element of the bounding box’s max vector that you’re looking for.

Here’s my UnderwaterEffect.js script, it’s mostly pieced together from other forum postings with a few tweaks:

//The scene's default fog settings
private var defaultFog;
private var defaultFogColor;
private var defaultFogDensity;
private var defaultSkybox;
private var defaultGravity;
var noSkybox : Material;

function Start() {
    //Set the background color
    camera.main.backgroundColor = Color (0, 0.2, 0.4, 1);

	defaultFog = RenderSettings.fog;
	defaultFogColor = RenderSettings.fogColor;
	defaultFogDensity = RenderSettings.fogDensity;
	defaultSkybox = RenderSettings.skybox;
	defaultGravity = Physics.gravity;
}


function OnTriggerEnter() {
   RenderSettings.fog = true;
   RenderSettings.fogColor = Color (0, 0.2, 0.4, 0.2);
   RenderSettings.fogDensity = 0.3;
//   RenderSettings.skybox = noSkybox;
	Physics.gravity = defaultGravity/10;
}

function OnTriggerExit() {
   RenderSettings.fog = defaultFog;
   RenderSettings.fogColor = defaultFogColor;
   RenderSettings.fogDensity = defaultFogDensity;
//   RenderSettings.skybox = defaultSkybox;
	Physics.gravity = defaultGravity;
}

Note that you will almost certainly have to make a few changes so it looks good in your particular environment. It’s quite sensitive to that.

Sounds really good jesse, how would check that i am in the water area? Otherwise i’ll be treading as long as i am higher than the waters max Y.

Thanks for your help so far!

You could make the water area a trigger and consider the player to be in the water when the character controller is touching the trigger.

How are you representing the water currently? You mentioned in your original post that it was represented using a bounding box; are you referring to Unity’s ‘Bounds’ class? If so, you could use Bounds.Contains() to determine whether the player position is currently in the water volume. (This might be better than the trigger approach, in that you wouldn’t start treading water until you were about halfway in, whereas with the trigger approach, unless you ‘inset’ your trigger by some amount, you’ll start treading as soon as you touch the water.)

The way I currently have water is pretty basic and i’m pretty sure what you said would work perfectly.

At the moment i have a mesh that is a box where my water would be, i turn off the mesh render so that it can’t be seen and add a box collider to it. For me that was easier then trying to line up the box in unity’s editor as i was able to do it in my modeling software. This mesh is tagged with “Water”.

So at the moment i have:

var inWater = false;
		for(var o : GameObject in GameObject.FindGameObjectsWithTag("Water"))
		{
			var box : BoxCollider = o.GetComponent(BoxCollider);
			if(box.bounds.Contains(transform.position))
			{
				inWater = true;
				print("point in box");
				treading = true;
				cancelMoves();
				verticalSpeed = 0;
				var waterY : float = box.bounds.max.y;
				var characterY = transform.position.y;
				
				if(waterY > characterY)
				{
					swimming = true;
					treading = false;
				}				
				else
				{
					treading = true;
				}
			}
		}
		if(!inWater)
		{
			treading = false;
			swimming = false;
		}

Is this on the right track?

It doesn’t work yet but just checking if i’m on the same page.

My problems are:

  1. Treading is never possible

  2. If you walk onto the water the player bouces up and down. Also if you are in the water and swim to the top instead of treading water the player bounces.

what about Collisions

function OnCollisionEnter(collision : Collision) {
	treading = true;
	//plus a whole bunch of code
}

function OnCollisionStay(collision : Collision) {
	treading = true;
	//plus a whole bunch of code
}

function OnCollisionExit(collision : Collision) {
	treading = false;
	//plus a whole bunch of code
}

triggers also??

I don’t know what you are doing, but maybe you could attach some colliders to the legs, shoulders and head, and use that to determine if someone is treading, swimming, or diving.

If you know that the legs are in the collider of the water, but not the shoulders or head, then player is treading.

If it is shoulders and legs, then the player is swimming.
And if the head, legs, and shoulders are in the water, then the player is diving.

I would likely just use the fog render settings to testing purposes before adding a complicated shader.

Treading is never possible because you’re basing whether the player is treading or not on whether the player position’s y value is above or below the water line. But, if the player position is inside the bounding box for the water, that will never be true. Instead, you’d need to use the y value corresponding to the current point of view, as I suggested previously. (Which you’ll need to do any way in order to determine whether the ‘under water’ visual effect should be applied.)

(I’m not sure what sort of control system it is exactly that you have in mind, so I probably can’t offer any specific suggestions beyond that.)

Hi Jesse, its been a while so i’m not sure if you still visit these forums but i’ve been very busy and haven’t had time to work in unity for a long time.

My problem is still the same as always and i was wondering if it was at all possible for you to explain how the point of view can be used to solve this problem? Sorry to take so long to get back a for not understanding.

Thanks.