Итак, я разрабатываю многопользовательскую онлайн-игру FPS для основной работы над SDD, и я столкнулся с проблемой. Ниже приведен код движения для моего игрока. Я пытаюсь внедрить в игру страйфинг и зайчик, поэтому я настроил тестовую среду в своем проекте, и мне удалось заставить все работать. Единственная проблема заключалась в том, что после того, как я попытался вставить это обратно в свой основной проект, он перестал работать.
Основная проблема в том, что прыжки иногда работают только иногда. Игрок прыгает только на очень небольшую величину и иногда остается там, что означает отсутствие трения, поскольку игрок застрял на земле. Он также, кажется, немного приподнимается под землей, но коллайдер на нем не должен допустить этого. Я пытался удалить код, который ускоряет падение вниз, но иногда это только исправляет.
Ссылка на код: https://pastebin.com/cLkemQhX
public class PlayerMovement: MonoBehaviourPun
{
[Header("Movement Settings")]
public float maxVelocityGround = 15f;
public float maxVelocityAir = 10f;
public float groundAccelerate = 90f;
public float airAccelerate = 180f;
public float fallMultiplier = 1.2f;
public float lookSens = 8f;
public float slowDrag = 0;
public float thrusterForce = 7f;
public float friction = 10f;
private float _friction = 0f;
[Header("Rotation")]
float xRot = 0F;
float yRot = 0F;
float minY = -90f;
float maxY = 90f;
Quaternion originalRotation;
//More Movement Variables
private float distToGround;
private Vector3 _velocity;
private Vector2 xyVelocity;
[Header("References")]
//public Text grounded;
//public Text velocity;
public Camera cam;
private Move motor;
private Rigidbody rb;
private CapsuleCollider collidr;
private GameObject rayPoint;
//private PlayerSetup playerSetup;
//Booleans
private bool jumpy = false;
void Start()
{
_friction = friction;
//Locks the cursor to the middle of the screen, and hides it from view
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
//These attatch the correct objectss to their references in the script, defined above
motor = GetComponent<Move>();
rb = GetComponent<Rigidbody>();
collidr = GetComponent<CapsuleCollider>();
rayPoint = GameObject.Find("point");
//playerSetup = GetComponent<PlayerSetup>();
//Sets the distance to the ground from the center of the collider, used in determining whe nthe player is on the ground
distToGround = collidr.bounds.extents.y;
if (GetComponent<Rigidbody>())
GetComponent<Rigidbody>().freezeRotation = true;
originalRotation = transform.localRotation;
}
void FixedUpdate()
{
//Debug function that shows a visual representation of when the player is on the ground
//string a = isGrounded().ToString();
//grounded.GetComponent<Text>().text = a;
//Finds the Velocity in the x plane. Also used in debug, as it shows it on screen
//xyVelocity = new Vector2(rb.velocity.x, rb.velocity.z);
//velocity.GetComponent<Text>().text = xyVelocity.magnitude.ToString("0.000");
//This statement checks if the player both is on the ground, and has requested to jump. If so it will jump
//while also not allowing multiple jumps while in the air. If the player holds it down, he will jump as soon
//as he touches the ground, avoiding friction and allowing the player to bunnyhop
if (Input.GetKey("space") && isGrounded())
{
rb.AddForce(Vector3.up * thrusterForce, ForceMode.Impulse);
jumpy = true;
}
//rb.AddForce(Jump(), ForceMode.Impulse);
//This makes you fall faster than you rise, and make jumping feel nicer overall.
if (rb.velocity.y < 0)
{
rb.velocity += Vector3.up * Physics.gravity.y * fallMultiplier * Time.deltaTime;
}
//Gets the input from the axis'
float input_y = Input.GetAxis("Vertical");
float input_x = Input.GetAxis("Horizontal");
//Calculates the direction we want to move in, taking into account mouse movement to allow for strafing
Vector3 accelDir = (transform.forward * input_y + transform.right * input_x).normalized;
//Checks if we are not pressing any inputs, and makes us decelerate faster, to make moving feel more snappy
decelerate(accelDir);
//This code adjusts the vector to be projected onto the plane that we are currently moving on. Makes strafing better
RaycastHit hit;
Physics.Raycast(collidr.center, Vector3.down, out hit, 1000);
accelDir = Vector3.ProjectOnPlane(accelDir, hit.normal).normalized;
//Finds the current velocity of our RIgidBody
Vector3 curVel = rb.velocity;
//Determines whether or not we want to use the air movement(ignore friction) or not.
//The boolean checks if we have just jumped, so while we are still on the ground, we don't want to calculate friciton
if (isGrounded() && jumpy == false)
{
_velocity = MoveGround(accelDir, curVel);
}
else
{
_velocity = MoveAir(accelDir, curVel);
}
//Apply Movement
rb.velocity = _velocity;
//These call the rotation functions below, one rotates the camera in the y plane, the other the rigidbody in the x plane, which has the camera as a child
cameraRotate();
rbRotate();
jumpy = false;
}
private Vector3 MoveGround(Vector3 accelDir, Vector3 prevVelocity)
{
// Apply Friction
float speed = prevVelocity.magnitude;
if (speed != 0) // To avoid divide by zero errors
{
float drop = speed * _friction * Time.fixedDeltaTime;
prevVelocity *= Mathf.Max(speed - drop, 0) / speed; // Scale the velocity based on friction.
}
return Accelerate(accelDir, prevVelocity, groundAccelerate, maxVelocityGround);
}
private Vector3 MoveAir(Vector3 accelDir, Vector3 prevVelocity)
{
return Accelerate(accelDir, prevVelocity, airAccelerate, maxVelocityAir);
}
private Vector3 Accelerate(Vector3 accelDir, Vector3 prevVelocity, float accelerate, float max_velocity)
{
float projVel = Vector3.Dot(prevVelocity, accelDir); // Vector projection of Current velocity onto accelDir.
float accelVel = accelerate * Time.fixedDeltaTime; // Accelerated velocity in direction of movment
// If necessary, truncate the accelerated velocity so the vector projection does not exceed max_velocity
if (projVel + accelVel > max_velocity)
{
accelVel = max_velocity - projVel;
};
return prevVelocity + accelDir * accelVel;
}
//Function to check if we are on the ground
public bool isGrounded()
{
return Physics.Raycast(collidr.bounds.center, Vector3.down, distToGround);
//Below is a capsule cast, it would be better to implement because it has a thickness
//return Physics.CheckCapsule(collider.bounds.center, new Vector3(collider.bounds.center.x, collider.bounds.min.y, collider.bounds.center.z), collider.radius * 0.9f);
}
/// <summary>
/// decelerates us faster when not moving
/// </summary>
/// <param name="input"></param>
public void decelerate(Vector3 input)
{
if (input == Vector3.zero)
{
_friction = 10f * friction;
}
else
{
_friction = friction;
}
}
/// <summary>
/// This function is the camera rotation function
/// </summary>
public void cameraRotate()
{
//Get the input from the mouse and multiply it by sensitivity so it can be adjusted from ingame
yRot += Input.GetAxis("Mouse Y") * lookSens;
//Clamp it so that we cant just keep spinning in the Y direction
yRot = clamp(yRot, minY, maxY);
//Calculate the quaternion using the amount of rotation found before. We use the negative mouse input as the amount
//of rotation, and then specify that we want this rotation to be around the x axis. It seems counter intuitive, but this is the way to do it
Quaternion yRotAngle = Quaternion.AngleAxis(-yRot, Vector3.right);
//Apply this rotation to the cameras transform
cam.transform.localRotation = originalRotation * yRotAngle;
}
/// <summary>
/// Basically the same as above, but we dont need to clamp it because we want to be able to forever spin to the left and right
/// </summary>
public void rbRotate()
{
xRot += Input.GetAxis("Mouse X") * lookSens;
Quaternion xRotAngle = Quaternion.AngleAxis(xRot, Vector3.up);
rb.transform.localRotation = originalRotation * xRotAngle;
}
/// <summary>
/// just clamps the angle we input between the next 2 floats
/// </summary>
/// <param name="angle">the float representation of the angle</param>
/// <param name="min">the min that the angle can be</param>
/// <param name="max">you got it by now right?></param>
/// <returns></returns>
private float clamp(float angle, float min, float max)
{
return Mathf.Clamp(angle, min, max);
}
}