Drew DeVault 14aa3ce07a Add "InteractiveBoundingBox" to IBlockProvider
This is used to determine the bounding box for interaction in the client
(the ray that's cast from your camera interacts with it to determine the
highlighted block).

TODO: Make it work better with metadata.

This commit also fixes one of the issues with snow: ref #194
2015-10-02 08:15:29 -04:00

60 lines
2.3 KiB
C#

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,
Ray ray, IBlockRepository repository, int posmax, int negmax)
{
// TODO: There are more efficient ways of doing this, fwiw
double min = negmax * 2;
var pick = -Coordinates3D.One;
var face = BlockFace.PositiveY;
for (int x = -posmax; x <= posmax; x++)
{
for (int y = -negmax; y <= posmax; y++)
{
for (int z = -posmax; z <= posmax; z++)
{
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;
if (box != null)
{
BlockFace _face;
var distance = ray.Intersects(box.Value.OffsetBy(coords), out _face);
if (distance != null && distance.Value < min)
{
min = distance.Value;
pick = coords;
face = _face;
}
}
}
}
}
}
if (pick == -Coordinates3D.One)
return null;
return new Tuple<Coordinates3D, BlockFace>(pick, face);
}
}
}