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.