- Home /
How to negate this force?
I'm making a videogame about submarines. I need the player to be able to move around the submarine. I've implemented this with a player using a rigidbody and a controller script and a submarine gameobject using a rigidbody and a controller script. The rigidbody has a script which is called buoyancy.
Depending on the volume of water displaced and the weight of the rigidbody, it will sink up to a certain height. This works fine.
The problem is since there is drag on each rigidbody, when the player moves, it will act this force upon the submarine and move it. This also happens when the player is pushing on a wall connect to the interior of the submarine.
I want the player not to be able to move the submarine from walking inside it but if it is light enough, to be able to push it from the outside.
Here's a link to a video showing this
Buoyancy Script
using System;
using UnityEngine;
public class Buoyancy : MonoBehaviour
{
private const float surfaceHeight = 0f;
private const float waterDensity = 1f;
[SerializeField]
private float area = 0f;
[SerializeField]
private Rigidbody objectRigidbody = null;
private Vector3 buoyantForce = Vector3.zero;
public Vector3 Force => buoyantForce;
private void FixedUpdate()
{
if (transform.position.y >= surfaceHeight)
{
buoyantForce = Vector3.zero;
return;
}
buoyantForce = GetBuoyantForce();
objectRigidbody.AddForce(buoyantForce, ForceMode.Force);
}
private Vector3 GetBuoyantForce()
{
Vector3 u = Vector3.up;
float magnitude = waterDensity * -Physics.gravity.y * (surfaceHeight - transform.position.y) * area;
return magnitude * u;
}
}
Player Movment Script
using System;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
[SerializeField]
private Rigidbody playerRigidbody = default;
[SerializeField]
private float jumpHeight = 1f;
[SerializeField]
private float airPenalty = 0.2f;
[SerializeField]
private float topSpeed = 2f;
[Header("Ground")]
[SerializeField]
private Transform groundCheck = default;
[SerializeField]
private float groundRadius = 1f;
[SerializeField]
private LayerMask groundMask = default;
private Input input = default;
private Vector2 move = default;
private bool grounded = false;
private bool jump = false;
private void Awake()
{
input = new Input();
input.Player.Move.performed += ctx => move = ctx.ReadValue<Vector2>();
input.Player.Move.canceled += _ => move = Vector2.zero;
input.Player.Jump.performed += _ => jump = true;
input.Player.Jump.canceled += _ => jump = false;
}
private void FixedUpdate()
{
CheckGrounded();
Vector3 force = Vector3.ClampMagnitude(transform.right * move.x + transform.forward * move.y, 1f) * topSpeed - playerRigidbody.velocity;
force.y = 0f;
if (grounded)
{
if (jump)
{
playerRigidbody.AddForce(Vector3.up * Mathf.Sqrt(-2f * Physics.gravity.y * jumpHeight), ForceMode.VelocityChange);
}
}
else
{
force *= airPenalty;
}
if (force != Vector3.zero)
{
playerRigidbody.AddForce(force, ForceMode.VelocityChange);
}
}
private void CheckGrounded()
{
grounded = Physics.CheckSphere(groundCheck.position, groundRadius, groundMask);
}
private void OnEnable()
{
input.Enable();
}
private void OnDisable()
{
input.Disable();
}
private void OnDrawGizmos()
{
if (groundCheck != null)
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(groundCheck.position, groundRadius);
}
}
}
Answer by Bunny83 · Sep 09, 2020 at 12:22 PM
To ensure a one directional interaction between the submarine and your player you could split up the physics into two parts. Unfortunately Unity's standard physics implementation does not support mutiple physics scenes in order to have seperate local physics for the player. However you can work with collision layers and have a seperate collison object for the submatine with a kinematic rigidbody. This seperate collision model of the submarine would be simply a child of the actual submarine. Now the player shouldn't collide with the actual submarine but only with this extra interior collider object. Since this object has a kinematic rigidbody it can push the player around when the submarine moves, but never the other way round because the player does not interact with the actual (non kinematic) submarine rigidbody.
Note if you don't want external forces and movement on the submarine to affect the player at all, it's usually the easiest solution to have the interior physics seperate and stationary somewhere in the level and just map the results into the actual submarine. Of course this can get tricky when the player can actually leave and enter the submarine. The first approach is more robust in this regards. Though it's also possible to combine both solutions depending on the wanted behaviour.
Always keep in mind that the physics engine is just a rough approximation and game or simulation development is just about getting the look and feel right and not to be physically accurate. PhysX is not a viable solution when you're looking for actual scientific physcis simulations.
I'm trying to do an open world game, so yes, the player will be able to enter and exit. I also have another script which automatically levels out the submarine because if it collides with an object, I want it to rotate accordingly but then return to its normal inclination. Would that affect the interaction or not? I'm already using two layers for collisions because when the player is inside the submarine, I still want the exterior colliders to detect collisions on the outside but if they are all on the same collision layers then the player is forced outside of the submarine. How can I adjust this accordingly? Sorry for the long answer.
Of course this is all still possible. Assu$$anonymous$$g that the world geometry and most other things are on the default layer, you can move the submarine itself on a seperate layer, the player on a seperate layer and the additional kinematic rigidbody on a seperate layer. With the collision matrix you can exactly specify which layer can collide with which other layer. So your submarine rigidbody should only collider with the default layer. The Player should collide with the default layer and the additional kinematic rigidbody of the submarine, but not with the submarine itself. Likewise the additional kinematic rigidbody shouldn't collide with anything else besides the player(s). Since the kinematic rigidbody can not be affected by collisions with other objects, the player can not affect the actual submarine at all.
Answer by Matt1000 · Sep 09, 2020 at 12:14 PM
If you know for sure the rigidbody Drag is the one causing the forces (which I didn't get tbh), then I'd simply go with a script that toggles that property whn you leave/enter the submarine.
Also, I don't understand why the buoyancy is affected by height but maybe it's due to pressure, not sure.
I'm following Archimedes' Principle:
F = h · ρ · g
Where
F is the force exerted upon the submarine
h is the depth of the submarine
ρ is the density of the medium
g is the gravity acted upon the submarine
Since the submarine is affected by gravity, the depth will begin to increase and thus the force. When the force is equals to the force of gravity, it will be at it's equilibrium point.
Put a beach ball on the surface. It stays there. Submerge it just below the surface. It pushes upwards. Try putting it by your feet. It pushes upwards very strongly.
Buoyancy in reality is not affected by height (or depth). A real submarine adjusts it's ballast tanks in order to become neutral so they perfectly float in the medium. They move up and down by using its diving rudders to literally "swim" up and down in the water. In a sense a submarine drives through the water like an airplane flies through the air. With the exception that a submarine doesn't immediately "fall down" when they make a full stop since they don't have to generate lift through speed. Though even submarines have "sail planes" which keep them more stable as they drive through the water.
Your answer
Follow this Question
Related Questions
Touch controlled ice puck 0 Answers
Add force based on drag speed 4 Answers
Force is not applied to the rigidbody? 1 Answer
Realistic methods of propulsion without friction involved 0 Answers
How exactly does Rigidbody Drag works? 3 Answers