Checking if a player is to the right or left of an NPC

Hey fellow devs!

I’ve been trying to make an enemy that, when it sees you, it starts rushing towards you in a straight line and, after it crosses you, it’ll attack either to the left or right.

Here’s a visual explanation:

This is the code I use to check if the player is at the right or left of the enemy:

-- self is the Enemy's model
-- Target is the player's HumanoidRootPart
-- Slash is a function i made to slash
local Passed = false

self.PrimaryPart.CFrame = CFrame.lookAt(self.PrimaryPart.Position,Target.Position,Vector3.yAxis)
local Dir = self.PrimaryPart.CFrame.LookVector

self.Humanoid.WalkSpeed = self:GetAttribute("ChargeSpeed")
	
task.spawn(function()
	while not Passed do
		self.Humanoid:MoveTo(Dir*1000)
		task.wait(4)
	end
end)

local rbxc_CHECK_POS
rbxc_CHECK_POS = RunService.Heartbeat:Connect(function()
	local relCFrame = self.PrimaryPart.CFrame:ToObjectSpace(Target.CFrame)
	if relCFrame.Z < 0 or Passed then
		-- Enemy has passed the player
		Passed = true
		rbxc_CHECK_POS:Disconnect()
		if relCFrame.X > 0 then
			Slash("Right")
		else
			Slash("Left")
		end
	end
end)

The problem is, the enemy istantly slashes to the right, even if the player is still in front. I have no idea what to do!

1 Like

I think you should try welding a non-colliding and transparent part to the enemy’s HumanoidRootPart, then connect its Touched function and do what you need to do inside of it.
Do something like this:

then attach a script to the new part with this inside:

local Players = game.Players
local Sensor = script.Parent

Sensor.Touched:Connect(function(Hit)
	
	if Players:GetPlayerFromCharacter(Hit.Parent) then -- Checks if the part collided is a player character child
		
		-- your slash animation and code.
		
	end
	
end)

1 Like

That would work, of course, but how do I know if the player is to the right or left of the NPC in this case?

You can just create two parts instead of one, it’s not too orthodox but I don’t know how else could you do.

I’ll use this as a temporary solution, but I won’t mark it as such yet to see if someone else responds. If I don’t find another way then I guess I’ll have to keep it.
The only problem I have with is that sometimes collisions are kinda janky, so I was trying something else.
Thanks anyways!

The problem is that there’s no way to know if a player passes by without collisions. The only other thing you can do is looping every player in the server and checking if their distance is less than the enemy’s range. But I strongly recommend to not do so as it is inefficient.

This uses dot products instead of collisions:

	local enemy = workspace.Enemy
	local target = workspace.Target

	local horizontalDot = enemy.CFrame.RightVector:Dot(CFrame.new(target.Position,enemy.Position).LookVector)
	local verticalDot = enemy.CFrame.LookVector:Dot(CFrame.new(target.Position,enemy.Position).LookVector)


	
	local direction
	
	if horizontalDot >= 0 then 
		direction = Vector2.new(-1,0)
	else  
		direction = Vector2.new(1,0)
	end
	
	if verticalDot >= 0.5 then
		direction = Vector2.new(0,1)
	elseif verticalDot <= -0.5 then
		direction = Vector2.new(0,-1)
	end
	
	print(direction.X,direction.Y)

Change the target and enemy, and it will return a vector2 of the relative location

1 Like

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