统一刚体碰撞无法正常工作
Unity rigidbody collision not working properly
我在统一刚体碰撞时遇到了很多奇怪的问题。我有一个播放器控制器脚本,它允许我移动我的播放器,但是当它与楼梯碰撞时,它会出现故障。当它与一扇门碰撞时,它会出现故障,当它在对角线行走时与地图边缘的 2 个不可见的盒子碰撞器碰撞时,它会穿过其中一个。我已经搜索了很多但找不到任何东西。我知道要继续的内容并不多,但这里有一些可能会有所帮助的内容:
- a video of what happens exactly
- 角色控制器代码:
using System;
using UnityEngine;
public class PlayerController : MonoBehaviour{
public Rigidbody body;
//player movement
private float speed = 12f;
private float walkSpeed = 10;
private float runSpeed = 15;
private float gravity = -9.81f;
public float jumpHeight = 2f;
private Vector3 inputs;
//player rotation
private float targetAngle = 0f;
private float angle = 0f;
public float turnSmoothTime = .1f;
public float turnSmoothVelocity;
//player jump
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
private bool isGrounded;
//there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
public int direction = 1;
public void movePlayer(Vector2 movement){
float horizontal = movement.x;
float vertical = movement.y;
//check if the player is standing on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
Quaternion rotation = new Quaternion();
body.freezeRotation = true;
if (Mathf.Abs(direction) == 1){
//gravity in y direction
//set the direction of the gravity
Physics.gravity = new Vector3(0f, direction * gravity, 0f);
//set the direction the inputs should work in
inputs.x = horizontal;
inputs.z = vertical;
inputs.y = body.velocity.y;
//calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
//set the characters rotation
rotation = Quaternion.Euler(0f, angle, 0f);
}
else if (Mathf.Abs(direction) == 2){
//gravity in x direction
Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);
inputs.y = -horizontal;
inputs.z = vertical;
inputs.x = body.velocity.x;
targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;
rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
}
else if (Mathf.Abs(direction) == 3){
//gravity in z-direction
Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);
inputs.x = horizontal;
inputs.y = vertical;
inputs.z = body.velocity.z;
targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;
//set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
Quaternion.AngleAxis(0f, Vector3.forward) *
Quaternion.AngleAxis(targetAngle, Vector3.up);
}
else{
direction = 1;
}
/*
if (inputs != Vector3.zero){
body.velocity = inputs;
}*/
//rotate the player in the move direction as long as they are moving
if (inputs.magnitude >= 0.1f){
transform.rotation = rotation;
}
}
void FixedUpdate(){
//move the player
body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
}
public void flip(int changedDirection){
inputs = Vector3.zero;
angle = 0f;
targetAngle = 0f;
direction = changedDirection;
}
public void walk(){
if (isGrounded){
speed = walkSpeed;
}
}
public void run(){
if (isGrounded){
speed = runSpeed;
}
}
public void jump(){
if (isGrounded){
if (direction == 1){
body.velocity = new Vector3(inputs.x, jumpHeight, inputs.z);
}
else if (direction == 2){
body.velocity = new Vector3(jumpHeight, inputs.y, inputs.z);
}
else if (direction == 3){
body.velocity = new Vector3(inputs.x, inputs.y, jumpHeight);
}
}
}
}
- 我的播放器对象的重要组件截图:
P.S。该代码有一些奇怪的引力变化部分。这是游戏的其余部分,但这对这个问题并不重要。希望你们能帮助我。我很乐意提供您可能需要的任何其他信息:) 感谢您提前抽出时间!!
编辑:根据第一个答案注释掉了一部分,但这并没有解决
首先,你移动你的播放器 'twice',首先在 movePlayer
函数中你有:
//move the player
if (inputs != Vector3.zero){
body.velocity = inputs;
}
然后在每个 FixedUpdate
:
body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
body.MovePosition
移动您的播放器,但不会将速度归零(您在 movePlayer
函数中设置)。
通过这种方式移动玩家可以 'overshoot' 对撞机太小,所以物体会通过。
您可以向刚体添加更多阻力以稍微减速对象。
好的,对于遇到类似问题的人,我找到了答案:
问题是我使用的是 body.moveposition,实际上应该 body.addforce。
这意味着您必须更改一些代码。如果您因为遇到类似问题而需要进一步解释,请与我联系,但这是我改进的代码以帮助您入门:
using System;
using UnityEngine;
public class PlayerController : MonoBehaviour{
public Rigidbody body;
//player movement
private float speed = 12f;
private float walkSpeed = 10;
private float runSpeed = 15;
public float gravity = -9.81f;
public float jumpHeight = 2f;
private Vector3 inputs;
//player rotation
private float targetAngle = 0f;
private float angle = 0f;
public float turnSmoothTime = .1f;
public float turnSmoothVelocity;
//player jump
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
private bool isGrounded;
//there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
public int direction = 1;
public void movePlayer(Vector2 movement){
float horizontal = movement.x;
float vertical = movement.y;
//check if the player is standing on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
Quaternion rotation = new Quaternion();
body.freezeRotation = true;
if (Mathf.Abs(direction) == 1){
//gravity in y direction
//set the direction of the gravity
Physics.gravity = new Vector3(0f, direction * gravity, 0f);
//set the direction the inputs should work in
inputs.x = horizontal;
inputs.z = vertical;
inputs.y = 0;
//calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
//set the characters rotation
rotation = Quaternion.Euler(0f, angle, 0f);
}
else if (Mathf.Abs(direction) == 2){
//gravity in x direction
Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);
inputs.y = -horizontal;
inputs.z = vertical;
inputs.x = body.velocity.x;
targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;
rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
}
else if (Mathf.Abs(direction) == 3){
//gravity in z-direction
Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);
inputs.x = horizontal;
inputs.y = vertical;
inputs.z = body.velocity.z;
targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;
//set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
Quaternion.AngleAxis(0f, Vector3.forward) *
Quaternion.AngleAxis(targetAngle, Vector3.up);
}
else{
direction = 1;
}
//rotate the player in the move direction as long as they are moving
if (inputs.magnitude >= 0.1f){
transform.rotation = rotation;
}
}
void FixedUpdate(){
body.AddForce(inputs * speed * Time.fixedDeltaTime);
}
public void flip(int changedDirection){
inputs = Vector3.zero;
angle = 0f;
targetAngle = 0f;
direction = changedDirection;
}
public void walk(){
if (isGrounded){
speed = walkSpeed;
}
}
public void run(){
if (isGrounded){
speed = runSpeed;
}
}
public void jump(){
if (isGrounded){
if (direction == 1){
body.AddForce(new Vector3(0, jumpHeight, 0));
}
else if (direction == 2){
body.AddForce(new Vector3(jumpHeight, 0, 0));
}
else if (direction == 3){
body.AddForce(new Vector3(0,0 , jumpHeight));
}
}
}
}
对我来说,这在跳跃方面造成了一些额外的问题,所以这里是您需要调整以解决这些问题的值:刚体质量和阻力以及玩家控制器重力和跳跃高度。
我在统一刚体碰撞时遇到了很多奇怪的问题。我有一个播放器控制器脚本,它允许我移动我的播放器,但是当它与楼梯碰撞时,它会出现故障。当它与一扇门碰撞时,它会出现故障,当它在对角线行走时与地图边缘的 2 个不可见的盒子碰撞器碰撞时,它会穿过其中一个。我已经搜索了很多但找不到任何东西。我知道要继续的内容并不多,但这里有一些可能会有所帮助的内容:
- a video of what happens exactly
- 角色控制器代码:
using System;
using UnityEngine;
public class PlayerController : MonoBehaviour{
public Rigidbody body;
//player movement
private float speed = 12f;
private float walkSpeed = 10;
private float runSpeed = 15;
private float gravity = -9.81f;
public float jumpHeight = 2f;
private Vector3 inputs;
//player rotation
private float targetAngle = 0f;
private float angle = 0f;
public float turnSmoothTime = .1f;
public float turnSmoothVelocity;
//player jump
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
private bool isGrounded;
//there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
public int direction = 1;
public void movePlayer(Vector2 movement){
float horizontal = movement.x;
float vertical = movement.y;
//check if the player is standing on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
Quaternion rotation = new Quaternion();
body.freezeRotation = true;
if (Mathf.Abs(direction) == 1){
//gravity in y direction
//set the direction of the gravity
Physics.gravity = new Vector3(0f, direction * gravity, 0f);
//set the direction the inputs should work in
inputs.x = horizontal;
inputs.z = vertical;
inputs.y = body.velocity.y;
//calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
//set the characters rotation
rotation = Quaternion.Euler(0f, angle, 0f);
}
else if (Mathf.Abs(direction) == 2){
//gravity in x direction
Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);
inputs.y = -horizontal;
inputs.z = vertical;
inputs.x = body.velocity.x;
targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;
rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
}
else if (Mathf.Abs(direction) == 3){
//gravity in z-direction
Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);
inputs.x = horizontal;
inputs.y = vertical;
inputs.z = body.velocity.z;
targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;
//set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
Quaternion.AngleAxis(0f, Vector3.forward) *
Quaternion.AngleAxis(targetAngle, Vector3.up);
}
else{
direction = 1;
}
/*
if (inputs != Vector3.zero){
body.velocity = inputs;
}*/
//rotate the player in the move direction as long as they are moving
if (inputs.magnitude >= 0.1f){
transform.rotation = rotation;
}
}
void FixedUpdate(){
//move the player
body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
}
public void flip(int changedDirection){
inputs = Vector3.zero;
angle = 0f;
targetAngle = 0f;
direction = changedDirection;
}
public void walk(){
if (isGrounded){
speed = walkSpeed;
}
}
public void run(){
if (isGrounded){
speed = runSpeed;
}
}
public void jump(){
if (isGrounded){
if (direction == 1){
body.velocity = new Vector3(inputs.x, jumpHeight, inputs.z);
}
else if (direction == 2){
body.velocity = new Vector3(jumpHeight, inputs.y, inputs.z);
}
else if (direction == 3){
body.velocity = new Vector3(inputs.x, inputs.y, jumpHeight);
}
}
}
}
- 我的播放器对象的重要组件截图:
P.S。该代码有一些奇怪的引力变化部分。这是游戏的其余部分,但这对这个问题并不重要。希望你们能帮助我。我很乐意提供您可能需要的任何其他信息:) 感谢您提前抽出时间!!
编辑:根据第一个答案注释掉了一部分,但这并没有解决
首先,你移动你的播放器 'twice',首先在 movePlayer
函数中你有:
//move the player
if (inputs != Vector3.zero){
body.velocity = inputs;
}
然后在每个 FixedUpdate
:
body.MovePosition(body.position + inputs * speed * Time.fixedDeltaTime);
body.MovePosition
移动您的播放器,但不会将速度归零(您在 movePlayer
函数中设置)。
通过这种方式移动玩家可以 'overshoot' 对撞机太小,所以物体会通过。
您可以向刚体添加更多阻力以稍微减速对象。
好的,对于遇到类似问题的人,我找到了答案:
问题是我使用的是 body.moveposition,实际上应该 body.addforce。
这意味着您必须更改一些代码。如果您因为遇到类似问题而需要进一步解释,请与我联系,但这是我改进的代码以帮助您入门:
using System;
using UnityEngine;
public class PlayerController : MonoBehaviour{
public Rigidbody body;
//player movement
private float speed = 12f;
private float walkSpeed = 10;
private float runSpeed = 15;
public float gravity = -9.81f;
public float jumpHeight = 2f;
private Vector3 inputs;
//player rotation
private float targetAngle = 0f;
private float angle = 0f;
public float turnSmoothTime = .1f;
public float turnSmoothVelocity;
//player jump
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
private bool isGrounded;
//there are 6 possible directions for gravity; positive and negative x, y and z. The direction can therefore be -3, -2, -1, 1, 2 or 3 where 1=y, 2=x, 3=z
public int direction = 1;
public void movePlayer(Vector2 movement){
float horizontal = movement.x;
float vertical = movement.y;
//check if the player is standing on the ground
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
Quaternion rotation = new Quaternion();
body.freezeRotation = true;
if (Mathf.Abs(direction) == 1){
//gravity in y direction
//set the direction of the gravity
Physics.gravity = new Vector3(0f, direction * gravity, 0f);
//set the direction the inputs should work in
inputs.x = horizontal;
inputs.z = vertical;
inputs.y = 0;
//calculate the angle with which the player has to be rotated and make the rotation smooth (smoothing is only possible in this orientation)
targetAngle = Mathf.Atan2(inputs.x, inputs.z) * Mathf.Rad2Deg;
angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
//set the characters rotation
rotation = Quaternion.Euler(0f, angle, 0f);
}
else if (Mathf.Abs(direction) == 2){
//gravity in x direction
Physics.gravity = new Vector3((direction / 2) * gravity, 0f, 0f);
inputs.y = -horizontal;
inputs.z = vertical;
inputs.x = body.velocity.x;
targetAngle = Mathf.Atan2(-inputs.y, inputs.z) * Mathf.Rad2Deg;
rotation = Quaternion.Euler(targetAngle, 0f, (direction / 2) * -90f);
}
else if (Mathf.Abs(direction) == 3){
//gravity in z-direction
Physics.gravity = new Vector3(0f, 0f, (direction / 3) * -gravity);
inputs.x = horizontal;
inputs.y = vertical;
inputs.z = body.velocity.z;
targetAngle = Mathf.Atan2(inputs.x, inputs.y) * Mathf.Rad2Deg;
//set the rotation in the correct order of the axis (90 degrees first and then around the correct axis)
rotation = Quaternion.AngleAxis((direction / 3) * -90f, Vector3.right) *
Quaternion.AngleAxis(0f, Vector3.forward) *
Quaternion.AngleAxis(targetAngle, Vector3.up);
}
else{
direction = 1;
}
//rotate the player in the move direction as long as they are moving
if (inputs.magnitude >= 0.1f){
transform.rotation = rotation;
}
}
void FixedUpdate(){
body.AddForce(inputs * speed * Time.fixedDeltaTime);
}
public void flip(int changedDirection){
inputs = Vector3.zero;
angle = 0f;
targetAngle = 0f;
direction = changedDirection;
}
public void walk(){
if (isGrounded){
speed = walkSpeed;
}
}
public void run(){
if (isGrounded){
speed = runSpeed;
}
}
public void jump(){
if (isGrounded){
if (direction == 1){
body.AddForce(new Vector3(0, jumpHeight, 0));
}
else if (direction == 2){
body.AddForce(new Vector3(jumpHeight, 0, 0));
}
else if (direction == 3){
body.AddForce(new Vector3(0,0 , jumpHeight));
}
}
}
}
对我来说,这在跳跃方面造成了一些额外的问题,所以这里是您需要调整以解决这些问题的值:刚体质量和阻力以及玩家控制器重力和跳跃高度。