BlockCast Position Problem

  1. What do you want to achieve?

I’m trying to fix a system I’m making

  1. What is the issue?

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

Typing out LookVector Positioning Below

Using the Direction Variable caused this Below

What is hitbox in your case? Is it a part welded to the character or similar?

Or if you could show how you’re calling HitboxHandler.Start that could be helpful as well.

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
1 Like

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: