Skip to content
This repository has been archived by the owner on Nov 25, 2024. It is now read-only.

Commit

Permalink
Finally, working collision
Browse files Browse the repository at this point in the history
  • Loading branch information
Oliver-makes-code committed Nov 18, 2023
1 parent f5c3e47 commit f9028bd
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 35 deletions.
34 changes: 34 additions & 0 deletions Client/Rendering/Camera.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using GlmSharp;
using Voxel.Common.Collision;
using Voxel.Common.World;

namespace Voxel.Client.Rendering;

Expand Down Expand Up @@ -29,4 +32,35 @@ public class Camera {
/// Far clip plane of camera.
/// </summary>
public float farClip = 500;

public void MoveAndSlide(VoxelWorld world, dvec3 delta) {
for (int i = 0; i < 3; i++) {
if (delta == dvec3.Zero)
break;
delta = MoveAndSlideSingle(world, delta);
}
}

private dvec3 MoveAndSlideSingle(VoxelWorld world, dvec3 delta) {
const double CollisionBackoff = 1/128d;

double minPercent = new AABB(
position - new dvec3(0.3, 1.6, 0.3),
position + new dvec3(0.3, 0.2, 0.3)
).MoveAndSlide(world, delta, out var normal);

position += delta * minPercent;

if (minPercent < 1 && minPercent >= 0)
position += delta.NormalizedSafe * -CollisionBackoff;

double remaining = 1 - minPercent;
var project = new dvec3(0);

for (int i = 0; i < 3; i++)
if (Math.Abs(normal[i]) < 0.0000001)
project[i] = delta[i] * remaining;

return project;
}
}
8 changes: 3 additions & 5 deletions Client/Rendering/GameRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,9 @@ public override void Render(double delta) {
MainCamera.rotationVec.x = MathF.PI/2;

inputDir = MainCamera.rotationY * (vec3)inputDir;

MainCamera.position += new AABB(
MainCamera.position - new dvec3(0.3, 1.6, 0.3),
MainCamera.position + new dvec3(0.3, 0.2, 0.3)
).MoveAndSlide(VoxelClient.Instance.world!, inputDir / 4);
inputDir /= 4;

MainCamera.MoveAndSlide(VoxelClient.Instance.world!, inputDir);

CameraStateManager.SetToCamera(MainCamera);

Expand Down
72 changes: 42 additions & 30 deletions Common/Collision/AABB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,26 @@ public AABB(dvec3 a, dvec3 b) {
Math.Max(a.z, b.z)
);
}

[Pure]
public bool CollidesWith(BlockView world) {
var min = (ivec3)dvec3.Floor(Min);
var max = (ivec3)dvec3.Ceiling(Max);
foreach (var pos in Iteration.Cubic(min, max))
if (world.GetBlock(pos).IsSolidBlock)
return true;
return false;
}

[Pure]
public dvec3 MoveAndSlide(BlockView world, dvec3 delta) {
public double MoveAndSlide(BlockView world, dvec3 delta, out dvec3 normal) {
normal = new();

var min = (ivec3)dvec3.Floor(Min) - new ivec3(1,1,1);
var max = (ivec3)dvec3.Ceiling(Max) + new ivec3(1,1,1);

double minPercent = 1;

foreach (var pos in Iteration.Cubic(min, max))
if (world.GetBlock(pos).IsSolidBlock)
delta = GetMinimumDistance(new(pos, pos + new ivec3(1, 1, 1)), delta);
if (world.GetBlock(pos).IsSolidBlock) {
double slide = SlideWith(new(pos, pos + new ivec3(1)), delta, out var locNormal);
if (slide >= minPercent)
continue;
normal = locNormal;
minPercent = slide;
}

return delta;
return minPercent;
}

private bool CollidesWith(AABB other)
Expand All @@ -52,21 +51,17 @@ private bool CollidesWith(AABB other)
Min.z < other.Max.z &&
Max.z > other.Min.z;

private dvec3 GetMinimumDistance(AABB other, dvec3 delta) {
private bool CollidesWithOnAxis(AABB other, int axis)
=> Min[axis] < other.Max[axis] &&
Max[axis] > other.Min[axis];

public double SlideWith(AABB other, dvec3 delta, out dvec3 normal) {
normal = new();
if (!new AABB(Min + delta, Max + delta).CollidesWith(other))
return delta;

double d = GetMinimumDistanceForAxis(other, delta);
return 1;

if (d != 0)
Console.WriteLine(d);

return delta;
}

// TODO: fix method name
private double GetMinimumDistanceForAxis(AABB other, dvec3 delta) {
double length = delta.Length;

if (length == 0)
return 0;

Expand All @@ -79,8 +74,14 @@ private double GetMinimumDistanceForAxis(AABB other, dvec3 delta) {
enter[i] = other.Min[i] - Max[i];
exit[i] = other.Max[i] - Min[i];
} else if (delta[i] < 0) {
exit[i] = other.Min[i] - Max[i];
enter[i] = other.Max[i] - Min[i];
enter[i] = Min[i] - other.Max[i];
exit[i] = Max[i] - other.Min[i];
} else if (CollidesWithOnAxis(other, i)) {
enter[i] = 0;
exit[i] = double.MaxValue;
} else {
enter[i] = double.MaxValue;
exit[i] = -1;
}
}

Expand All @@ -89,12 +90,23 @@ private double GetMinimumDistanceForAxis(AABB other, dvec3 delta) {
exitDiv = exit / length;

double
enterDivMax = enterDiv.Max(),
enterDivMax = double.MinValue,
exitDivMin = exitDiv.Min();

int maxDir = 0;

for (int i = 0; i < 3; i++) {
if (enterDivMax >= enterDiv[i])
continue;
enterDivMax = enterDiv[i];
maxDir = i;
}

normal[maxDir] = -Math.Sign(delta[maxDir]);

if (enterDivMax > exitDivMin)
return 0;
if (enterDivMax > 1 || exitDivMin > 1)
if (enterDivMax > 1)
return 0;
if (enterDivMax < 0 || exitDivMin < 0)
return 0;
Expand Down
1 change: 1 addition & 0 deletions Test/TestRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class TestRegistry {
private static List<TestSuite> testSuites = new();
public static void RegisterTests() {
testSuites.Add(new BlockViewSuite());
testSuites.Add(new AABBSuite());
}

public static void Main() {
Expand Down
25 changes: 25 additions & 0 deletions Test/Tests/AABBSuite.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using GlmSharp;
using Voxel.Common.Collision;

namespace Voxel.Test.Tests;

public class AABBSuite : TestSuite {

protected override Dictionary<string, Test> DefineTests()
=> new() {
["K.K. Slider"] = () => {
var boxA = new AABB(
new(0),
new(1)
);
var boxB = new AABB(
new(2, 0, 0),
new(3, 1, 1)
);

Assert(boxA.SlideWith(boxB, new(2, 0, 0), out _) == 0.5, "Sliding 1x1x1 cubes on one axis");
}
};
}

0 comments on commit f9028bd

Please sign in to comment.