When I use the passed Direction variable in Start() it doesn’t work properly unless you manually type it out even though the Direction variable is the same thing as the LookVector. It also causes problems in the DebugVisible function.
I’ve tried to print out the direction and Lookvector and they’re mostly the same so I’m not sure why it’s giving different results
The Code
local HitboxHandler = {VisibleDebug = false}
runservice = game:GetService("RunService")
local heart
local debugparts
function DebugVisible(blockcast, Hitbox, origin, direction)
if blockcast then
debugparts.Anchored = true
debugparts.CanCollide = false
debugparts.Size = Hitbox
debugparts.Position = origin.Position + origin.CFrame.LookVector * blockcast.Distance
debugparts.Transparency = .5
debugparts.Orientation = origin.Orientation
debugparts.BrickColor = BrickColor.Red()
debugparts.Parent = workspace
else
debugparts.Anchored = true
debugparts.CanCollide = false
debugparts.Size = Hitbox
debugparts.Position = origin.Position + origin.CFrame.LookVector*8
debugparts.Transparency = .5
debugparts.Orientation = origin.Orientation
debugparts.BrickColor = BrickColor.Blue()
debugparts.Parent = workspace
end
end
function HitboxHandler.Start(character, origin, hitbox, direction)
local rayparams = RaycastParams.new()
debugparts = Instance.new("Part")
rayparams.FilterType = Enum.RaycastFilterType.Exclude
rayparams.FilterDescendantsInstances = {character, debugparts}
heart = runservice.Heartbeat:Connect(function()
local blockcast = workspace:Blockcast(origin.CFrame, hitbox, origin.CFrame.LookVector*8, rayparams)
print("Direction ", direction, "And LookVector ", origin.CFrame.LookVector*8)
DebugVisible(blockcast, hitbox, origin, direction)
if blockcast then
print(blockcast.Instance)
else
print("No Part")
end
end)
end
function HitboxHandler.Stop()
heart:Disconnect()
debugparts:Destroy()
end
return HitboxHandler
Hitbox is just a simple vector3 to make everything compact and cleaner. I’m calling HitboxHandler from a local script with UserInput
The Code
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character.Humanoid
local uips = game:GetService("UserInputService")
local HitboxHandler = require(game.ReplicatedStorage.HitboxHandler)
local hitbox = Vector3.new(10,10,10)
uips.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
HitboxHandler.Start(character, character.Torso, hitbox, character.Torso.CFrame.LookVector*8)
end
end)
Thanks for that. What’s going on here is that you’re passing the direction properly but only when the character first spawns, so you’re only reading from the torso.CFrame.LookVector one time, and thus it’s never updated.
So suppose the character.Torso.CFrame.LookVector is Vector3(0, 0, -1) (which is the default identity CFrame lookvector) as a variable direction which is what you’re doing now. When the character moves, because you really just created a shallow copy of the LookVector as your direction variable, the value of direction is still Vector3(0, 0, -1) while the orientation of the torso might actually be roughly Vector3(0.7071, 0, 0.7071), so that is why you are getting an old direction.
What you need to do is read from the torso itself each frame.
So your final hitboxHandler.Start function would look like this:
function HitboxHandler.Start(character, origin, hitbox) -- we can omit direction here
local rayparams = RaycastParams.new()
debugparts = Instance.new("Part")
rayparams.FilterType = Enum.RaycastFilterType.Exclude
rayparams.FilterDescendantsInstances = {character, debugparts}
heart = runservice.Heartbeat:Connect(function()
local direction = origin.CFrame.LookVector * 8 -- we can calculate the direction here
local blockcast = workspace:Blockcast(origin.CFrame, hitbox, direction, rayparams)
print("Direction ", direction, "And LookVector ", origin.CFrame.LookVector*8)
DebugVisible(blockcast, hitbox, origin, direction)
if blockcast then
print(blockcast.Instance)
else
print("No Part")
end
end)
end
I see, that would work but how would I keep the versatility of being able to choose direction without setting it in the hitboxhandler itself since that would only allow you to have one choice
It would really depend on what your needs are for this system, are you going to have more than 1 hitbox, and is each hitbox going to have its own additional arbitrary rotation relative to it?
I’d like it to be modular and easily modifiable so I can use it for projectiles and melee. The other uses for direction could be something else other than lookvector. I need the direction so I can be able to change things easily, similar to other opensource hitboxes.
Well in your case, I think there are two options that would allow for a good balance between modularity and organization and such. I’ve only very briefly worked with FastCast, so I’m kind of going in from an outsider perspective.
1- You could either store a list of each part and the corresponding directional vector and magnitude, which might look something like this:
local directionInfo = {}
local characters = {}
function module.AddHitbox(character, origin, hitbox, direction) -- direction would be in local space relative to `origin` and would be constant relative to origin, similar to the LookVector but could be any arbitrary rotation
directionInfo[character] = {
direction = direction;
origin = origin;
size = hitbox;
}
table.insert(characters, character)
end
function module.OnHit(attacker, target)
-- handle when attacker hits target
end
local heartbeat
function module.Start()
heartbeat = runService.Heartbeat:Connect(function()
for _, character in characters do
local info = directionInfo[character]
if not info then continue end
local direction = info.direction
local origin = info.origin
local size = info.size
local directionForBlockcast = origin.CFrame:VectorToWorldSpace(direction)
local blockcast = workspace:Blockcast(origin.CFrame, info.size, rayParams) -- rayParams would have to be defined somewhere
if not blockcast then continue end
module.OnHit(character, blockcast.Hit)
end
end)
end
function module.Stop(character) -- "deactivates" a hitbox
directionInfo[character] = nil
table.remove(characters, table.find(characters, character))
end
2- you could stray away from this structure and look into Lua’s implementation of object oriented programming. Each hitbox would be its own “object”, and the hitbox object could contain any number of properties including the ones that were included in point 1. This would allow a hitbox to be more easily modified in the case of wanting to change properties at any point. In my opinion it allows for making expandability and the modification of objects from other sources easier.
There are a bunch of tutorials on here about it but this one is pretty good: