Humanoid direction control Humanoid:FaceTo()

Overview
As a game developer, it is important to have feature parity between Player Characters and Non-Player Characters (NPCs). There is currently a gap in functionality related to character direction alignment. Player characters use Humanoid:Move(vec3, true) to orient the character independently of the move direction. The player, using shiftlock or being in first-person, will orient their character in the direction of their camera, regardless of their movement. This API is not usable on NPC’s as it specifically relies on the orientation of the camera (which NPCs do not have).

The Humanoid does have the setting Humanoid.AutoRotate which is seemingly used to disable the built-in humanoid rotation forces, allowing devs to implement their own rotation forces. This is not ideal because devs won’t be able to rotate NPC characters with the same exact forces, or with similarly easy to use API’s as Player Characters.

Usecases
In my swordfighting game, players use shiftlock to face their characters in the direction of their cameras, allowing for facing their targets while moving, and giving fine-control over the direction of their sword swings. I am not able to make NPC’s that have the same exact functionality as player characters. This is is upsetting. Regardless of my parity and strafing usecases, the biggest usecase is to orient a non-moving character, such as to face the direction they are speaking.

Suggested API Request

  • Humanoid.FaceToPoint: Vector3?
  • Humanoid.FaceToPart: BasePart?
  • Humanoid:FaceTo(point: Vector3, part: BasePart?)

These APIs match the paradigm currently set by Humanoid.WalkToPoint, Humanoid.WalkToPart, and Humanoid:MoveTo(). It is expected that the two properties will automatically be set by the Humanoid:MoveTo() function unless Humanoid.AutoRotate is set to false. The rotational forces should only be applied in humanoid states that allow players to rotate their characters.

Ugly Workaround
To understand my struggles more, I am sharing some of the code that I use to try to emulate this functionality in my sword fighting game. It is not ideal since the rotational forces in player characters and NPCs do not match. My code also does not take into account the current humanoid state, so there is more code that needs to be developed to make progress towards PC and NPC parity.

function Bot:FaceTo(faceToPos)
	if not (self.Humanoid and self.Character and self.Character.Parent and self.Character.PrimaryPart) then
		return
	end
	self.Humanoid.AutoRotate = false
	--self.Character:PivotTo(CFrame.lookAt(selfPos, selfPos + flatAttackVec))	-- Always face the target -- has stuttering problems
	local bodyGyro = self.Character.PrimaryPart:FindFirstChild('BotFaceToBodyGyro')
	if not bodyGyro then
		bodyGyro = Instance.new('BodyGyro')
		bodyGyro.Name = 'BotFaceToBodyGyro'
		-- These values are guesses, after many manual observations and changes
		bodyGyro.MaxTorque = Vector3.new(0,1,0) * 4000000
		bodyGyro.D = 5--500
		bodyGyro.P = 300000--3000
		bodyGyro.Parent = self.Character.PrimaryPart
	end
	bodyGyro.CFrame = CFrame.lookAt(self.Character.PrimaryPart.CFrame.Position, faceToPos)
end

function Bot:MoveTo(goalPos, faceToPos: Vector3?)
	if not (self.Humanoid and self.Character and self.Character.Parent and self.Character.PrimaryPart) then
		return
	end

	if faceToPos then
		self:FaceTo(faceToPos)
	else
		local bodyGyro = self.Character.PrimaryPart:FindFirstChild('BotFaceToBodyGyro')
		if bodyGyro then
			bodyGyro:Destroy()
		end
		self.Humanoid.AutoRotate = true
	end
	self.Humanoid:MoveTo(goalPos)
end
9 Likes

Curious, what is stopping you from using Model:PivotTo() or setting Humanoid.RootPart.CFrame?

1 Like

These most likely dont work with the humanoid walking

2 Likes

ControllerManagers have this built-in as FacingDirection


Unfortunately, this does not work very well and results in movement being very stuttery if you use :MoveTo:

The docs state that this property is read-only (I may be misunderstanding though, but that “Read Parallel” tag’s description on it is very misleading if it can be set).

1 Like

Unfortunately it is misleading :pensive_face: “Read Parallel” only applies for use in Parallel scripts, in that it is read-only in parallel and cannot be written-to. “Read Only” for all scripts uses a different tag that’s just Read Only:

2 Likes