Projectile HitBox is Bugged

Hi Im trying to make Mirana’s ability from the anime called “Dota:Dragon’s Blood”. Im trying to make rain of arrows. But theres a problem. Hitbox. Idk why but it glitches and stops at the air. Please help me

local folder = game:GetService(“ReplicatedStorage”)

local function ar()

script.Parent.CFrame = CFrame.lookAt(script.Parent.Position, workspace.TARRR.Position)
local pos = Vector3.new(script.Parent.CFrame.X+math.random(-20,20),script.Parent.CFrame.Y+math.random(-10,10),script.Parent.Position.Z)
local arrow = folder.Folder.Arrow:Clone()

arrow.Parent = script.Parent
game.Debris:AddItem(arrow,5)
arrow.CFrame = CFrame.new(pos)
local newforce = Instance.new("BodyForce")
newforce.Force = Vector3.new(0,workspace.Gravity * arrow:GetMass(), 0)
newforce.Parent = arrow

local bodyvel = Instance.new("BodyVelocity")
bodyvel.Parent = arrow
bodyvel.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
bodyvel.Velocity = (workspace.TARRR.Position - script.Parent.Position).unit * 110

arrow.Orientation = script.Parent.Orientation


arrow.HitBox.Touched:Connect(function(hit)
	
	if hit.Name~="Arrow" and hit.Name~= "HitBox" and hit:IsA("Part") then
		print(hit)
		arrow.Anchored=true
	end
end)

end
task.delay(0.1,function()
while wait(0.1) do
ar()
ar()
end
end)

1 Like

Not an answer to your problem, but it is more efficient to put the .Touched event on the HitBox. That way you don’t make a new connection every time.

Problems in your current code

  1. BodyForce cancels gravity completely
    newforce.Force = Vector3.new(0,workspace.Gravity * arrow:GetMass(), 0)
    That makes the arrow float forever. Gravity never pulls it down.

  2. BodyVelocity forces constant motion
    It keeps applying the same velocity every frame, so there’s no “falling” curve — just a flat, constant-speed line. When Roblox’s physics engine pauses or body forces conflict, it looks like it froze.

  3. Too many arrows too fast
    while wait(0.1) do ar(); ar(); end creates 20 arrows per second. Roblox throttles physics when too many parts exist, especially if each arrow has multiple BodyMovers.

  4. Arrow may touch itself immediately
    That can trigger .Touched instantly and anchor it right away.

Fixed version.

local folder = game:GetService("ReplicatedStorage")
local target = workspace:WaitForChild("TARRR")

local function fireArrow()
	local arrow = folder.Folder.Arrow:Clone()
	arrow.Parent = script.Parent
	arrow.Anchored = false
	arrow.CanCollide = true
	
	-- random offset spawn position
	local pos = script.Parent.Position + Vector3.new(math.random(-20,20), math.random(-10,10), 0)
	arrow.CFrame = CFrame.lookAt(pos, target.Position)
	
	-- apply impulse (preferred over BodyVelocity)
	local dir = (target.Position - pos).Unit
	local speed = 110
	
	arrow:ApplyImpulse(dir * speed * arrow:GetMass())
	
	game.Debris:AddItem(arrow, 5)
	
	-- hit detection
	local hitbox = arrow:FindFirstChild("HitBox")
	if hitbox then
		hitbox.Anchored = false
		hitbox.Touched:Connect(function(hit)
			if hit:IsDescendantOf(arrow) then return end
			if hit:IsA("Part") and hit.Name ~= "Arrow" and hit.Name ~= "HitBox" then
				print("Hit:", hit)
				arrow.Anchored = true
				arrow:ClearAllChildren() -- optional: stop physics forces
			end
		end)
	end
end

-- fire continuously
task.spawn(function()
	while task.wait(0.2) do
		fireArrow()
	end
end)

I would also recommend using raycasts and tweening them to the hit position instead of physics, as they are way more performant at scale.


local folder = game:GetService("ReplicatedStorage")
local target = workspace:WaitForChild("TARRR")
local tweenService = game:GetService("TweenService")

-- Config
local MAX_DISTANCE = 500
local ARROW_SPEED = 110 -- studs per second

local function fireArrow()
	local arrow = folder.Folder.Arrow:Clone()
	arrow.Parent = script.Parent
	arrow.Anchored = true
	arrow.CanCollide = false
	
	-- random offset
	local startPos = script.Parent.Position + Vector3.new(math.random(-20,20), math.random(-10,10), 0)
	local dir = (target.Position - startPos).Unit
	
	arrow.CFrame = CFrame.lookAt(startPos, startPos + dir)
	
	-- Raycast setup
	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {script.Parent, arrow}
	rayParams.FilterType = Enum.RaycastFilterType.Exclude
	rayParams.IgnoreWater = true
	
	local result = workspace:Raycast(startPos, dir * MAX_DISTANCE, rayParams)
	
	local hitPos = result and result.Position or (startPos + dir * MAX_DISTANCE)
	local distance = (hitPos - startPos).Magnitude
	local travelTime = distance / ARROW_SPEED
	
	-- Tween arrow to hit position
	local tween = tweenService:Create(
		arrow,
		TweenInfo.new(travelTime, Enum.EasingStyle.Linear),
		{CFrame = CFrame.lookAt(hitPos, hitPos + dir)}
	)
	tween:Play()
	
	tween.Completed:Connect(function()
		if result then
			-- Hit something
			print("Hit:", result.Instance)
			local hit = result.Instance
			
			-- Optionally "stick" arrow at hit
			local stuck = folder.Folder.Arrow:Clone()
			stuck.Anchored = true
			stuck.CFrame = CFrame.lookAt(hitPos, hitPos + dir)
			stuck.Parent = hit
			
			game.Debris:AddItem(stuck, 5)
		end
		
		arrow:Destroy()
	end)
end

-- Fire continuously
task.spawn(function()
	while task.wait(0.2) do
		fireArrow()
	end
end)

isnt it what i already did?

arrow.HitBox.Touched:Connect(function(hit)

if hit.Name~="Arrow" and hit.Name~= "HitBox" and hit:IsA("Part") then
	print(hit)
1 Like


Thats why i used velocity and bodyforce. I wanted arrows to shoot from math random positions of script.Parent and just fly toward the target. Now the arrows dont shoot toward the target, now they shoot at the target

Touched and TouchEnded is a horrible way to go for projectiles, it is not intended to use for fast physics contact, hence why Raycasting is a thing.

1 Like

my bad this will make in a square area give the rain affect with raycast and then tween on a hit to that position instead having to rely on slow physics

local folder = game:GetService("ReplicatedStorage")
local tweenService = game:GetService("TweenService")

-- ⚙️ Config
local AREA_CENTER = Vector3.new(0, 100, 0) -- Center point of rain zone (above ground)
local AREA_SIZE = Vector2.new(200, 200)    -- Width/Depth of rain zone
local ARROW_SPEED = 180                    -- Studs per second (controls fall speed)
local FALL_ANGLE = 15                      -- Degrees, tilt from vertical
local MAX_DISTANCE = 300                   -- How far arrows fall before disappearing
local FIRE_INTERVAL = 0.05                 -- How often to spawn arrows (smaller = denser rain)

-- 🔥 Arrow spawn function
local function spawnArrow()
	local arrow = folder.Folder.Arrow:Clone()
	arrow.Parent = workspace
	arrow.Anchored = true
	arrow.CanCollide = false

	-- Pick a random spawn position within area
	local x = AREA_CENTER.X + math.random(-AREA_SIZE.X/2, AREA_SIZE.X/2)
	local z = AREA_CENTER.Z + math.random(-AREA_SIZE.Y/2, AREA_SIZE.Y/2)
	local startPos = Vector3.new(x, AREA_CENTER.Y, z)

	-- Calculate fall direction (15° forward tilt)
	local angle = math.rad(FALL_ANGLE)
	local forwardDir = Vector3.new(0, -math.cos(angle), math.sin(angle)) -- tilts slightly forward (Z+)
	forwardDir = forwardDir.Unit

	arrow.CFrame = CFrame.lookAt(startPos, startPos + forwardDir)

	-- Raycast to find where it would hit (e.g., ground or object)
	local rayParams = RaycastParams.new()
	rayParams.FilterType = Enum.RaycastFilterType.Exclude
	rayParams.FilterDescendantsInstances = {arrow}
	rayParams.IgnoreWater = true

	local result = workspace:Raycast(startPos, forwardDir * MAX_DISTANCE, rayParams)
	local hitPos = result and result.Position or (startPos + forwardDir * MAX_DISTANCE)
	local distance = (hitPos - startPos).Magnitude
	local travelTime = distance / ARROW_SPEED

	-- Tween arrow toward the ground
	local tween = tweenService:Create(
		arrow,
		TweenInfo.new(travelTime, Enum.EasingStyle.Linear),
		{CFrame = CFrame.lookAt(hitPos, hitPos + forwardDir)}
	)
	tween:Play()

	tween.Completed:Connect(function()
		if result then
			-- Create "stuck" arrow
			local stuck = folder.Folder.Arrow:Clone()
			stuck.Anchored = true
			stuck.CFrame = CFrame.lookAt(hitPos, hitPos + forwardDir)
			stuck.Parent = result.Instance
			game.Debris:AddItem(stuck, 5)
		end
		arrow:Destroy()
	end)
end

-- 🌧️ Continuous arrow rain loop
task.spawn(function()
	while task.wait(FIRE_INTERVAL) do
		spawnArrow()
	end
end)

lol, get off this forum if you are going to ctrl c ctrl v chatgpt code

3 Likes


ummm…

local AREA_SIZE = Vector2.new(200, 200)    -- Width/Depth of rain zone

this is the X ans Z axis size of the rectangle the arrows rain from its prob too big for u or u make it more dense by increasing the spawnrate by

local FIRE_INTERVAL = 0.05                 -- How often to spawn arrows (smaller = denser rain)

if u want u can modify it to use a parts size and position bounds instead of a coded vector choice is yours

AREA_CENTER = Vector3.new(0, 100, 0) is the center position in ur world of where rectangle is

it keeps working very weird. Like i want arrows go from script.Parent, not from the sky, and shoot toward the target, not at it. The second script u sent was just a rain of arrows from the sky, that cant be moved. I need arrows shoot from script.Parent, bc when i will script it as an ability, then i will need to spawn block(its gonna be a magical sphere when particles) that will shoot with arrows

Its using code position and size if u say script.Parent is the part it need to rain from size and position wise u can change these 2 lines

local AREA_CENTER = script.Parent.Position --Vector3.new(0, 100, 0) -- Center point of rain zone (above ground)
local AREA_SIZE = Vector2.new(script.Parent.Size.X, script.Parent.Size.Z)   --Vector2.new(200, 200)    -- Width/Depth of rain zone

its coded that it rains down by 15 deg angle if u want it to change the angle also change the degrees with

local FALL_ANGLE = 15                      -- Degrees, tilt from vertical

do u want it to shoot from the angle the part its shooting from is facing towards ?


green is the source and red is the target. I need arrows shoot toward the target.

how i refference the red part the green is script.Parent where is the red ?

is it workspace.TARRR ?

TARRR is red and Script.Parent is green

local folder = game:GetService("ReplicatedStorage")
local tweenService = game:GetService("TweenService")

-- 🟩 Source (spawning area)
local green = script.Parent
-- 🟥 Target (impact area)
local red = workspace.TARRR

-- ⚙️ Config
local ARROW_SPEED = 180
local FIRE_INTERVAL = 0.05
local MAX_DISTANCE = 1000 -- safety distance for long tweens

-- 🧮 Utility: get a random position within a part’s bounds
local function getRandomPointInPart(part)
	local size = part.Size
	local cf = part.CFrame

	local offset = Vector3.new(
		math.random(-size.X/2, size.X/2),
		math.random(-size.Y/2, size.Y/2),
		math.random(-size.Z/2, size.Z/2)
	)

	return (cf.Position + cf:VectorToWorldSpace(offset))
end

-- 🏹 Spawn function
local function spawnArrow()
	local arrow = folder.Folder.Arrow:Clone()
	arrow.Parent = workspace
	arrow.Anchored = true
	arrow.CanCollide = false

	-- Random spawn (green) and target (red)
	local startPos = getRandomPointInPart(green)
	local endPos = getRandomPointInPart(red)

	local dir = (endPos - startPos).Unit
	local distance = (endPos - startPos).Magnitude
	local travelTime = distance / ARROW_SPEED

	arrow.CFrame = CFrame.lookAt(startPos, startPos + dir)

	-- Raycast for realism (to stop early if hitting something mid-air)
	local rayParams = RaycastParams.new()
	rayParams.FilterType = Enum.RaycastFilterType.Exclude
	rayParams.FilterDescendantsInstances = {arrow, green}
	rayParams.IgnoreWater = true
	local result = workspace:Raycast(startPos, dir * distance, rayParams)

	if result then
		endPos = result.Position
		travelTime = (endPos - startPos).Magnitude / ARROW_SPEED
	end

	-- Tween from green → red
	local tween = tweenService:Create(
		arrow,
		TweenInfo.new(travelTime, Enum.EasingStyle.Linear),
		{CFrame = CFrame.lookAt(endPos, endPos + dir)}
	)
	tween:Play()

	tween.Completed:Connect(function()
		if result then
			-- Stick arrow into hit surface
			local stuck = folder.Folder.Arrow:Clone()
			stuck.Anchored = true
			stuck.CFrame = CFrame.lookAt(endPos, endPos + dir)
			stuck.Parent = result.Instance
			game.Debris:AddItem(stuck, 5)
		end
		arrow:Destroy()
	end)
end

-- 🌧️ Continuous rain
task.spawn(function()
	while task.wait(FIRE_INTERVAL) do
		spawnArrow()
	end
end)

should use green parts position and bounds the spawn the arrows spread inside of it volume random and rain towards the red part and spread to those size and bounds

Bro Used Chatgpt…

Dude why didnt you just code it yourself

Bump Jumpscare Too but i dont care thats just LAME MAN…

2 Likes