Making a UI element face a relative movement position?

I’m currently working on a 2D game based off the popular game Just Shapes and Beats.

Recently I was working on the character framework when I came across a small issue. In the original Just Shapes and Beats, your character would face towards your movement goal/position.

Example of Character movement

2021-01-07-14-34-17


Currently, I have only been able to replicate a similar humanoid feature for the character but I have not been able to replicate the Rotation goal or “LookCFrame” if you want to put it as so.

My version of movement

2021-01-07-14-37-48


Comparing both movement styles together makes mine look very bland, lazy and boring which is why I want to at least try to replicate a similar style for my own game.

Thanks in advance!

So the end-goal here should be to set the Rotation of your UI object to face the direction of movement. To do this, we first need to figure out the angle between the UP direction (where Rotation is 0) and the movement direction. To do this, we can get the arc-cosine of the dot product of both normalized directional vectors. This works for both Vector2s and Vector3s. But only need Vector2 in this case:

local function AngleBetween(vectorA, vectorB)
	return math.acos(math.clamp(vectorA.Unit:Dot(vectorB.Unit), -1, 1))
end

And then from there, we can set the rotation:

myGui.Rotation = math.deg(AngleBetween(Vector2.new(0, 1), movementVector))

I don’t know how you’re defining movementVector, so that’s up to you to plug in.

2 Likes

Thats a really interesting answer but im not entirely sure how I would implement it into my script.

Would you be able to explain what movementVector would be?

Im not entirely good at the math portion of coding yet haha, but Im really interested in what results I can yield with your answer.

Current I’ve implemented this by turning my “Character Frame” Position into a Vector2 but it only seems to return nan (not a number).

Heres my Code:

local function AngleBetween(vectorA, vectorB)
	return math.acos(math.clamp(vectorA.Unit:Dot(vectorB.Unit), -1, 1));
end

--// Rotation Handling
local CharaterPos = Character.Position;
Character.Rotation = math.deg(AngleBetween(Vector2.new(0, 1), Vector2.new(CharaterPos.X.Scale, CharaterPos.Y.Scale)))

How are you currently moving your character around?

2 Likes
--// Inputs
UserInputService.InputBegan:Connect(function(Input, Processed)
	if Processed then return end
	
	--// Movement Handling
	if table.find(MovementKeyCodes, Input.KeyCode) then
		table.insert(MoveDirections, Input.KeyCode);
	end
	
	--// Mechanic Handling
	if Mechanics[Input.KeyCode] or table.find(Mechanics, Input.KeyCode) then
		Mechanics[Input.KeyCode](Character);
	end
	
	--// Tween Movements
	if next(MoveDirections) and table.getn(MoveDirections) <= 1 then
		if Tweens["BackSize"] then
			Tweens["BackSize"]:Cancel();
		end
		
		Tweens["Shrink"] = TweenService:Create(Character, TweenInfo.new(0.5, Enum.EasingStyle.Back), {
			Size = UDim2.fromOffset(15, 15),
		});

		Tweens["Shrink"]:Play();
		Tweens["Shrink"].Completed:Wait();
		Tweens["Shrink"] = nil;
	end
end)

UserInputService.InputEnded:Connect(function(Input)
	if table.find(MoveDirections, Input.KeyCode) then
		table.remove(MoveDirections, table.find(MoveDirections, Input.KeyCode));
		
		if not next(MoveDirections) then
			Character.Rotation = 0;
			Tweens["BackSize"] = TweenService:Create(Character, TweenInfo.new(1, Enum.EasingStyle.Elastic), {
				Size = UDim2.fromOffset(20, 20),
			});
			
			Tweens["BackSize"]:Play();
			Tweens["BackSize"].Completed:Wait();
			Tweens["BackSize"] = nil;
		end
	end
end)

--// Mover
RunService.Heartbeat:Connect(function()
	if next(MoveDirections) ~= nil and Character ~= nil then
		local Humanoid = Character.Humanoid;
		local MoveSpeed = Humanoid.Speed.Value;
		
		--// Handle Movements
		if table.find(MoveDirections, Enum.KeyCode.W) then
			Character.Position -= UDim2.fromOffset(0, MoveSpeed);
		end
		
		if table.find(MoveDirections, Enum.KeyCode.A) then
			Character.Position -= UDim2.fromOffset(MoveSpeed, 0);
		end
		
		if table.find(MoveDirections, Enum.KeyCode.S) then
			Character.Position += UDim2.fromOffset(0, MoveSpeed);
		end
				
		if table.find(MoveDirections, Enum.KeyCode.D) then
			Character.Position += UDim2.fromOffset(MoveSpeed, 0);
		end
		
		--// Rotation Handling
		local CharaterPos = Character.Size;
		Character.Rotation = math.deg(AngleBetween(Vector2.new(0, 1), Vector2.new(CharaterPos.X.Scale, CharaterPos.Y.Scale)))
	end
end)

This is pretty much the code I use to move the character.
The character itself is just a frame inside of a “PlayerDump” frame with the size of 1,0,1,0