CastVisuals is a very simple module that allows you to easily visualise your cast operations in any given WorldRoot (ie: Workspace or WorldModel).
API is simple; every function takes the same parameters as their WorldRoot counterparts. All functions are type-safe to help avoid issues.
local CastVisual = CastVisuals.new(Color3.new(1,0,0), workspace) -- both args are optional, Color is Color3.new(0, 0, 1) by default and WorldRoot is Workspace by default.
CastVisual:Raycast(Origin: Vector3, Direction: Vector3, CastParams)
task.wait(1)
CastVisual:Spherecast(Origin: Vector3, Radius: number, Direction: Vector3, CastParams)
task.wait(1)
CastVisual:Blockcast(Origin: CFrame, Size: Vector3, Direction: Vector3, CastParams)
task.wait(5)
CastVisual:Hide() -- hides the visualisation (note: also hides if cast hits nothing)
Visuals can be customised too, there is a list of config options at the top of the script.
This is really great, but it would be better if you could see the visual even if the cast didn’t hit. Often I’m not sure I’m actually casting correctly!
This is a neat module, though to save a bit of performance in our games maybe simply make it return the RaycastResult, this way we don’t need to make another raycast for the actual functionality.
Another performance thingy (I like performance in modules lol) is to only create new Instances when they are being used, but don’t destroy them when they aren’t being used since that is also not great. Because right now you’re creating all instances when you construct the class. One might not always use all three of the raycasting methods in the same Visuals object and that creates useless instances.
Hello. First off, thank you for your useful module.
However after some use as a debug tool, I have found an oversight for the Blockcast visualizer.
The Box Adornment that you use inherits from the Parent’s CFrame rotation, which does not match with the actual result of the blockcast. In your visualizer, the Box visual is oriented along the Parent’s direction, which should not be the case, and should instead be oriented based on the provided CFrame.
Here’s the fixed function:
function CastVisualiser:Blockcast(CF: CFrame, Size: Vector3, Direction: Vector3, RaycastParameters: RaycastParams?)
local self: CastVisualiserPrivate = self
local Cast = self.WorldRoot:Blockcast(CF, Size, Direction, RaycastParameters)
if not Cast then
self:Hide()
return
end
local FinalPos = CF.Position + (Direction.Unit * Cast.Distance)
self.CastOriginPart.CFrame = CFrame.lookAt(CF.Position, FinalPos)
self.LineVisual.Length = Cast.Distance - CONE_HEIGHT
self.ConeVisual.CFrame = CFrame.new(0, 0, -Cast.Distance)
self.BoxVisual.CFrame = CFrame.new(0,0, -Cast.Distance) * self.BoxVisual.Parent.CFrame.Rotation:Inverse() * CF.Rotation
self.BoxVisual.Size = Size
self.BoxVisual.Visible = true
self.SphereVisual.Visible = false
self.CastOriginPart.Parent = self.WorldRoot:FindFirstChild("Terrain") or self.WorldRoot
end
This allows the box visualizer’s orientation to be fully independent from the box’s parent’s cframe orientation, the same way an actual BlockCast behaves (CFrame not oriented based on the cast direction).
I’ve tested it, and it now matches the actual result of a blockcast.