60 lines
2.3 KiB
C#
Raw Normal View History

using System;
using TrueCraft.API;
using TrueCraft.Core.Logic;
using TrueCraft.Core.Logic.Blocks;
using TrueCraft.API.Logic;
namespace TrueCraft.Client
{
/// <summary>
/// Efficient ray caster that can cast a ray into a voxel map
/// and return the voxel that it intersects with.
/// </summary>
public static class VoxelCast
{
// Thanks to http://gamedev.stackexchange.com/questions/47362/cast-ray-to-select-block-in-voxel-game
public static Tuple<Coordinates3D, BlockFace> Cast(ReadOnlyWorld world,
2015-09-27 17:21:23 -04:00
Ray ray, IBlockRepository repository, int posmax, int negmax)
{
2015-09-27 17:14:04 -04:00
// TODO: There are more efficient ways of doing this, fwiw
2015-09-27 17:21:23 -04:00
double min = negmax * 2;
2015-09-27 17:14:04 -04:00
var pick = -Coordinates3D.One;
var face = BlockFace.PositiveY;
2015-09-27 17:21:23 -04:00
for (int x = -posmax; x <= posmax; x++)
{
2015-09-27 17:21:23 -04:00
for (int y = -negmax; y <= posmax; y++)
{
2015-09-27 17:21:23 -04:00
for (int z = -posmax; z <= posmax; z++)
{
2015-09-27 17:14:04 -04:00
var coords = (Coordinates3D)(new Vector3(x, y, z) + ray.Position).Round();
if (!world.IsValidPosition(coords))
continue;
var id = world.GetBlockID(coords);
if (id != 0)
{
var provider = repository.GetBlockProvider(id);
var box = provider.InteractiveBoundingBox;
2015-09-27 17:14:04 -04:00
if (box != null)
{
BlockFace _face;
var distance = ray.Intersects(box.Value.OffsetBy(coords), out _face);
2015-09-27 17:14:04 -04:00
if (distance != null && distance.Value < min)
{
min = distance.Value;
pick = coords;
face = _face;
2015-09-27 17:14:04 -04:00
}
}
}
}
}
}
2015-09-27 17:14:04 -04:00
if (pick == -Coordinates3D.One)
return null;
return new Tuple<Coordinates3D, BlockFace>(pick, face);
}
}
}