Any First Person Swimming Code Examples or Advice? (Voxel)

I’m not the type to usually ask this form of question. However, I’m trying to write some code to handle swimming from a first-person view. I’m making a voxel engine, and I want the player to be able to swim in placed fluid blocks.

I am struggling like crazy with this. I have some code for slowing the player down when entering fluid, and slowly reducing gravity upon entering the water to create a slowing effect. I have code for moving upwards in the water when the space bar is pressed and sinking when letting go. The transition between going up and down is fairly rough.

The major problem I have is what happens at the surface when swimming up to it. I can’t seem to figure out how to get the player to smoothly end up on land from the water. When the player gets a little bit out of the water, gravity quickly pulls it under again. And no matter what I try to do to fix this problem, something else breaks.

So I’m wondering if anyone knows of an asset that has some kind of first person swimming code in it that could help me.

If not, I’ll try to go more in depth about what I’m doing and perhaps you can help me.

It starts with a function called CheckBlocksInside. This function has the job of figuring out which blocks the player is currently inside. If the player is inside fluid, we want to do the swimming mechanics.

So if the player is in a fluid, I set the player’s state to “Swimming”. Otherwise, the state is “Normal”.

These states get used in the update method.

My update method is:

  1. Get Input
move = new Vector3(Input.GetAxis("Horizontal"), 0.0f, Input.GetAxis("Vertical"));
move *= speed * Time.deltaTime;
  1. Call CheckBlocksInside to figure out which blocks the player is inside, and also set swimming state if necessary.

  2. Check the state of the player. If the player is in swimming state, run the following code:

move.x *= 0.5f;
move.z *= 0.5f;

gravity -= 8 * Time.deltaTime;
if (gravity < 2.0f) gravity = 2.0f;

if (controller.isGrounded) gravity = 2.0f;

if (Input.GetKey(KeyCode.Space))
{
    if (gravity < 2.05f)
        move.y += gravity * Time.deltaTime * 3.0f;
}

Halve the movement vector, then I subtract gravity over time until it reaches a value of 2 (that still is going to need some tweaking). And when space is pressed, if gravity is low enough, move upward.

  1. If the player is in normal state, run this code instead:
gravity = 5.0f;

if (controller.isGrounded)
{
    jumping = false;
    jumpSpeed = 0;
   
    // Checks the block below the player, to see if anything special should happen.
    move = CheckBlockBelow();
    gravModifier = 1.00f;
   
    if (Input.GetKey(KeyCode.Space))
    {
        jumpSpeed = 9.0f;
        jumping = true;
    }
}

if (jumping)
    jumpSpeed -= gravity * gravModifier * Time.deltaTime;

move.y += jumpSpeed * Time.deltaTime;
gravModifier += 0.005f;

if (gravModifier > 5.0f) gravModifier = 5.0f;

This handles jumping and a gravity modifier to make the player fall faster as time goes on. I need to use Time.deltaTime so it isn’t frame-rate dependent, still. But that’s unrelated to my problem here.

And after that’s done, I run this code:

move.y -= gravity * gravModifier * Time.deltaTime;

move = transform.TransformDirection(move);
Move();

It handles gravity and transforming the coordinates to local. Move() calls CharacterController.Move and also checks some boundaries to ensure the player isn’t out of bounds of the world.

That’s about all I have. Upward and downward movement underwater works, entering water works. What doesn’t work is getting out of the water. The player can’t jump while in water, and can’t really escape the water. If I try to allow jumping in the water surface, then I run into issues such as the jump being canceled before the player gets out of the water, or when entering the water again the swimming isn’t handled until the player hits the ground under water.

I’ve also struggled very much to find any help on this kind of thing, so any help would be greatly appreciated.

Messing with the laws of physics ! Funky. Why alter the gravity when swimming ?
I would use a couple other variables to figure this out. Maybe check out Archimede laws to give you some ideas.

Anyway, i would start simple and go the way around with an inverse force to gravity, a vector, that pushes you “up”, slightly stronger than gravity but stops pushing when you hit the surface.
This should solve your issue as well as then you would be able to jump freely.
You could also replace the jump with a “pull up” animation that moves the players on top of a block out of water.

If you’re going for realism, then an implementation of proper physics is probably going to be needed as then you’ll be dealing with weight, density and other fancy variables and calculations.

Just my 2 cents.

1 Like

If the player is in water and the next movement upward is going to move the player out of water apply an extra burst of force to the controller to push him/her out enough to make it onto the surface? could also check if the black they’re going towards is solid before the burst.