For my Bleach RPG, I am creating a Cero beam attack that will launch out and damage enemies. It's pretty much a basic cylinder mesh that launches forward (like a Kamehameha from Dragon Ball), and will damage whatever enemy character is within the beam. I managed to get it to work, but I feel that there is a better way to do this.
Here's what I did so far...
function clamp(n, bound) if n > bound then return bound elseif n < -bound then return -bound end return n end _G.ClosestPointOnPart = function(point, part) local p = part.CFrame:vectorToObjectSpace(point-part.Position) local hz = part.Size/2 local pointOnPart = Vector3.new(clamp(p.x, hz.x), clamp(p.y, hz.y), clamp(p.z, hz.z)) return part.Position + part.CFrame:vectorToWorldSpace(pointOnPart) end --[[ CheckCylinderCollisions returns a table of every enemy within the cylinder. table targets - Variable contains every enemy model we want to check for collisions Vector3 base - The start position of the cylinder int dist - How long the cylinder is (not used) Vector3 lv - The direction the cylinder is pointing int max_dist - The radius of the cylinder ]] _G.CheckCylinderCollisions = function(targets,base,dist,lv,max_dist) local new_targets = {} for i,v in pairs(targets) do local h = v:findFirstChild("Humanoid") if h and h.Health > 0 then local pos = _G.ClosestPointOnPart(base,v.Torso) --local dist2 = (base-pos).magnitude --local A = CFrame.new(base,pos).lookVector --local B = lv --*dist --local d = math.sqrt(dist2^2-A:Dot(B)^2) local p1 = (base-pos) local p2 = (p1:Dot(lv))*lv local d = (p1-p2).magnitude if d <= max_dist then local tab = {Target = v, Position = pos} table.insert(new_targets,tab) end end end return new_targets end
The more efficient way to do this is to use raycasting, cast a ray from the intial position the the end position. After that use FindPartOnRay() to return the hit parts.