I made a hitbox module, not as good as something like raycastv4 but its slightly easier to use than making all of those attachments
I use close range for this (melee weapons)
to use this just put any part into the function :Start with the callback with damage, heal, whatever, raycastparams and settings (settings in the script)
CODE:
local function len(Table)
local counter = 0
for _, v in pairs(Table) do
counter =counter + 1
end
return counter
end
local module = {}
module.RunningHitboxes = {}
function module:Start(
hitbox:Instance,callback,params:RaycastParams,
Settings:{["IsSphere?"]:boolean,
["AcctuallRendering?"]:boolean,
["Radius"]:number,["Size"]:Vector3,
["Pos"]:CFrame|Vector3,
["Ofset?"]:Vector3,
["PartForOfset?"]:Instance,
["db"]:number}
)
--settings perams explained:
--IsSphere? is for if the hitbox should detect in a box shape or Sphere shape, If not put into settings it will default as False
--AcctuallRendering? if true the hitbox pos and size will be the same as the hitbox(:Instance sent as first peramater) defaults as False
--Raduis is the Spheres size if it is rendered as sphere. Not needed if IsSphere is false
--Size is the size of the hitbox in a Vector3
--Pos is either the position:Vector3 of the Sphere or the CFrame of the box --SPECIFIC POSITION NOT OFSET
--db is the amount of time between each individual player hit. if negative/nonexistant the cooldown is inf without waiting
--PartForOfset is the part for the ofset
--Ofset the ofset for the part needing ofset
if not self.RunningHitboxes[hitbox] then
print("loaded hitbox",self.RunningHitboxes,hitbox)
self.RunningHitboxes[hitbox] = {["settings"] = {}}
end
self.RunningHitboxes[hitbox]["callback"] = callback
self.RunningHitboxes[hitbox]["params"] = params
self.RunningHitboxes[hitbox]["settings"] = Settings
self.RunningHitboxes[hitbox]["Hitdb"] = {}
self.ToggleAppropeatleyRS()
end
function module:CreateHitbox(hitboxPart:Instance)
print("depreceated")
return hitboxPart
end
function module:Stop(hitbox:Instance)
if self.RunningHitboxes[hitbox] then
self.RunningHitboxes[hitbox] = nil
end
self.ToggleAppropeatleyRS()
end
local RSrunning = false
local RSconnection = nil
function module.ToggleAppropeatleyRS()
if len(module.RunningHitboxes) < 1 then-- it is 0
if RSrunning then
module.StopRS()
end
else--it is not 0 (eg 1-10000)
if not RSrunning then
module.StartRS()
end
end
end
function module.StopRS()
RSrunning = false
print("Stopping RS",len(module.RunningHitboxes))
RSconnection:Disconnect()
end
function module.StartRS()
RSrunning = true
print("Starting RS",len(module.RunningHitboxes))
RSconnection = game["Run Service"].RenderStepped:Connect(module.RunServiceFrame)
end
--[[
Settings:{["IsSphere?"]:boolean,
["AcctuallRendering?"]:boolean,
["Radius"]:number,["Size"]:Vector3,
["Pos"]:CFrame|Vector3,
["Ofset?"]:Vector3,
["PartForOfset?"]:Instance,
["db"]:number}
]]
function module.RunServiceFrame()
if len(module.RunningHitboxes) < 1 then warn("RunningTable smaller than 1") return end
for i,v in module.RunningHitboxes do
if not i then warn("hitbox doesnt exist??") continue end
if not i:IsA("BasePart") then warn("hitbox is not a basepart") continue end
local settings = v.settings
if len(settings) == 0 then
warn("PlayerNote: STOP FLICKING SN:no settings????..(hitboxParent: "..i.Parent.Name..",hitboxParentParent: "..i.Parent.Parent.Name..")")
continue
end
if not game.Players.LocalPlayer.Character:FindFirstChild("Ragdolled") then module:Stop(v.hitbox) return end
if game.Players.LocalPlayer.Character:FindFirstChild("Ragdolled").Value then module:Stop(v.hitbox) return end
if settings["AcctuallRendering?"] then
settings["Pos"] = i.CFrame
settings["Size"] = i.Size
end
if settings["PartForOfset?"] then
local ofsetPos = settings["PartForOfset?"].CFrame
local ofset = (typeof(settings["Ofset?"]) == "CFrame" and settings["Ofset?"] or CFrame.new(settings["Ofset?"]))
--print(Vector3.new(ofset),ofsetPos,ofsetPos * Vector3.new(ofset))
local newCFrame = ofsetPos * ofset
settings["Pos"] = newCFrame
end
if not settings["Pos"] then
local warnstring = "PlayerNote: how SN:no pos?? (hitboxParent: "..i.Parent.Name..",hitboxParentParent: "..i.Parent.Parent.Name..") "
for i,v in settings do
warnstring = warnstring.." "..i.. " : ".. tostring(v)
end
warn(warnstring)
continue end
local partsFound = {}
if settings["IsSphere?"] then
local Pos = (typeof(settings["Pos"])) == "Vector3" and settings["Pos"] or settings["Pos"].Position
partsFound = workspace:GetPartBoundsInRadius(Pos, settings["Radius"], v["params"])
else
local Pos = (typeof(settings["Pos"])) == "CFrame" and settings["Pos"] or CFrame.new(settings["Pos"])
partsFound = workspace:GetPartBoundsInBox(Pos, settings["Size"], v["params"])
end
local Hit_HumFound:{[BasePart]:Humanoid} = {}
local detectedHumanoid = false
for _,part in partsFound do
local hum = part.Parent:FindFirstChild("Humanoid")
if not hum then continue end
detectedHumanoid = true
if Hit_HumFound[hum] then continue end
local waiting = true
if v["Hitdb"][hum] then
if not settings["db"] then continue end
if settings["db"] < 0 then continue end
local now = tick()
local stored = v["Hitdb"][hum]
local difference = (now - stored)
print(difference)
if difference >= settings["db"] then
waiting = false
v["Hitdb"][hum] = nil
end
else
waiting = false
end
if waiting then continue end
Hit_HumFound[hum] = part
v["Hitdb"][hum] = tick()
end
if game.ReplicatedStorage.Settings_preferences.HitboxesEnabled.Value then --REMOVE THIS YALL IF YOU DONT GOT THIS BOOLVALUE
local hitboxview = Instance.new("Part")
--print(len(Hit_HumFound))
hitboxview.BrickColor = (not detectedHumanoid and BrickColor.new("Bright red")) or BrickColor.new("Bright green")--if hit its green otherwise red
hitboxview.Anchored = true
hitboxview.CanCollide = false
hitboxview.CanQuery = false
hitboxview.CanTouch = false
hitboxview.CastShadow = false
hitboxview.Size = (settings["IsSphere?"] and Vector3.new(settings.Radius,settings.Radius,settings.Radius) or settings.Size)--if issphere its a sphere otherwise not
hitboxview.CFrame = (typeof(settings["Pos"])) == "CFrame" and settings["Pos"] or CFrame.new(settings["Pos"])
hitboxview.Shape = (settings["IsSphere?"] and Enum.PartType.Ball or Enum.PartType.Block)--if IsSphere then ball else block
hitboxview.Transparency = 0
hitboxview.Material = Enum.Material.ForceField
--if detectedHumanoid then
-- --hitboxview.Size = hitboxview.Size + Vector3.new(.2,.2,.2)
-- hitboxview.Material = Enum.Material.SmoothPlastic
-- hitboxview.Transparency = .6
--end
hitboxview.Parent = workspace.Clutter
game.Debris:AddItem(hitboxview,2)
end
for HitHum,HitPart in Hit_HumFound do
v["callback"](HitPart,HitHum)
end
end
end
print("Hitboxes required SEP?")
--if callback then
-- callback(HitPart,HitHum)--base hit callback
--end
return module
This is an example of usage
--this example makes the part Specified the hitbox,
local callback = function(HitPart:Part,HitHum:Humanoid)
HitHum:TakeDamage(10)
end
RequiredModule:Start(Workspace.Part,callback,raycastparams.new(),{["AcctuallRendering?"] = true ["db"] = -1})
--this example makes the hitbox an ofset to the characters torso
local callback = function(HitPart:Part,HitHum:Humanoid)
HitHum:TakeDamage(10)
end
RequiredModule:Start(Workspace.Part,callback,raycastparams.new(),{["Size"] = Vector3.new(5,5,5), ["Ofset?"] = CFrame.new(0,0,-3),["PartForOfset?"] = char.HumanoidRootPart,["db"] = -1})
task.Wait(10)
RequiredModule:Stop(Workspace.Part)
--btw since these both use the same Workspace.Part, they will both override each other (or it will completely break idk