How would I find the direction of where the mouse is moving? (left/right X axis, up and down, Z-Axis)

So I’m making a board game that has an overhead camera, and is 3D, but I’m having an issue trying to locate where the mouse last position is and what axis it’s moving from…

I made a 2D grid on the client so I can get every tile and reposition accordingly, but the issue here is, when I move on the X axis (left-right) the model ends up moving .25 studs increment instead of .5 studs, and that’s because I’m sending on the wrong direction when moving left to right.

Here’s a video to show what I mean, moving the ships up and down use the .5 stud increment, but left to right uses .25…

local function generateTileGrid(tilesModel)
	local grid = {}
	for _, tile in tilesModel:GetChildren() do
		if tile:IsA("BasePart") then
			local x = math.round(tile.Position.X / 0.5)
			local z = math.round(tile.Position.Z / 0.5)
			grid[z] = grid[z] or {}
			grid[z][x] = tile
		end
	end
	return grid
end

local function getClosestTile(result, grid)
	local closest, closestDist = nil, math.huge
	for _, row in grid do
		for _, tile in row do
			local dist = (tile.Position - result.Position).Magnitude
			if dist < closestDist then
				closest = tile
				closestDist = dist
			end
		end
	end
	return closest
end

local function getTiles(grid, startTile, modelLength, direction)
	local occupied = {}
	local startX = math.round(startTile.Position.X / 0.5)
	local startZ = math.round(startTile.Position.Z / 0.5)

	for i = 0, modelLength - 1 do
		local x, z = startX, startZ
		if direction == "Z" then
			z += i
		else
			x += i
		end

		if not grid[z] or not grid[z][x] then
			return nil -- out of bounds
		end

		table.insert(occupied, grid[z][x])
	end

	return occupied
end

local grid = generateTileGrid(tilesModel)
runService.RenderStepped:Connect(function()
	local result = mouseRaycast()
	if not result then return end

	local hitPart = result.Instance
	if not hitPart then return end

	if not isPlacing then
		if hitPart and hitPart.Name == "Hitbox" then
			local shipModel = hitPart.Parent
			if shipModel:IsA("Model") then
				hoveredShip = shipModel
				createHiglight(hoveredShip)
			end
		else
			deleteHighlight(hoveredShip)
			hoveredShip = nil
		end
	else
		if selectedShip then
			local closestTile = getClosestTile(result, grid)
			if closestTile then
				local shipSizeZ = selectedShip:GetExtentsSize().Z
				local tilesNeeded = math.round(shipSizeZ / 0.5)

				local shipTiles = getTiles(grid, closestTile, tilesNeeded, "Z")
				if shipTiles then
					local finalTile = shipTiles[math.ceil(#shipTiles / 2)]
					local height = selectedShip:GetExtentsSize().Y / 2
					local targetPos = finalTile.Position + Vector3.new(0, height, 0)
					local target = CFrame.new(targetPos)
					selectedShip:PivotTo(target)
				end
			end
		end
	end
end)

Any help would be appreciated (I’m using userinputservice for raycasting and trying to get the mouse position :slightly_smiling_face:)

1 Like

Hi you need to directectly get the player mouse like this :

--|| Services ||--
local Players = game:GetService("Players")

--|| Variables ||--
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()
local MouseHitCFrame = Mouse.Hit
local MouseTarget = Mouse.Target ::BasePart?

if MouseTarget then
	print("Mouse is pointing on ",MouseTarget.Name)
end

--|| Connections ||--
Mouse.Move:Connect(function()
	--your code
end)
1 Like

Yes I’m aware, and I am using UserInputService to reference the mouse, but this doesn’t explain my issue though, how would I get to direction to where the mouse is moving?

local mousePos = inputService:GetMouseLocation()

I think you can do something like this, the direction is a normalised Vector2, you’ll get something like 0, 1, this just means it’s moving up, it goes 8 ways I’m pretty sure, but you can definitely limit it to 4, anyway here is the code, let me know if you don’t understand something:

local UIS = game:GetService("UserInputService")
local lastPos = UIS:GetMouseLocation()

UIS.InputChanged:Connect(function(input : InputObject) : RBXScriptSignal
	if input.UserInputType == Enum.UserInputType.MouseMovement then
	local currentPos = UIS:GetMouseLocation()
	local delta = currentPos - lastPos
	lastPos = currentPos

	local direction = Vector2.zero
	if delta.Magnitude > 0 then
		direction = Vector2.new(math.sign(delta.X), math.sign(delta.Y))
	end

		print("direction:", direction)
	end
end)

1 Like

So yeah this works, but I’m confused on how I would determine what direction I’m going? It’s always printing Z, even though Im getting the absolute value of both directions, am I doing it wrong?

if selectedShip then
	local closestTile = getClosestTile(result, grid)
	if closestTile then
		local shipSizeZ = selectedShip:GetExtentsSize().Z
		local tilesNeeded = math.round(shipSizeZ / 0.5)

		local axis = "Z"
		if math.abs(direction.X) > math.abs(direction.Y) then
			axis = "X"
		end

		print('axis:', axis)

		local shipTiles = getTiles(grid, closestTile, tilesNeeded, axis)
		if shipTiles then
			local finalTile = shipTiles[math.ceil(#shipTiles / 2)]
			local height = selectedShip:GetExtentsSize().Y / 2
			local targetPos = finalTile.Position + Vector3.new(0, height, 0)
			local target = CFrame.new(targetPos)
			selectedShip:PivotTo(target)
		end
	end
end

So I ended up finding a solution,

I looped through every single tile and get the center position by adding every single tiles Position, once I get that, I divide the center position by the amount of tiles on the board, it ended up making every single increment even and positioning the model in the center of each single tile.

1 Like

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