Enemy not going to the right height and some going inside of the ground

so, im doing a tower defense game and im working on the movement system, but for some reason, the enemies just dont fit well.

image

Code:

local replicatedStorage = game:GetService('ReplicatedStorage')
local tweenService = game:GetService('TweenService')

local events = replicatedStorage.Events
local enemiesModels = replicatedStorage.Enemies
local gameFolder = workspace.Game
local serverToClient = events.ServerToClient
local enemies = gameFolder.Enemies
local map = gameFolder.Map
local spawns = map.Spawns
local waypoints = map.Waypoints
local module = {}

function module:UpdateRender(id:number, templateCFrame:CFrame, nodePosition:Vector3)
	for _, enemy in pairs(enemies:GetChildren()) do
		if enemy:GetAttribute('ID') == id then
			enemy:WaitForChild('Render'):SetPrimaryPartCFrame(templateCFrame)
			
			local weld = Instance.new('WeldConstraint')
			weld.Parent = enemy
			weld.Part0 = enemy
			weld.Part1 = enemy:WaitForChild('Render').PrimaryPart
		end
	end
end

function module:Get(enemy:string)
	return require(script[enemy])
end

function module.Move(TEMPLATE:BasePart)
	serverToClient.UpdateRender:FireAllClients(TEMPLATE:GetAttribute('ID'), TEMPLATE.CFrame, waypoints[TEMPLATE:GetAttribute('MovingTo')].Position)
	for node = 1, #waypoints:GetChildren() do
		local cframe = TEMPLATE.CFrame
		local distance = (cframe.Position - waypoints[node].Position).Magnitude
		local speed = distance * TEMPLATE:GetAttribute('Speed')

		local ti = TweenInfo.new(speed, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0)
		local t_MOVE = tweenService:Create(TEMPLATE, ti, {Position = waypoints[node].Position})
		local t_ROTATE = tweenService:Create(TEMPLATE, TweenInfo.new(0.5, Enum.EasingStyle.Linear, Enum.EasingDirection.In, 0, false, 0), {CFrame = CFrame.lookAt(TEMPLATE.Position, waypoints[node].Position)})
		t_MOVE:Play()
		t_ROTATE:Play()
		t_MOVE.Completed:Wait()
	end
	
	--if distance < 0.5 then
	--	if TEMPLATE:GetAttribute('MovingTo') == #waypoints:GetChildren() then
	--		TEMPLATE:Destroy()
	--	else
	--		TEMPLATE:SetAttribute('MovingTo', TEMPLATE:GetAttribute('MovingTo') + 1)
	--	end
	--end
	
	--local speed = TEMPLATE:GetAttribute('Speed') * deltaTime
	--local estimatedTime = speed / distance
	--local alpha = math.min(estimatedTime, 1)

	--serverToClient.UpdateRender:FireAllClients(TEMPLATE:GetAttribute('ID'), TEMPLATE.CFrame, waypoints[TEMPLATE:GetAttribute('MovingTo')].Position)
	--cframe = cframe:Lerp(CFrame.new(Vector3.new(waypoints[TEMPLATE:GetAttribute('MovingTo')].Position.X, TEMPLATE.Position.Y, waypoints[TEMPLATE:GetAttribute('MovingTo')].Position.Z)), alpha)
	--TEMPLATE.CFrame = cframe
end

function module:SpawnEnemy(enemyName:string, amount:number, delay_:number)
	for i = 1, amount or 1 do
		local enemy = enemiesModels:FindFirstChild(enemyName)
		if not enemy then warn(enemyName..' does not exist bozo') return end
		local spawnChoosen = spawns:GetChildren()[math.random(1, #spawns:GetChildren())]
		local template = replicatedStorage.Server:Clone()
		
		for attribute:string, value:any in pairs(module:Get(enemyName)) do
			template:SetAttribute(attribute, value)
		end
		
		template:SetAttribute('ID', math.random(1, 9999999))
		template.Name = enemyName
		template.Parent = enemies
		template:SetNetworkOwner(nil)
		template.Anchored = true
		template.Size = enemy.PrimaryPart.Size
		template.CFrame = CFrame.new(Vector3.new(spawnChoosen.Position.X, (spawnChoosen.Size.Y/2 + enemy.PrimaryPart.Size.Y * 1.5), spawnChoosen.Position.Z))
		template.CollisionGroup = 'Enemies'
		serverToClient.RenderEnemy:FireAllClients(enemyName, template:GetAttribute('ID'), template.CFrame)
		coroutine.wrap(module.Move)(template)
		
		task.wait(delay_ or 1)
	end
end

return module

The Y position of the RootPart of your enemies has to be set as:

Root.CFrame = CFrame.new(X, (Root.Size.Y / 2) + (RightLeg.Size.Y), Z)   

Any leg works by the way, but I’m using the Right one in this example.

This accounts for half of the torso and the full length of the leg, making the enemy perfectly stand on the ground. Do keep in mind you’ll have to adjust my code to fit into yours as I’ve just given you a general idea.