Hi,
I’m trying since 2 week to make a character playable in a moving SubMarine.
I tried different method, and this is the best I did:
This is the script where I move the player.
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class FPSController : MonoBehaviour
{
public float mouseSensitivity = 100f;
public float moveSpeed = 5f;
public Rigidbody sousMarinRb;
private Rigidbody rb;
private float xRotation = 0f;
private float lastSubmarineYRotation;
private Camera playerCamera;
private bool isMoving = false;
void Start()
{
rb = GetComponent<Rigidbody>();
playerCamera = Camera.main;
Cursor.lockState = CursorLockMode.Locked;
if (sousMarinRb == null)
{
Debug.LogError("Référence au sous-marin manquante !");
}
else
{
lastSubmarineYRotation = sousMarinRb.rotation.eulerAngles.y;
}
}
void Update()
{
GestionCamera();
}
void FixedUpdate()
{
float moveZ = Input.GetAxis("Vertical");
float moveX = Input.GetAxis("Horizontal");
isMoving = (moveZ != 0 || moveX != 0);
if (isMoving)
{
// No constraint if player move
rb.constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
Vector3 move = (playerCamera.transform.right * moveX + playerCamera.transform.forward * moveZ).normalized * moveSpeed;
move.y = 0;
// Use submarine velocity
if (sousMarinRb != null)
{
Vector3 submarineVelocity = sousMarinRb.linearVelocity;
move += submarineVelocity;
}
rb.linearVelocity = move;
}
else
{
// Adjust rotation for player if submarine is rotating
float currentSubmarineYRotation = sousMarinRb.rotation.eulerAngles.y;
float rotationDifference = Mathf.DeltaAngle(lastSubmarineYRotation, currentSubmarineYRotation);
transform.Rotate(Vector3.up * rotationDifference);
// Update last submarine rotation
lastSubmarineYRotation = currentSubmarineYRotation;
// Constraint if player doesn't move
rb.constraints = RigidbodyConstraints.FreezePositionX | RigidbodyConstraints.FreezePositionZ | RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY | RigidbodyConstraints.FreezeRotationZ;
// Stop player imediatly if no key is pressed
rb.linearVelocity = new Vector3(0, rb.linearVelocity.y, 0);
}
}
public void GestionCamera()
{
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;
transform.Rotate(Vector3.up * mouseX);
xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);
playerCamera.transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
}
}
And this is how I move the submarine:
using UnityEngine;
public class GestionVitesseSousMarin : MonoBehaviour
{
//Speed
public int actualSpeed; // Vitesse actuelle
public int minSpeed; // Vitesse minimale autorisée
public int maxSpeed; // Vitesse maximale autorisée
public int speed; // Multiplicateur de vitesse
public Rigidbody rb; // Référence au Rigidbody du sous-marin
//
//Rotation Y
public int actualRot; // Vitesse actuelle de rotation
public int minRot = -3; // Vitesse minimale autorisée
public int maxRot = 3; // Vitesse maximale autorisée
public float speedRot = 100f; // Multiplicateur de vitesse pour la rotation
//
//Rotation X
public int actualAngle; // Angle actuel de l'inclinaison
public int minAngle = -3; // Valeur minimale d'inclinaison vers le bas
public int maxAngle = 3; // Valeur maximale d'inclinaison vers le haut
public float rotationHauteurSpeed = 2f; // Vitesse d'interpolation pour l'inclinaison
private Quaternion targetRotation;
//
void Start()
{
if (rb == null)
{
rb = GetComponent<Rigidbody>();
}
targetRotation = this.transform.rotation;
}
void FixedUpdate()
{
SetSubmarineSpeed();
SetRotation();
}
public void SetSubmarineSpeed()
{
Vector3 movement = transform.forward * actualSpeed * speed * Time.fixedDeltaTime;
rb.MovePosition(rb.position + movement);
}
public void SetRotation()
{
//Y Rotation
float rotationAmount = actualRot * speedRot * Time.fixedDeltaTime;
Quaternion rotationY = Quaternion.Euler(0f, rotationAmount, 0f);
// X Rotation
float angleX = -actualAngle * 15f; // Chaque unité d'actualAngle correspond à 15°
targetRotation = Quaternion.Euler(angleX, rb.rotation.eulerAngles.y, 0f); // Assurer qu'il n'y ait pas de rotation sur l'axe Z
// Rotate
Quaternion globalRotation = Quaternion.Slerp(rb.rotation * rotationY, targetRotation, Time.fixedDeltaTime * rotationHauteurSpeed);
rb.MoveRotation(globalRotation);
}
}
The issue is when the submarine rotate on Y, if my character try to go forward, he rotate while he’s moving.
I set submarine as a parent of player.
Can someone help me ?