The target of the module script should be a monster, but the player is the target

The attack animation is supposed to run on dummy, but it keeps running on players. I don’t know what the hell is wrong with this, please help!

local Players = game:GetService("Players")
local Workspace = game:GetService("Workspace")
local RunService = game:GetService("RunService")

local targetDistance = 40 -- 플레이어가 이 거리 이내로 접근하면 추적을 시작합니다
local attackDistance = 5 -- 공격을 시작할 거리
local attackCooldown = 2 -- 공격 사이의 대기 시간
local attackDamage = 5 -- 공격 피해량

local MobClass = {}
MobClass.__index = MobClass

function MobClass.new(dummy)
	local self = setmetatable({}, MobClass)

	self.Model = dummy
	self.Humanoid = dummy:FindFirstChildOfClass("Humanoid")
	self.PrimaryPart = dummy.PrimaryPart or dummy:WaitForChild("HumanoidRootPart")

	self.AttackAnim = dummy:FindFirstChild("AttackAnimation") or Instance.new("Animation")
	self.AttackAnim.AnimationId = "rbxassetid://18754158629" -- 애니메이션 ID를 교체하세요
	self.AttackAnimTrack = self.Humanoid:LoadAnimation(self.AttackAnim)

	self.Target = nil
	self.LastAttackTime = 0

	self:Start()

	return self
end

function MobClass:Start()
	spawn(function()
		while self.Humanoid and self.Humanoid.Health > 0 do
			self:FindTarget()
			if self.Target then
				self:MoveToTarget()
				self:AttackTarget()
			end
			wait(0.5)
		end
		self:Respawn()
	end)
end

function MobClass:FindTarget()
	local players = Players:GetPlayers()
	local nearestDistance = targetDistance
	self.Target = nil

	for _, player in ipairs(players) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
			local distance = (self.PrimaryPart.Position - player.Character.HumanoidRootPart.Position).Magnitude
			if distance < nearestDistance then
				nearestDistance = distance
				self.Target = player.Character
			end
		end
	end
end

function MobClass:MoveToTarget()
	if self.Target and self.Target:FindFirstChild("HumanoidRootPart") then
		self.Humanoid:MoveTo(self.Target.HumanoidRootPart.Position)
	end
end

function MobClass:AttackTarget()
	if self.Target and (self.PrimaryPart.Position - self.Target.HumanoidRootPart.Position).Magnitude <= attackDistance then
		local currentTime = tick()
		if currentTime - self.LastAttackTime >= attackCooldown then
			self.LastAttackTime = currentTime
			-- 애니메이션을 NPC의 Humanoid에서 실행
			if self.AttackAnimTrack then
				print("Playing attack animation on NPC:", self.Model.Name) -- 정확한 출력
				self.AttackAnimTrack:Play() -- NPC의 애니메이션을 실행
			else
				warn("Animation Track is not found!")
			end
			local targetHumanoid = self.Target:FindFirstChildOfClass("Humanoid")
			if targetHumanoid then
				targetHumanoid:TakeDamage(attackDamage)
			end
		end
	end
end

For your information, this is the server script that requires this module script

local MobClass = require(script.ModuleScript)

local function onDummyAdded(dummy)
	if dummy:IsA("Model") and dummy:FindFirstChildOfClass("Humanoid") then
		-- 새로 생성된 dummy 모델에 대해 MobClass를 초기화
		MobClass.new(dummy)
	end
end

-- 초기 dummy 모델을 workspace에서 확인
for _, dummy in ipairs(workspace:GetChildren()) do
	if dummy:IsA("Model") and dummy:FindFirstChildOfClass("Humanoid") then
		onDummyAdded(dummy)
	end
end

-- 새로운 dummy 모델이 추가될 때 연결
workspace.ChildAdded:Connect(function(child)
	if child:IsA("Model") and child:FindFirstChildOfClass("Humanoid") then
		onDummyAdded(child)
	end
end)

I believe this is happening because each player’s character meets all of that criteria.

  • The character is a model
  • The character model does have a humanoid

So there is nothing specifying whether or not to run this on each character.
I would suggest replacing your checks and/or using attributes in conjunction with your checks to see if the dummy is not a player.