Nub Cast [Simple Block Hitboxes] [Bezier Hitboxes] [V2.0]

INTRODUCTION

This module works very simply, but it can be useful in several cases, such as simple projectiles.

I’ve seen some similar options here on the developer forum, however, they didn’t meet all my needs so I decided to make one myself.

Why use this?

This module allows you to make almost completely customizable hitboxes in addition to a different way from the conventional way of making projectiles

ACCESS

You can get the module by downloading it from Roblox Marketplace

API

NubCast.new(Params : OverlapParams, Debug : Boolean)

create a new caster where you can add an OverlapParams and set debug to true or false

NubCast:Cast(origin : Vector3, target : Vector3, size : number, segments : number, travelTime : number) -- ActiveCast

cast a new hitbox with the passed parameters

ActiveCast.Stop()

stop the current cast

ActiveCast.Finished -- RBXScriptSignal

The event is triggered when the hitbox collides with something or travel time has been exceeded

ActiveCast.Hitted -- RBXScriptSignal

The event is triggered when the hitbox collides with something. passes a table with overlap params result

EXAMPLES

Creating a new hitbox

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local NubCast = require(ReplicatedStorage.NubCast)

local Overlap = OverlapParams.new()
Overlap.FilterDescendantsInstances = {}
Overlap.FilterType = Enum.RaycastFilterType.Exclude

local Caster = NubCast.new(Overlap, true)

local StartPosition = Vector3.new(0, 30, 0) -- Hitboxes Origin
local TargetPosition = Vector3.new(0, -10, 0) -- Hitboxes Target Position

local Segments = 5 -- Number of hitboxes created in a cast
local Size = 5 -- Hitbox Size
local TravelTime = 1 -- Hitbox cast time

local ActiveCast = Caster:Cast(StartPosition, TargetPosition, Size, Segments, TravelTime)

Basically creating a hitbox is very simple and if you set debug to true when creating the hitbox you will be able to view it

Adding a projectile

First let’s create a folder in the workspace so the hitbox doesn’t detect the projectiles

image

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local NubCast = require(ReplicatedStorage.NubCast)

local Overlap = OverlapParams.new()
Overlap.FilterDescendantsInstances = {workspace.Projectiles}
Overlap.FilterType = Enum.RaycastFilterType.Exclude

local Caster = NubCast.new(Overlap, true)

local StartPosition = Vector3.new(0, 30, 0) -- Hitboxes Origin
local TargetPosition = Vector3.new(0, -10, 0) -- Hitboxes Target Position

local Segments = 10 -- Number of hitboxes created in a cast
local Size = 5 -- Hitbox Size
local TravelTime = 1 -- Hitbox cast time

local Projectile = Instance.new("Part")
Projectile.Size = Vector3.one * 2
Projectile.Anchored = true
Projectile.Position = StartPosition
Projectile.Shape = "Ball"
Projectile.Color = Color3.fromRGB(88, 88, 88)
Projectile.Material = Enum.Material.Metal
Projectile.Parent = workspace.Projectiles

local TravelTween = game.TweenService:Create(
	Projectile,
	TweenInfo.new(TravelTime, Enum.EasingStyle.Linear),
	{Position = TargetPosition}
)

TravelTween:Play()

local ActiveCast = Caster:Cast(StartPosition, TargetPosition, Size, Segments, TravelTime)

ActiveCast.Hitted:Connect(function()
	TravelTween:Pause()
end)

ActiveCast.Finished:Connect(function()
	Projectile:Destroy()
end)

Adding a projectile is very simple, you just need to create it and make it move with interpolation or some other method.

Just ensuring that it will pause when it hits a target to ensure that the projectile will not continue moving.

TIPS

It is recommended not to move projectiles on the server.

The module is not recommended for EVERY case as there may be some inaccuracy or loss of memory.

15 Likes

Module with the same purpose as fastcast, but better.

4 Likes

NEW MODULE BEZIER UPDATE

Now in addition to linear hitboxes you can create hitboxes with curves!

The way to create the curves is very simple, you just need to pass an argument with the bezier points.

API

NubCast:BezierCast(origin : Vector3, target : Vector3, points : any, size : number, segments : number, travelTime : number) -- ActiveCast

EXAMPLES

Creating a new hitbox

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local NubCast = require(ReplicatedStorage.NubCast)

local Overlap = OverlapParams.new()
Overlap.FilterDescendantsInstances = {workspace}
Overlap.FilterType = Enum.RaycastFilterType.Exclude

local Caster = NubCast.new(Overlap, true)

local StartPosition = Vector3.new(0, 30, 0) -- Hitboxes Origin
local TargetPosition = Vector3.new(0, 0, 0) -- Hitboxes Target Position

local Segments = 5 -- Number of hitboxes created in a cast
local Size = 5 -- Hitbox Size
local TravelTime = 1 -- Hitbox cast time

local BezierPoints = {
	Vector3.new(20, 10, 0)
}

local ActiveCast = Caster:BezierCast(StartPosition, TargetPosition, BezierPoints, Size, Segments, TravelTime)

with this we will have this result

Adding a projectile

let’s use the projectiles folder in the workspace so the hitbox ignores projectiles

As in this case the projectile has bezier curves we cannot just use tween service so let’s do a loop to update the position

In this case we will use a simple quad bezier function

local function Lerp(a, b, t)
	return a + (b - a) * t
end

local function QuadBezier(P1, P2, P3, t)
	local L1 = Lerp(P1, P2, t)
	local L2 = Lerp(P2, P3, t)
	
	local QuadBezier = Lerp(L1, L2, t)
	
	return QuadBezier
end

Now we create the projectile and make it move in a for loop

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local NubCast = require(ReplicatedStorage.NubCast)

local Overlap = OverlapParams.new()
Overlap.FilterDescendantsInstances = {workspace.Projectiles}
Overlap.FilterType = Enum.RaycastFilterType.Exclude

local Caster = NubCast.new(Overlap, true)

local StartPosition = Vector3.new(0, 30, 0) -- Hitboxes Origin
local TargetPosition = Vector3.new(0, 0, 0) -- Hitboxes Target Position

local Segments = 10 -- Number of hitboxes created in a cast
local Size = 1 -- Hitbox Size
local TravelTime = 1 -- Hitbox cast time

local BezierPoints = {
	Vector3.new(20, 10, 0)
}

local function Lerp(a, b, t)
	return a + (b - a) * t
end

local function QuadBezier(P1, P2, P3, t)
	local L1 = Lerp(P1, P2, t)
	local L2 = Lerp(P2, P3, t)
	
	local QuadBezier = Lerp(L1, L2, t)
	
	return QuadBezier
end
local Moving = true

local Projectile = Instance.new("Part")
Projectile.Size = Vector3.one * 2
Projectile.Anchored = true
Projectile.Position = StartPosition
Projectile.Shape = "Ball"
Projectile.Color = Color3.fromRGB(88, 88, 88)
Projectile.Material = Enum.Material.Metal
Projectile.Parent = workspace.Projectiles

task.spawn(function()
	for Index = 0, 1, .1 do
		if not Moving then return end

		local CurrentPosition = QuadBezier(StartPosition, BezierPoints[1], TargetPosition, Index)

		Projectile.Position = CurrentPosition

		task.wait(.1)
	end
end)

local ActiveCast = Caster:BezierCast(StartPosition, TargetPosition, BezierPoints, Size, Segments, TravelTime)

ActiveCast.Finished:Connect(function()
	Moving = false

	game.Debris:AddItem(Projectile, 1)
end)

and we have this result

As you can see, the hitbox is not that accurate because unlike raycast hitboxes, this one works using overlap, which does not allow us to obtain the exact position of the hit, only the part that collided.

However, with a new edit I made to the module, if there is something in front of the hitbox, the hitted event will send a raycast Result

ActiveCast.Hitted:Connect(function(OverlapResult, RaycastResult)
	task.wait()

	if RaycastResult then
		Projectile.Position = RaycastResult.Position
	end
end)

ActiveCast.Finished:Connect(function(OverlapResult, RaycastResult)
	Moving = false

	game.Debris:AddItem(Projectile, 1)
end)

TIPS

the hitted event is fired before the finished event.

IT IS RECOMMENDED NOT TO MOVE PROJECTILES ON THE SERVER.

4 Likes

Very useful module, the bezier update saved me. thx akanub

2 Likes

Amazing module! My only current issue is how the “RaycastResult” property doesn’t hit/return at times with the Bezier function, and it doesn’t hit/return at all for the normal Cast function.