Rotating a Part Towards a Position By Using Number

I would like to make a projectile that rotates towards a Position lets say for example 5 degrees each second. I am using a Heartbeat connection and setting the CFrame with the DeltaTime.

The problem is frankly I have no idea how to make it rotate towards the Position using a set degree every second. I know how to use CFrame.lookat, however I don’t know how to use the degree and given CFrame to create a CFrame that is 5 degrees closer to the Position.

This is part of a larger system that calculates projectiles and more specifically hitboxes. The important projectile motion code is down below.

type AbstractHitboxType = {
	Piercing:number?,
	--PiercingConfiguration:{
	--	PierceWallMode:PierceMode?, -- default melee IgnoreOnHit, projectile and raycast are StopOnHit
	--	PierceHumanoidMode:PierceMode?, -- default CountOnHit
	--}?,
	RememberHitLength:number?,

	VisualHitbox:boolean?,
	FilterDescendantsInstances:{Instance}?
}

-- abstract projectile hitbox function
local function ProjectileHitboxAbstract(HitProjectileValues:HitProjectileValuesType,FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid)->(),HitCharacter:{},Params:OverlapParams):(RBXScriptConnection,BasePart)
	local RunServiceConnection:RBXScriptConnection
	local CurrentTime = 0

	local ProjectilePart:BasePart

	if HitProjectileValues.ProjectileInstance then
		ProjectilePart = HitProjectileValues.ProjectileInstance:Clone()
	else
		ProjectilePart = Instance.new("Part")

		ProjectilePart.Color = HitProjectileValues.ProjectileColor3::Color3
		ProjectilePart.Shape = HitProjectileValues.ProjectilePartType::Enum.PartType
		ProjectilePart.Material = HitProjectileValues.ProjectileMaterial::Enum.Material
		ProjectilePart.Transparency = HitProjectileValues.ProjectileTransparency::number
	end

	ProjectilePart.Size = HitProjectileValues.Size
	ProjectilePart.Name = "Projectile"
	ProjectilePart.Anchored = true
	ProjectilePart.CanCollide = false
	ProjectilePart.CanQuery = false
	ProjectilePart.CanTouch = false

	local ProjectileCFrame = CFrame.new(HitProjectileValues.Position,HitProjectileValues.Position + HitProjectileValues.Direction)
	ProjectilePart:PivotTo(ProjectileCFrame)

	local ForwardVector:Vector3 = ProjectilePart.CFrame.LookVector
	local Gravity = -Vector3.new(0,HitProjectileValues.GravityAmpilfier::number * workspace.Gravity,0)
	local Velocity:Vector3 = ForwardVector * HitProjectileValues.Magnitude::number

	RunServiceConnection = RunService.Heartbeat:Connect(function(DeltaTime:number)
		CurrentTime += DeltaTime

		if CurrentTime >= HitProjectileValues.Lifetime then
			RunServiceConnection:Disconnect()
			ProjectilePart:Destroy()

			if HitProjectileValues.Explosion then
				-- explosion code
			end
		end

		local NewGravity = Gravity * CurrentTime
		local NewAddedVelocity = HitProjectileValues.AddedVelocity::Vector3 * CurrentTime

		ForwardVector = ProjectilePart.CFrame.LookVector

		Velocity = ForwardVector * HitProjectileValues.Magnitude::number
		Velocity += NewAddedVelocity

		ProjectilePart.Position += 
			(Velocity * DeltaTime)
			+ (NewGravity * DeltaTime) 

		-- TODO: finish projectile targetting
		do			
			if HitProjectileValues.Target then
				local TargetPosition:Vector3

				if typeof(HitProjectileValues.Target) == "Instance" then
					if HitProjectileValues.Target:IsA("BasePart") then
						TargetPosition = HitProjectileValues.Target.Position
					end
				elseif typeof(HitProjectileValues.Target) == "Vector3" then
					TargetPosition = HitProjectileValues.Target
				end

				local LookAtCFrame = CFrame.lookAt(ProjectilePart.Position,TargetPosition)
				local RotationLookAtX,RotationLookAtY,RotationLookAtZ = LookAtCFrame:ToEulerAnglesXYZ()
				print(math.deg(RotationLookAtX),math.deg(RotationLookAtY),math.deg(RotationLookAtZ))

				local p = Instance.new("Part")
				p.Size = Vector3.new(0.5,0.5,5)
				p.CFrame = LookAtCFrame
				p.Anchored = true
				p.Parent = workspace

				ProjectilePart.CFrame = ProjectilePart:GetPivot() 
				--ProjectilePart.Rotation += NormalizedLookAtVector * (HitProjectileValues.RotationalVelocity::Vector3).Magnitude * DeltaTime
			else
				ProjectilePart.CFrame = ProjectilePart:GetPivot() * CFrame.Angles(
					math.rad(HitProjectileValues.RotationalVelocity.X) * DeltaTime,
					math.rad(HitProjectileValues.RotationalVelocity.Y) * DeltaTime,
					math.rad(HitProjectileValues.RotationalVelocity.Z) * DeltaTime
				)
			end
		end
	end)

	ProjectilePart.Parent = workspace

	return RunServiceConnection,ProjectilePart
end

export type HitProjectileValuesType = {
	-- required
	Position:Vector3, -- at position
	Direction:Vector3, -- look at position
	Size:Vector3, -- size of projectile
	Lifetime:number, -- lifetime of projectile
	
	-- not required
	ProjectileColor3:Color3?, -- color3 projectile
	ProjectilePartType:Enum.PartType?, -- shape of the projectile
	ProjectileTransparency:number?,
	ProjectileMaterial:Enum.Material?,
	
	ProjectileInstance:BasePart?, -- if passed it ignores all other params and uses ProjectileInstance, may override ProjectileColor3 and ProjectilePartType

	Explosion:{ -- explosion when projectile hits a wall or reaches piercing max
		ExplosionColor3:Color3?, -- color3 of explosion
		ExplosionSize:Vector3?, -- size of explosion
		ExplosionPartType:Enum.PartType?, -- PartType of explosion
		ExplosionLifetime:number?,
		FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid)->()?, -- calls on hit
		VisualParticleValues:ParticleModule.ParticlesValues?, -- particles that play when explosion
	}?, 
	
	Magnitude:number?, -- default 0, start "speed" of projectile
	GravityAmpilfier:number?, -- GravityAmpilifer * workspace.Gravity, decides how much "control" gravity has over the projectile
	AddedVelocity:Vector3?, -- how much velocity is added to the velocity every second
	RotationalVelocity:Vector3?, -- how much rotation is added every second
	Target:(BasePart|Vector3)?, -- if the projectile rotates towards a part or vector3, the Magnitude of RotationVelocity will be used to rotate towards
}&AbstractHitboxType

-- it does the projectile stuff what else do you want
function module:HitProjectile(HitProjectileValues:HitProjectileValuesType,FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid?)->()):(RBXScriptConnection,BasePart)
	if HitProjectileValues.Magnitude == nil then HitProjectileValues.Magnitude = 1 end
	if HitProjectileValues.VisualHitbox == nil then HitProjectileValues.VisualHitbox = true end
	if HitProjectileValues.Piercing == nil then HitProjectileValues.Piercing = 1 end
	if HitProjectileValues.FilterDescendantsInstances == nil then HitProjectileValues.FilterDescendantsInstances = {} end
	if HitProjectileValues.GravityAmpilfier == nil then HitProjectileValues.GravityAmpilfier = 0 end
	if HitProjectileValues.RotationalVelocity == nil then HitProjectileValues.RotationalVelocity = Vector3.new(0,0,0) end
	if HitProjectileValues.AddedVelocity == nil then HitProjectileValues.AddedVelocity = Vector3.new(0,0,0) end

	if HitProjectileValues.ProjectileColor3 == nil then HitProjectileValues.ProjectileColor3 = Color3.fromRGB(255, 255, 255) end
	if HitProjectileValues.ProjectilePartType == nil then HitProjectileValues.ProjectilePartType = Enum.PartType.Ball end
	if HitProjectileValues.ProjectileTransparency == nil then HitProjectileValues.ProjectileTransparency = 0 end
	if HitProjectileValues.ProjectileMaterial == nil then HitProjectileValues.ProjectileMaterial = Enum.Material.SmoothPlastic end

	if HitProjectileValues.Explosion then
		if HitProjectileValues.Explosion.ExplosionSize == nil then HitProjectileValues.Explosion.ExplosionSize = HitProjectileValues.Size * 1.35 end
		if HitProjectileValues.Explosion.ExplosionColor3 == nil then HitProjectileValues.Explosion.ExplosionColor3 = HitProjectileValues.ProjectileColor3 end
		if HitProjectileValues.Explosion.ExplosionPartType == nil then HitProjectileValues.Explosion.ExplosionPartType = HitProjectileValues.ProjectilePartType end
	end

	local RunServiceConnection,ProjectilePart
	local CurrentTime = 0
	local HitCharacters = {}
	local Params = OverlapParams.new()

	Params.FilterDescendantsInstances = HitProjectileValues.FilterDescendantsInstances::{Instance}

	RunServiceConnection,ProjectilePart = ProjectileHitboxAbstract(HitProjectileValues,FunctionOnHit,HitCharacters,Params)

	return RunServiceConnection,ProjectilePart
end

Please note I do not want to use Tweens for setting the projectile’s CFrame.

1 Like

Thinking of turning the CFrame.lookAt rotation into a Vector and doing some dot products and math on it then turning it back into a CFrame using CFrame.Angles()

I think a lerp will help in your case.

  1. find angle between two vectors
  2. calculate alpha by (RadiansPerSecond/AngleFromStep1)
  3. Use the alpha to CurrentCF:Lerp(LookAtCF,alpha * delta) where delta is the time in seconds since the last time we tried to set a new CFrame.
3 Likes

Basically what @Jeremylin080114 said, but in code:

type AbstractHitboxType = {
	Piercing:number?,
	--PiercingConfiguration:{
	--	PierceWallMode:PierceMode?, -- default melee IgnoreOnHit, projectile and raycast are StopOnHit
	--	PierceHumanoidMode:PierceMode?, -- default CountOnHit
	--}?,
	RememberHitLength:number?,

	VisualHitbox:boolean?,
	FilterDescendantsInstances:{Instance}?
}

-- abstract projectile hitbox function
local function ProjectileHitboxAbstract(HitProjectileValues:HitProjectileValuesType,FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid)->(),HitCharacter:{},Params:OverlapParams):(RBXScriptConnection,BasePart)
	local RunServiceConnection:RBXScriptConnection
	local CurrentTime = 0

	local ProjectilePart:BasePart

	if HitProjectileValues.ProjectileInstance then
		ProjectilePart = HitProjectileValues.ProjectileInstance:Clone()
	else
		ProjectilePart = Instance.new("Part")

		ProjectilePart.Color = HitProjectileValues.ProjectileColor3::Color3
		ProjectilePart.Shape = HitProjectileValues.ProjectilePartType::Enum.PartType
		ProjectilePart.Material = HitProjectileValues.ProjectileMaterial::Enum.Material
		ProjectilePart.Transparency = HitProjectileValues.ProjectileTransparency::number
	end

	ProjectilePart.Size = HitProjectileValues.Size
	ProjectilePart.Name = "Projectile"
	ProjectilePart.Anchored = true
	ProjectilePart.CanCollide = false
	ProjectilePart.CanQuery = false
	ProjectilePart.CanTouch = false

	local ProjectileCFrame = CFrame.new(HitProjectileValues.Position,HitProjectileValues.Position + HitProjectileValues.Direction)
	ProjectilePart:PivotTo(ProjectileCFrame)

	local ForwardVector:Vector3 = ProjectilePart.CFrame.LookVector
	local Gravity = -Vector3.new(0,HitProjectileValues.GravityAmpilfier::number * workspace.Gravity,0)
	local Velocity:Vector3 = ForwardVector * HitProjectileValues.Magnitude::number

	RunServiceConnection = RunService.Heartbeat:Connect(function(DeltaTime:number)
		CurrentTime += DeltaTime

		if CurrentTime >= HitProjectileValues.Lifetime then
			RunServiceConnection:Disconnect()
			ProjectilePart:Destroy()

			if HitProjectileValues.Explosion then
				-- explosion code
			end
		end

		local NewGravity = Gravity * CurrentTime
		local NewAddedVelocity = HitProjectileValues.AddedVelocity::Vector3 * CurrentTime

		ForwardVector = ProjectilePart.CFrame.LookVector

		Velocity = ForwardVector * HitProjectileValues.Magnitude::number
		Velocity += NewAddedVelocity

		ProjectilePart.Position += 
			(Velocity * DeltaTime)
			+ (NewGravity * DeltaTime) 

		-- TODO: finish projectile targetting
		do			
			if HitProjectileValues.Target then
				local TargetPosition:Vector3

				if typeof(HitProjectileValues.Target) == "Instance" then
					if HitProjectileValues.Target:IsA("BasePart") then
						TargetPosition = HitProjectileValues.Target.Position
					end
				elseif typeof(HitProjectileValues.Target) == "Vector3" then
					TargetPosition = HitProjectileValues.Target
				end

				if TargetPosition then
					local targetCF = CFrame.lookAt(ProjectilePart.Position, TargetPosition)

					local angleBetween = math.acos(math.clamp(ProjectilePart.CFrame.LookVector:Dot(targetCF.LookVector), -1, 1))

					local rotationSpeedRad = math.rad(HitProjectileValues.RotationalVelocity.Magnitude)
					local alpha = angleBetween > 0 and math.min(1, rotationSpeedRad * DeltaTime / angleBetween) or 1

					ProjectilePart.CFrame = ProjectilePart.CFrame:Lerp(targetCF, alpha)
				end
			else
				ProjectilePart.CFrame = ProjectilePart:GetPivot() * CFrame.Angles(
					math.rad(HitProjectileValues.RotationalVelocity.X) * DeltaTime,
					math.rad(HitProjectileValues.RotationalVelocity.Y) * DeltaTime,
					math.rad(HitProjectileValues.RotationalVelocity.Z) * DeltaTime
				)
			end
		end
	end)

	ProjectilePart.Parent = workspace

	return RunServiceConnection,ProjectilePart
end

export type HitProjectileValuesType = {
	-- required
	Position:Vector3, -- at position
	Direction:Vector3, -- look at position
	Size:Vector3, -- size of projectile
	Lifetime:number, -- lifetime of projectile

	-- not required
	ProjectileColor3:Color3?, -- color3 projectile
	ProjectilePartType:Enum.PartType?, -- shape of the projectile
	ProjectileTransparency:number?,
	ProjectileMaterial:Enum.Material?,

	ProjectileInstance:BasePart?, -- if passed it ignores all other params and uses ProjectileInstance, may override ProjectileColor3 and ProjectilePartType

	Explosion:{ -- explosion when projectile hits a wall or reaches piercing max
		ExplosionColor3:Color3?, -- color3 of explosion
		ExplosionSize:Vector3?, -- size of explosion
		ExplosionPartType:Enum.PartType?, -- PartType of explosion
		ExplosionLifetime:number?,
		FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid)->()?, -- calls on hit
		VisualParticleValues:ParticleModule.ParticlesValues?, -- particles that play when explosion
	}?, 

	Magnitude:number?, -- default 0, start "speed" of projectile
	GravityAmpilfier:number?, -- GravityAmpilifer * workspace.Gravity, decides how much "control" gravity has over the projectile
	AddedVelocity:Vector3?, -- how much velocity is added to the velocity every second
	RotationalVelocity:Vector3?, -- how much rotation is added every second
	Target:(BasePart|Vector3)?, -- if the projectile rotates towards a part or vector3, the Magnitude of RotationVelocity will be used to rotate towards
}&AbstractHitboxType

-- it does the projectile stuff what else do you want
function module:HitProjectile(HitProjectileValues:HitProjectileValuesType,FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid?)->()):(RBXScriptConnection,BasePart)
	if HitProjectileValues.Magnitude == nil then HitProjectileValues.Magnitude = 1 end
	if HitProjectileValues.VisualHitbox == nil then HitProjectileValues.VisualHitbox = true end
	if HitProjectileValues.Piercing == nil then HitProjectileValues.Piercing = 1 end
	if HitProjectileValues.FilterDescendantsInstances == nil then HitProjectileValues.FilterDescendantsInstances = {} end
	if HitProjectileValues.GravityAmpilfier == nil then HitProjectileValues.GravityAmpilfier = 0 end
	if HitProjectileValues.RotationalVelocity == nil then HitProjectileValues.RotationalVelocity = Vector3.new(0,0,0) end
	if HitProjectileValues.AddedVelocity == nil then HitProjectileValues.AddedVelocity = Vector3.new(0,0,0) end

	if HitProjectileValues.ProjectileColor3 == nil then HitProjectileValues.ProjectileColor3 = Color3.fromRGB(255, 255, 255) end
	if HitProjectileValues.ProjectilePartType == nil then HitProjectileValues.ProjectilePartType = Enum.PartType.Ball end
	if HitProjectileValues.ProjectileTransparency == nil then HitProjectileValues.ProjectileTransparency = 0 end
	if HitProjectileValues.ProjectileMaterial == nil then HitProjectileValues.ProjectileMaterial = Enum.Material.SmoothPlastic end

	if HitProjectileValues.Explosion then
		if HitProjectileValues.Explosion.ExplosionSize == nil then HitProjectileValues.Explosion.ExplosionSize = HitProjectileValues.Size * 1.35 end
		if HitProjectileValues.Explosion.ExplosionColor3 == nil then HitProjectileValues.Explosion.ExplosionColor3 = HitProjectileValues.ProjectileColor3 end
		if HitProjectileValues.Explosion.ExplosionPartType == nil then HitProjectileValues.Explosion.ExplosionPartType = HitProjectileValues.ProjectilePartType end
	end

	local RunServiceConnection,ProjectilePart
	local CurrentTime = 0
	local HitCharacters = {}
	local Params = OverlapParams.new()

	Params.FilterDescendantsInstances = HitProjectileValues.FilterDescendantsInstances::{Instance}

	RunServiceConnection,ProjectilePart = ProjectileHitboxAbstract(HitProjectileValues,FunctionOnHit,HitCharacters,Params)

	return RunServiceConnection,ProjectilePart
end

Let me know if you have any issues or problems with this code. Also, for the rotation speed, I simply used the magnitude of HitProjectileValues.RotationalVelocity. Was it supposed to be like a per-axis type of thing?

1 Like

Thanks! I will try this.

I wanted to use the magnitude of HitProjectilesValues.RotationalVelocity

Final code I used is put down below.

type AbstractHitboxType = {
	Piercing:number?,
	--PiercingConfiguration:{
	--	PierceWallMode:PierceMode?, -- default melee IgnoreOnHit, projectile and raycast are StopOnHit
	--	PierceHumanoidMode:PierceMode?, -- default CountOnHit
	--}?,
	RememberHitLength:number?,

	VisualHitbox:boolean?,
	FilterDescendantsInstances:{Instance}?
}

-- abstract projectile hitbox function
local function ProjectileHitboxAbstract(HitProjectileValues:HitProjectileValuesType,FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid)->(),HitCharacter:{},Params:OverlapParams):(RBXScriptConnection,BasePart)
	local RunServiceConnection:RBXScriptConnection
	local CurrentTime = 0
	local ProjectilePart:BasePart

	if HitProjectileValues.ProjectileInstance then
		ProjectilePart = HitProjectileValues.ProjectileInstance:Clone()
	else
		ProjectilePart = Instance.new("Part")

		ProjectilePart.Color = HitProjectileValues.ProjectileColor3::Color3
		ProjectilePart.Shape = HitProjectileValues.ProjectilePartType::Enum.PartType
		ProjectilePart.Material = HitProjectileValues.ProjectileMaterial::Enum.Material
		ProjectilePart.Transparency = HitProjectileValues.ProjectileTransparency::number
	end

	ProjectilePart.Size = HitProjectileValues.Size
	ProjectilePart.Name = "Projectile"
	ProjectilePart.Anchored = true
	ProjectilePart.CanCollide = false
	ProjectilePart.CanQuery = false
	ProjectilePart.CanTouch = false

	local ProjectileCFrame = CFrame.new(HitProjectileValues.Position,HitProjectileValues.Position + HitProjectileValues.Direction)
	ProjectilePart:PivotTo(ProjectileCFrame)

	local ForwardVector:Vector3 = ProjectilePart.CFrame.LookVector
	local Gravity = -Vector3.new(0,HitProjectileValues.GravityAmpilfier::number * workspace.Gravity,0)
	local Velocity:Vector3 = ForwardVector * HitProjectileValues.Magnitude::number

	RunServiceConnection = RunService.Heartbeat:Connect(function(DeltaTime:number)
		CurrentTime += DeltaTime

		if CurrentTime >= HitProjectileValues.Lifetime then
			RunServiceConnection:Disconnect()
			ProjectilePart:Destroy()

			if HitProjectileValues.Explosion then
				-- explosion code
			end
		end
		
		local ProjectileCFrame = ProjectilePart:GetPivot()
		local NewGravity = Gravity * CurrentTime
		local NewAddedVelocity = HitProjectileValues.AddedVelocity::Vector3 * CurrentTime

		ForwardVector = ProjectilePart.CFrame.LookVector

		Velocity = ForwardVector * HitProjectileValues.Magnitude::number
		Velocity += NewAddedVelocity

		local RotationCFrame:CFrame = CFrame.new()
		
		do	
			if HitProjectileValues.Target then
				local TargetPosition:Vector3

				if typeof(HitProjectileValues.Target) == "Instance" then
					if HitProjectileValues.Target:IsA("BasePart") then
						TargetPosition = HitProjectileValues.Target.Position
					end
				elseif typeof(HitProjectileValues.Target) == "Vector3" then
					TargetPosition = HitProjectileValues.Target
				end

				if TargetPosition then
					local TargetCFrame = CFrame.lookAt(ProjectileCFrame.Position,TargetPosition).Rotation
					local AngleBetweenVectors = ProjectilePart.CFrame.LookVector:Angle(TargetCFrame.Position)
					local RotationSpeedInRadians = math.rad(HitProjectileValues.RotationalVelocity.Magnitude) * DeltaTime
					local Alpha = 1
					
					if RotationSpeedInRadians - AngleBetweenVectors <= 0 then 
						Alpha = RotationSpeedInRadians
					elseif RotationSpeedInRadians - AngleBetweenVectors > 0 then
						Alpha = RotationSpeedInRadians - AngleBetweenVectors
					end

					RotationCFrame = ProjectileCFrame.Rotation:Lerp(TargetCFrame,Alpha)
				end
			else
				RotationCFrame = ProjectileCFrame.Rotation * CFrame.Angles(
					math.rad(HitProjectileValues.RotationalVelocity.X) * DeltaTime,
					math.rad(HitProjectileValues.RotationalVelocity.Y) * DeltaTime,
					math.rad(HitProjectileValues.RotationalVelocity.Z) * DeltaTime
				)
			end
		end
		
		ProjectilePart:PivotTo(CFrame.new(
				ProjectilePart.Position  
				+ (Velocity * DeltaTime)
				+ (NewGravity * DeltaTime) 
			) * RotationCFrame
		)
	end)

	ProjectilePart.Parent = workspace

	return RunServiceConnection,ProjectilePart
end

export type HitProjectileValuesType = {
	-- required
	Position:Vector3, -- at position
	Direction:Vector3, -- look at position
	Size:Vector3, -- size of projectile
	Lifetime:number, -- lifetime of projectile
	
	-- not required
	ProjectileColor3:Color3?, -- color3 projectile
	ProjectilePartType:Enum.PartType?, -- shape of the projectile
	ProjectileTransparency:number?,
	ProjectileMaterial:Enum.Material?,
	
	ProjectileInstance:BasePart?, -- if passed it ignores all other params and uses ProjectileInstance, may override ProjectileColor3 and ProjectilePartType

	Explosion:{ -- explosion when projectile hits a wall or reaches piercing max
		ExplosionColor3:Color3?, -- color3 of explosion
		ExplosionSize:Vector3?, -- size of explosion
		ExplosionPartType:Enum.PartType?, -- PartType of explosion
		ExplosionLifetime:number?,
		FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid)->()?, -- calls on hit
		VisualParticleValues:ParticleModule.ParticlesValues?, -- particles that play when explosion
	}?, 
	
	Magnitude:number?, -- default 0, start "speed" of projectile
	GravityAmpilfier:number?, -- GravityAmpilifer * workspace.Gravity, decides how much "control" gravity has over the projectile
	AddedVelocity:Vector3?, -- how much velocity is added to the velocity every second
	RotationalVelocity:Vector3?, -- how much rotation is added every second
	Target:(BasePart|Vector3)?, -- if the projectile rotates towards a part or vector3, the Magnitude of RotationVelocity will be used to rotate towards
}&AbstractHitboxType

-- it does the projectile stuff what else do you want
function module:HitProjectile(HitProjectileValues:HitProjectileValuesType,FunctionOnHit:(HitProjectileValues:HitProjectileValuesType,ReceivingHumanoid:Humanoid?)->()):(RBXScriptConnection,BasePart)
	if HitProjectileValues.Magnitude == nil then HitProjectileValues.Magnitude = 1 end
	if HitProjectileValues.VisualHitbox == nil then HitProjectileValues.VisualHitbox = true end
	if HitProjectileValues.Piercing == nil then HitProjectileValues.Piercing = 1 end
	if HitProjectileValues.FilterDescendantsInstances == nil then HitProjectileValues.FilterDescendantsInstances = {} end
	if HitProjectileValues.GravityAmpilfier == nil then HitProjectileValues.GravityAmpilfier = 0 end
	if HitProjectileValues.RotationalVelocity == nil then HitProjectileValues.RotationalVelocity = Vector3.new(0,0,0) end
	if HitProjectileValues.AddedVelocity == nil then HitProjectileValues.AddedVelocity = Vector3.new(0,0,0) end
	
	if HitProjectileValues.ProjectileColor3 == nil then HitProjectileValues.ProjectileColor3 = Color3.fromRGB(255, 255, 255) end
	if HitProjectileValues.ProjectilePartType == nil then HitProjectileValues.ProjectilePartType = Enum.PartType.Ball end
	if HitProjectileValues.ProjectileTransparency == nil then HitProjectileValues.ProjectileTransparency = 0 end
	if HitProjectileValues.ProjectileMaterial == nil then HitProjectileValues.ProjectileMaterial = Enum.Material.SmoothPlastic end
	
	if HitProjectileValues.Explosion then
		if HitProjectileValues.Explosion.ExplosionSize == nil then HitProjectileValues.Explosion.ExplosionSize = HitProjectileValues.Size * 1.35 end
		if HitProjectileValues.Explosion.ExplosionColor3 == nil then HitProjectileValues.Explosion.ExplosionColor3 = HitProjectileValues.ProjectileColor3 end
		if HitProjectileValues.Explosion.ExplosionPartType == nil then HitProjectileValues.Explosion.ExplosionPartType = HitProjectileValues.ProjectilePartType end
	end

	local RunServiceConnection,ProjectilePart
	local CurrentTime = 0
	local HitCharacters = {}
	local Params = OverlapParams.new()
	
	Params.FilterDescendantsInstances = HitProjectileValues.FilterDescendantsInstances::{Instance}
	
	RunServiceConnection,ProjectilePart = ProjectileHitboxAbstract(HitProjectileValues,FunctionOnHit,HitCharacters,Params)

	return RunServiceConnection,ProjectilePart
end

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.