Skip to content

Instantly share code, notes, and snippets.

@evaera
Last active July 8, 2023 06:22
Show Gist options
  • Save evaera/735f23c67c2c173cfed2955f357b03a3 to your computer and use it in GitHub Desktop.
Save evaera/735f23c67c2c173cfed2955f357b03a3 to your computer and use it in GitHub Desktop.
Roblox Arrow Adornment

Roblox Arrows for 3D Visualizations

ezgif-3-d70ddeaac0db

Installation

Quick and dirty. You probably want this for debugging, so just slap this function in wherever you want it.

Minified and full versions are included below. Pick one!

Usage

Call the arrow function to create an arrow in workspace. If you call the function twice with the same name, the second call will replace & reuse the original. This works well when calling from within a Heartbeat event listener to update the arrow every frame.

  • arrow(name: string, from: Vector3, to: Vector3) -> Creates an arrow between from and to
  • arrow(name: string, point: Vector3) -> Creates an arrow pointing at point
  • arrow(name: string, cframe: CFrame) -> Creates an arrow with its point at the CFrame position facing the CFrame LookVector
  • arrow(name: string, part: BasePart) -> Arrow represents the Part's CFrame
  • arrow(name: string, fromPart: BasePart, toPart: BasePart) -> Arrow between the two parts
local function arrow(b,c,d,e,f)e=e or BrickColor.random().Color;f=f or 1;if typeof(c)=="Instance"then if c:IsA("BasePart")then c=c.CFrame elseif c:IsA("Attachment")then c=c.WorldCFrame end;if d~=nil then c=c.p end end;if typeof(d)=="Instance"then if d:IsA("BasePart")then d=d.Position elseif d:IsA("Attachment")then d=d.WorldPosition end end;if typeof(c)=="CFrame"and d==nil then local g=c.lookVector;d=c.p;c=d+g*-10 end;if d==nil then d=c;c=d+Vector3.new(0,10,0)end;assert(typeof(c)=="Vector3"and typeof(d)=="Vector3","Passed parameters are of invalid types")local h=workspace:FindFirstChild("Arrows")or Instance.new("Folder")h.Name="Arrows"h.Parent=workspace;local i=h:FindFirstChild(b.."_shaft")or Instance.new("CylinderHandleAdornment")i.Height=(c-d).magnitude-2;i.CFrame=CFrame.lookAt((c+d)/2-(d-c).unit*1,d)if i.Parent==nil then i.Name=b.."_shaft"i.Color3=e;i.Radius=0.15;i.Adornee=workspace.Terrain;i.Transparency=0;i.Radius=0.15*f;i.Transparency=0;i.AlwaysOnTop=true;i.ZIndex=5-math.ceil(f)end;i.Parent=h;local j=h:FindFirstChild(b.."_head")or Instance.new("ConeHandleAdornment")f=f==1 and 1 or 1.4;if j.Parent==nil then j.Name=b.."_head"j.Color3=e;j.Radius=0.5*f;j.Transparency=0;j.Adornee=workspace.Terrain;j.Height=2*f;j.AlwaysOnTop=true;j.ZIndex=5-math.ceil(f)end;j.CFrame=CFrame.lookAt((CFrame.lookAt(d,c)*CFrame.new(0,0,-2-(f-1)/2)).p,d)j.Parent=h;if f==1 then arrow(b.."_backdrop",c,d,Color3.new(0,0,0),2)end end
local function arrow(name, from, to, color, scale)
color = color or BrickColor.random().Color
scale = scale or 1
if typeof(from) == "Instance" then
if from:IsA("BasePart") then
from = from.CFrame
elseif from:IsA("Attachment") then
from = from.WorldCFrame
end
if to ~= nil then
from = from.p
end
end
if typeof(to) == "Instance" then
if to:IsA("BasePart") then
to = to.Position
elseif to:IsA("Attachment") then
to = to.WorldPosition
end
end
if typeof(from) == "CFrame" and to == nil then
local look = from.lookVector
to = from.p
from = to + (look * -10)
end
if to == nil then
to = from
from = to + Vector3.new(0, 10, 0)
end
assert(typeof(from) == "Vector3" and typeof(to) == "Vector3", "Passed parameters are of invalid types")
local container = workspace:FindFirstChild("Arrows") or Instance.new("Folder")
container.Name = "Arrows"
container.Parent = workspace
local shaft = container:FindFirstChild(name .. "_shaft") or Instance.new("CylinderHandleAdornment")
shaft.Height = (from - to).magnitude - 2
shaft.CFrame = CFrame.lookAt(
((from + to)/2) - ((to - from).unit * 1),
to
)
if shaft.Parent == nil then
shaft.Name = name .. "_shaft"
shaft.Color3 = color
shaft.Radius = 0.15
shaft.Adornee = workspace.Terrain
shaft.Transparency = 0
shaft.Radius = 0.15 * scale
shaft.Transparency = 0
shaft.AlwaysOnTop = true
shaft.ZIndex = 5 - math.ceil(scale)
end
shaft.Parent = container
local pointy = container:FindFirstChild(name .. "_head") or Instance.new("ConeHandleAdornment")
scale = scale == 1 and 1 or 1.4
if pointy.Parent == nil then
pointy.Name = name .. "_head"
pointy.Color3 = color
pointy.Radius = 0.5 * scale
pointy.Transparency = 0
pointy.Adornee = workspace.Terrain
pointy.Height = 2 * scale
pointy.AlwaysOnTop = true
pointy.ZIndex = 5 - math.ceil(scale)
end
pointy.CFrame = CFrame.lookAt((CFrame.lookAt(to, from) * CFrame.new(0, 0, -2 - ((scale-1)/2))).p, to)
pointy.Parent = container
if scale == 1 then
arrow(name .. "_backdrop", from, to, Color3.new(0, 0, 0), 2)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment