Keeping CFrame-movement-based NPC on the ground

I’ve made an NPC which chases nearby players that moves via changing the CFrame of the primary part of its model. It mostly works as intended, however when the player jumps, the NPC begins to levitate, and eventually moves back down. I want the NPC to stay upright on top of the surface it is standing on. I tried looking through video tutorials and DevForum but there’s really no solution I can find… Been a while since I programmed this NPC too so I wouldn’t be 100% sure to be able to explain all of the code.

coding shenanigans, this is all just inside 1 script

local EvilLeafy = script.Parent
local Scream = EvilLeafy.Body.Scream
local Teleport = EvilLeafy.Body.Teleport
local MaxDistance = 200
local Vignette = script:FindFirstChild("VignetteEffect")

function Kill(part)
	part.Parent.Humanoid.Health = 0
	if not Scream.Playing then
		Scream:Play()
	end
end

function findNearestCharacter(leafPosition)
	for i, player in pairs(game:GetService("Players"):GetPlayers()) do
		if player.Character and player.Character:FindFirstChild("Humanoid") and player.Character:FindFirstChild("Humanoid").Health > 0 then
			local distance = (player.Character.HumanoidRootPart.Position - leafPosition).Magnitude
			if distance < MaxDistance then
				return player.Character
			else
				return false
			end	
		else
			return false
		end
	end
end

function teleportToCharacter()
	local character = findNearestCharacter(EvilLeafy.Hitbox.Position)
	if character then
		local distance = character.HumanoidRootPart.Position - EvilLeafy.Hitbox.Position
		local distance2 = (character.HumanoidRootPart.Position - EvilLeafy.Hitbox.Position).Magnitude
		local charOrientation = character.HumanoidRootPart.Orientation
		local offset = distance.Unit * 16
		local lookAt = CFrame.lookAt(EvilLeafy.Hitbox.Position, character.HumanoidRootPart.Position)

		if distance2 <= 20 then
			EvilLeafy:SetPrimaryPartCFrame(character.HumanoidRootPart.CFrame)
			Kill(character.HumanoidRootPart)
		else
			EvilLeafy:SetPrimaryPartCFrame(lookAt + offset)
		end
		
		Teleport:Play()
		if game:GetService("Players"):GetPlayerFromCharacter(character).PlayerGui:FindFirstChild(Vignette.Name) then
			game:GetService("Players"):GetPlayerFromCharacter(character).PlayerGui:FindFirstChild(Vignette.Name):Destroy()
		end
		local clone = Vignette:Clone()
		clone.Parent = game:GetService("Players"):GetPlayerFromCharacter(character).PlayerGui
	end	
end

EvilLeafy.Hitbox.Touched:Connect(function(part)
	if part.Parent:FindFirstChild("Humanoid") then
		Kill(part)
	end
end)

while true do
	task.wait(1)
	if script.Parent.Hitbox.Parent == nil then
		EvilLeafy:Destroy()
	end
	teleportToCharacter()
end

you could instead replace this line

with this:

local CharPosition =  character.HumanoidRootPart.CFrame.Position
EvilLeafy:SetPrimaryPartCFrame(CFrame.new(CharPosition.X, 0 --[[you can change]], Char.Position.Z) 

this keeps leafy on the same Y axis.

2 Likes

The NPC is teleporting while the player is in the air, so the offset vector is pointing upwards. You can fix that by creating a new offset vector with Y = 0:

local offset = distance.Unit * 16
local offset2 = Vector3.new(offset.X, 0, offset.Z)

And then you do EvilLeafy:SetPrimaryPartCFrame(lookAt + offset2) in the following else block.

However, you also need to apply the change suggested by @fredtheprank2335 so that the NPC doesn’t get shifted upwards when killing the player.

1 Like

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