How would I make this "prefer" to go towards a player?

So basically I’ve made a script that moves a block like in the video below. How would I make it pick going TOWARDS the player if possible for it to do so?

local TweenService = game:GetService("TweenService")
local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Quart, Enum.EasingDirection.Out)
local tweenInfoIn = TweenInfo.new(2.5, Enum.EasingStyle.Quart, Enum.EasingDirection.In)
local goal = {}
local isDelayed = false

local function additionalDelay(Time)
	isDelayed = true
	task.wait(Time)
	isDelayed = false
end

-- Improved raycasting function with better wall detection
local function ray(vectors)
	local rayOrigin = script.Parent.Position
	local rayDirection = vectors
	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {script.Parent}  -- Ignore the parent (itself)
	rayParams.FilterType = Enum.RaycastFilterType.Exclude  -- Exclude parent object from raycast

	local raycastResult = workspace:Raycast(rayOrigin, rayDirection, rayParams)

	if raycastResult then
		local hitPart = raycastResult.Instance
		-- Ensure we detect walls and not other parts like "monster"
		if hitPart.ClassName == "Part" and hitPart.Name ~= "monster" then
			local distance = (script.Parent.Position - hitPart.Position).Magnitude
			local size = hitPart.Size
			local margin = size.Magnitude / 2 + 2  -- Margin to avoid parts (slightly increased)

			-- Debugging: Check what is being hit
			print("Hit: ", hitPart.Name, " at distance: ", distance)

			-- If the distance is too small, treat it as blocked space
			if distance < margin then
				print("Blocked by: ", hitPart.Name)
				return hitPart
			end
		end
	end
	return nil  -- Return nil if no wall is detected
end

-- Search for valid spaces and ensure the part avoids obstacles
local function Search()
	local validSpaces = {}
	local directions = {
		Vector3.new(0, 0, -12),  -- Negative Z direction (back)
		Vector3.new(0, 0, 12),   -- Positive Z direction (front)
		Vector3.new(12, 0, 0),   -- Positive X direction (right)
		Vector3.new(-12, 0, 0),  -- Negative X direction (left)
	}

	for _, direction in pairs(directions) do
		local result = ray(direction)
		if result == nil then
			-- No obstacles found in the direction, add it to valid spaces
			table.insert(validSpaces, direction)
		else
			-- Debugging: Show which direction is blocked
			print("Direction blocked: ", direction)
		end
	end
	return validSpaces
end

-- Improved move function with better obstacle handling
local function move(ValidSpaces)
	if #ValidSpaces == 0 then
		print("No valid spaces to move.")
		return
	end

	local directionChosen = ValidSpaces[math.random(1, #ValidSpaces)]
	print("Chosen valid space direction: ", directionChosen)

	local movingPart = script.Parent
	local stepSize = 1  -- Step size for incremental movement (adjust as needed)

	-- Function to create a tween for the movement
	local function createTween(targetPosition)
		local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
		local tweenGoal = {Position = targetPosition}
		return TweenService:Create(movingPart, tweenInfo, tweenGoal)
	end

	-- Start moving the part step by step in the chosen direction
	local currentPosition = movingPart.Position
	while true do
		-- Increment the position by step size in the chosen direction
		local nextPosition = currentPosition + directionChosen * stepSize

		-- Raycast to check for obstacles
		local result = ray(nextPosition - currentPosition)  -- Cast ray between current and next position
		if result ~= nil then
			print("Hit an obstacle: ", result.Name)
			break  -- Stop moving if an obstacle is hit
		end

		-- Move the part to the new position
		local tween = createTween(nextPosition)
		tween:Play()
		tween.Completed:Wait()

		-- Update the current position after the movement
		currentPosition = nextPosition

		-- Small delay between each step to prevent too fast movement
	end

	print("Movement stopped due to obstacle.")
end

-- Event listener for value change
local value = script.Value
value:GetPropertyChangedSignal("Value"):Connect(function()
	if value.Value == false then
		goal.ImageColor3 = Color3.fromRGB(72, 72, 72)
		local tween
		script.Parent.Deactivate:Play()
		local f = coroutine.wrap(additionalDelay) f(2)
		for i, v in pairs(script.Parent:GetDescendants()) do
			if v.ClassName == "ImageLabel" then
				tween = TweenService:Create(v, tweenInfoIn, goal)
				tween:Play()
			end
		end
	end
	if value.Value == true then
		local f = coroutine.wrap(additionalDelay) f(2)
		goal.ImageColor3 = Color3.fromRGB(255, 0, 0)
		local tween
		script.Parent.POD_power_up:Play()

		for i, v in pairs(script.Parent:GetDescendants()) do
			if v.ClassName == "ImageLabel" then
				tween = TweenService:Create(v, tweenInfoIn, goal)
				tween:Play()
			end
		end
	end
end)

-- Main loop for searching and moving
while true do
	if value.Value == true then
		if isDelayed == false then
			-- Only proceed with move if no delay
			local validSpaces = Search()
			script.Parent["rock move"]:Play()
			move(validSpaces)  -- Move to the chosen valid space
			script.Parent["rock move"]:Stop()
			script.Parent["slam"]:Play()
			task.wait(1)  -- Ensure no immediate repeat
		end
		task.wait()
	end
	task.wait()
end

You can use pathfinding service to generate some waypoints which should give you an idea (the first waypoint) of the direction you should go in.

Make the agent radius smaller then the cube or else it wont work properly in my experience.

also, a suggestion to change from while true to while result

I don’t want to use the pathfinding service, since wouldn’t I need to recode the entire script to fit it?

It needs to see the player to go towards it?

uh no? you can use a function?? that returns the direction chosen???

yes, it should be able to see the player then go towards it

You could do a raycast that its origin is the monster and the direction is the direction of nearest player position. If it hits a wall, then it isn’t able to see the player and continue moving kinda randomly, if it is able to see the player then check the direction he would be closer to the player he is seeing and walk this direction.

smth like that:

-- just central code:

local NearestPlayer -- Find nearest player
local Monster -- Monster
local Raycast = workspace:Raycast(Monster.Position, (NearestPlayer.Position - Monster.Position), params) -- Set the params to just the walls, i guess

if Raycast.Instance.Parent == workspace:WaitForChild("Walls") then

    -- act walking randomly

else

    -- test all movements possibilities and check in which one the monster would be closer to the player
   
end

(This code won’t work at all. I did it just to give you an idea what I’m thinking.)

you can use combo of raycasting and A* pathfinding, you have grid soo it would be easy, check every time this cube moves if it can see the player, then if it can, use A* to find optimal path to the player