В настоящее время я работаю над клоном Minecraft и сейчас пытаюсь реализовать столкновение игрока с землей.Мой подход состоит в том, чтобы получить блоки, с которыми игрок мог столкнуться, через поле столкновения игрока, расширенное его скоростью, и оттуда обрабатывать каждый блок, сравнивая расстояние вдоль каждой оси со скоростью в этом направлении и сохраняя меньшую единицу.Затем, в конце концов, я двигаю игрока наименьшим возвращаемым движением вдоль каждой оси.
Теперь у меня проблема в том, что при перемещении в угол или край блока он работает не так, как ожидалось (иначе), но вместо этого заставляет игрока сгибаться внутри блока или даже позволить ему полностью войти в блок.Как я могу это исправить?
Player.cs (метод обновления):
IList<Box> collidables = world.GetBoxes(collisionBox.Moved(position).Expanded(velocity * 2));
foreach (Box c in collidables) {
velocity = collisionBox.Moved(position).ResolveCollision(c, velocity);
}
position += velocity;
Box.cs (внутри struct Box):
public Box Expanded(Vector3 expand) {
Vector3 _min = min;
Vector3 _max = max;
if (expand.X < 0) {
_min.X += expand.X;
} else {
_max.X += expand.X;
}
if (expand.Y < 0) {
_min.Y += expand.Y;
} else {
_max.Y += expand.Y;
}
if (expand.Z < 0) {
_min.Z += expand.Z;
} else {
_max.Z += expand.Z;
}
return new Box(_min, _max);
}
public float ResolveXCollision(Box b, float x) {
if (b.Max.Y <= Min.Y || b.Min.Y >= Max.Y) {
return x;
}
if (b.Max.Z <= Min.Z || b.Min.Z >= Max.Z) {
return x;
}
if ((x > 0) && (Center.X <= b.Center.X)) {
float max = b.Min.X - Max.X;
if (Math.Abs(max) < Math.Abs(x)) {
x = max;
}
}
if ((x < 0) && (Center.X >= b.Center.X)) {
float max = b.Max.X - Min.X;
if (Math.Abs(max) < Math.Abs(x)) {
x = max;
}
}
return x;
}
public float ResolveYCollision(Box b, float y) {
if (b.Max.X <= Min.X || b.Min.X >= Max.X) {
return y;
}
if (b.Max.Z <= Min.Z || b.Min.Z >= Max.Z) {
return y;
}
if ((y > 0) && (Center.Y <= b.Center.Y)) {
float max = b.Min.Y - Max.Y;
if (Math.Abs(max) < Math.Abs(y)) {
y = max;
}
}
if ((y < 0) && (Center.Y >= b.Center.Y)) {
float max = b.Max.Y - Min.Y;
if (Math.Abs(max) < Math.Abs(y)) {
y = max;
}
}
return y;
}
public float ResolveZCollision(Box b, float z) {
if (b.Max.X <= Min.X || b.Min.X >= Max.X) {
return z;
}
if (b.Max.Y <= Min.Y || b.Min.Y >= Max.Y) {
return z;
}
if ((z > 0) && (Center.Z <= b.Center.Z)) {
float max = b.Min.Z - Max.Z;
if (Math.Abs(max) < Math.Abs(z)) {
z = max;
}
}
if ((z < 0) && (Center.Z >= b.Center.Z)) {
float max = b.Max.Z - Min.Z;
if (Math.Abs(max) < Math.Abs(z)) {
z = max;
}
}
return z;
}
public Vector3 ResolveCollision(Box b, Vector3 mov) {
float x = ResolveXCollision(b, mov.X);
Box xb = b.Moved(new Vector3(x, 0, 0));
float y = ResolveYCollision(xb, mov.Y);
Box yb = xb.Moved(new Vector3(0, y, 0));
float z = ResolveZCollision(yb, mov.Z);
Box zb = yb.Moved(new Vector3(0, 0, z));
return new Vector3(x, y, z);
}
public Box Moved(Vector3 movement) => new Box(min + movement, max + movement);