I am attempting to make an aggressive ai for creatures in my game. The goal is that they turn to look at you when you get close, and then chase you. Chasing, and detecting, is well within my knowledge, but I can’t seem to find a solution for smooth look at, or implementing look at in a tween. This is vital, because some of the creatures are very big, and if they turned around instantly via actual look at, it would look very low quality.
You can use CFrame.lookAt() to get the target orientation and then use Lerping to rotate smoothly towards the target (using a small alpha and creating a new lerp every frame)
So something like this? (Don’t use this one in release, I just found it as a free model)
local MaxLookDistance = 1000
local MovementSpeed = 4
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local Chat = game:GetService("Chat")
local Debris = game:GetService("Debris")
local Cheeky = script.Parent
local DefaultCFrame = Cheeky.CFrame
local function getNearestPlayer()
local part = nil
local dist = MaxLookDistance
for i,v in ipairs(Players:GetPlayers()) do
local character = v.Character
if character then
local root = character:FindFirstChild("Head")
if root then
local thisDist = (root.Position-Cheeky.Position).Magnitude
if thisDist < dist then
dist = thisDist
part = root
end
end
end
end
return part
end
local focusedPart = nil
local lastCheck = 0
RunService.Heartbeat:Connect(function(delta)
if focusedPart then
local cf = CFrame.lookAt(
DefaultCFrame.Position,
focusedPart.Position
)
Cheeky.CFrame = Cheeky.CFrame:Lerp(cf, delta * MovementSpeed)
else
Cheeky.CFrame = Cheeky.CFrame:Lerp(
DefaultCFrame,
delta * MovementSpeed
)
end
if time() > lastCheck then
lastCheck = time() + 1
focusedPart = getNearestPlayer()
end
end)
local Parts = {Cheeky, Cheeky.Face, Cheeky.ChatBubble}
local CFData = {}
local BubbleOffset = Cheeky.Size.Y/2
RunService.Heartbeat:Connect(function(delta)
local cf = nil
table.clear(CFData)
if focusedPart then
cf = CFrame.lookAt(
DefaultCFrame.Position,
focusedPart.Position
)
else
cf = DefaultCFrame
end
local NewCF = Cheeky.CFrame:Lerp(cf, delta * MovementSpeed)
CFData[1] = NewCF
CFData[2] = NewCF
CFData[3] = NewCF * CFrame.new(0,BubbleOffset,0)
workspace:BulkMoveTo(Parts, CFData, Enum.BulkMoveMode.FireCFrameChanged)
end)
Cheeky.Anchored = true
Could you explain how the would work?
u cant (or shouldnt) set the head’s CFrame, you have to use the “Neck” Motor6D that is inside the Torso of the character
The problem is that C0 and C1 properties, which are both CFrames, are in relative object space, and to translate from world space to relative space is a tedious task
fortunately, there’s already been a post made about this topic
be wary that the marked solution might not point at the target accurately, u can scroll down and hopefully find the updated version of the script
now, to lerp it u can do something like this (code taken from the solution):
while true do -- replace the while loop with whatever u want to use (a for loop should do)
task.wait()
local lookat = CFrame.lookAt(Head.Position, target.Position, upperTorso.CFrame.UpVector)
local goalCF = target.CFrame:Lerp(lookat, 0.5)
neckJoint.C0 = worldCFrameToC0ObjectSpace(neckJoint,goalCF)
end
All of my creatures are custom rigs built to look like alien sea life. they have no resemblance to the base Roblox character. The way I have made the motor6d’s work is also finicky, but still works with animations. Altering the motor6d’s I think would mess with how it works the wrong way. I simply want a way to smooth CFrame.lookat()
my reply still applies, but with a few changes:
for i = 0, 10, 1 do -- some arbitrary amount of steps
local lookat = CFrame.lookAt(Head.Position, target.Position, upperTorso.CFrame.UpVector)
Head.CFrame = Head.CFrame:Lerp(lookat, i/10) -- i/10 has has to be between 0 and 1
task.wait()
end
(have to say that this doesnt work with base roblox characters, as it will turn their entire character towards the target, which is why motor6d was used)
My goal is to turn the whole character. does this do that?
i misunderstood and thought you were turning their heads lol. You’ll have to replace Head with whatever primary part your character has, also with a few changes because my previous script would look up and down as well
for i = 0, 10, 1 do -- some arbitrary amount of steps
local lookat = CFrame.lookAt(primaryPart.Position, target.Position)
local _, x, _ = lookat:ToEulerAnglesYXZ()
local flatLookAt = CFrame.new(primaryPart.Position) * CFrame.Angles(0, x, 0)
primaryPart.CFrame = primaryPart.CFrame:Lerp(flatLookAt, 0.5)
task.wait()
end
what do you mean look up and down. The game is inspired by Subnautica, your in the middle of an ocean. They will look directly at you including up and down.
then just replace the Head with the primary part of the models
I tested your method. It is just normal look at, but with no up and down, and still no smoothing. I mean the start of the look at I want to slowly look over to the target, not jolt to it.
the reason its not smooth is because i’ve assigned a random value for a number of steps in the for loop, which was too low for a noticeable difference.
this is the code u should be using
local numOfSteps = 50
for i = 0, numOfSteps, 1 do -- some arbitrary amount of steps
local lookat = CFrame.lookAt(Head.Position, target.Position, upperTorso.CFrame.UpVector)
Head.CFrame = Head.CFrame:Lerp(lookat, i/numOfSteps)
task.wait()
end
This works great, but the more steps I add the longer it takes to finish, even it the orientation has reached looking at me. Is there a way to stop it once it is done? I want it to be like a 3 second time until its done, but preventing it from lingering even when its done.
im not sure if i understand what u mean, it stops when it looks at u and it doesnt linger. If you want it to be 3 seconds exactly you’ll have to use task.wait(duration/numOfSteps)
I looked everywhere to find out how to do this. this works, thanks.
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.