[SOLVED] Problem with pantograph

I did test it, also then is it meant to look like this (the elbow)?
image

1 Like

Yeahh… did you flip the meshes upside down?

1 Like

image
C0 property, if you put y to -180 it looks like this

1 Like

Wait, could you send me your version?

Also, do you got the mesh detail level all the way up? Because that makes it look messed up lol

Anyways, so far so close? or so far so good lol

1 Like

Here is my update, but I do think that I need to fix something so wait a sec

Pantograph thingy.rbxm (29.3 KB)

1 Like

How is it confusing? He provided all the images. Simply learn trigonometry…

1 Like

Nah all good, thanks!

Alrighty, thanks.

There is an issue with your one,
Your one looks like this

When it should look like this.

For the hand it looks like this
image

I’m not very good at this sort of stuff plus I kind of get it a bit more. Anyways, I think we’ve nearly figured it out mostly storm, but I am in studio trying to see if I can fix the issues above.

Oh, how foolish am I? I now understand why it wasn’t working. The max angle that formula could reach was 45, this was due to the way I decided to calculate it:

By splitting the triangle into two triangles I can indeed use the same formula, but I forgot to take into account what would happen if the desired angle was more than the double of the bar size. This would break the right triangle’s very concept, the 90° angle must oppose the hypotenuse, so by having it higher than the bar size I am essentially breaking math.

To fix this I refactored how I thought about the problem, rather than splitting the triangle in two, I am going to take everything into account and use the cosine law instead. This will allow me to go past 90° and ignore right angles completely. Once I am done I’ll send the code.

1 Like

Ahh, alright thanks!

I was recommended by someone to use acos but I’m not sure how to use that or anything even then I probably still wouldn’t of been able to do this at least the Devforum exists lol.

If possible do you think you could make it so the C1 updates instead of using desired angle? I feel that it would be a performance thing if it animates constantly.

1 Like

There you go pal, everything is fixed and only using C1 updates:
Pantograph Working.rbxm (30.3 KB)

2 Likes

Thanks so much! I don’t think I could have of ever done this by myself! Been stuck on this issue for a few months lol. I’m reading the math that was done for it and its like I don’t know what that means lol

However one last issue, how could I make it so the top of the hand touches underneath the wire?

image

Other than that I think its ready to be chucked on top of the train and ready to move.

1 Like

Move the anchor point, the A part is the thing that is considered when doing the calculation, either that or you can lower the height by modifying the C0 or C1 values for the Y axis of the handle in Position.

I’ll try option 1, don’t really want to make it any lower than it is when the pantograph is lowered.

Here’s the code. Replace {AMOUNT TO CHANGE Y HERE} with the studs in Y. For example: -0.5 or so

local MAXIMUM_DISTANCE = 20;

local raycastParams = RaycastParams.new();
raycastParams.FilterDescendantsInstances = {script.Parent};
raycastParams.FilterType = Enum.RaycastFilterType.Exclude;

local calculateAngle = function(targetHeight : number, size : number): (number, number)
	local secondAngle = math.acos((size^2*2-(targetHeight^2))/(2*(size^2)));
	if (secondAngle ~= secondAngle) then error("Woah dude, I can't reach that far... I have small arms y'know?") end;
	
	local firstAngle = (math.pi - secondAngle)/2;
	
	return firstAngle, secondAngle;
end

local updatePantograph = function(Pantograph)
	local RaycastResult = workspace:Raycast(Pantograph.OriginRay.Position, Pantograph.OriginRay.CFrame.UpVector * MAXIMUM_DISTANCE, raycastParams)

	if RaycastResult then
		local Wire = RaycastResult.Instance
		local Distance = RaycastResult.Distance

		local lowerArm = Pantograph.LowerArm;
		local upperArm = Pantograph.UpperArm;
		
		local lowerSize = (lowerArm.A.Position - upperArm.A.Position).Magnitude;
		local upperSize = (upperArm.A.Position - Pantograph.VisualHand.A.Position).Magnitude;
		
		local firstAngle, secondAngle = calculateAngle(Distance, (lowerSize + upperSize)/2);
		
		lowerArm.Motor.C0 = CFrame.Angles(0,0,math.pi);
		
		lowerArm.Motor.C1 = CFrame.Angles(0,-math.pi,firstAngle + (math.pi * 0.5));
		upperArm.Motor.C1 = CFrame.Angles(0,0,-secondAngle);

		Pantograph.VisualHand.Motor.C0 = CFrame.Angles(firstAngle + math.pi * 0.5, 0, 0) * CFrame.new(0,{AMOUNT TO CHANGE Y HERE},0);
	end
end

game:GetService("RunService").Heartbeat:Connect(function()
	updatePantograph(script.Parent.Panto);
end);

Oh no, I’d prefer for the hand not to change position at all and only change orientation so could I take like the Y size of the angles or something for the hand to be touching the wire?

Would using IK animations work? I think you can set parameters

1 Like

Hmmm, I don’t know but its all good now storm helped me with it and it works ok just a inch too high but going to get that sorted.

1 Like

Then removing the distance by half the size of the handle will solve that, since then the calculated distance will be lower than the real distance and the handle would be touching the top.

local MAXIMUM_DISTANCE = 20;

local raycastParams = RaycastParams.new();
raycastParams.FilterDescendantsInstances = {script.Parent};
raycastParams.FilterType = Enum.RaycastFilterType.Exclude;

local calculateAngle = function(targetHeight : number, size : number): (number, number)
	local secondAngle = math.acos((size^2*2-(targetHeight^2))/(2*(size^2)));
	if (secondAngle ~= secondAngle) then error("Woah dude, I can't reach that far... I have small arms y'know?") end;
	
	local firstAngle = (math.pi - secondAngle)/2;
	
	return firstAngle, secondAngle;
end

local updatePantograph = function(Pantograph)	
	local RaycastResult = workspace:Raycast(Pantograph.OriginRay.Position, Pantograph.OriginRay.CFrame.UpVector * MAXIMUM_DISTANCE, raycastParams)

	if RaycastResult then
		local Wire = RaycastResult.Instance
		local Distance = RaycastResult.Distance - Pantograph.VisualHand.Size.Y/2; --change here

		local lowerArm = Pantograph.LowerArm;
		local upperArm = Pantograph.UpperArm;
		
		local lowerSize = (lowerArm.A.Position - upperArm.A.Position).Magnitude;
		local upperSize = (upperArm.A.Position - Pantograph.VisualHand.A.Position).Magnitude;
		
		local firstAngle, secondAngle = calculateAngle(Distance, (lowerSize + upperSize)/2);
		
		lowerArm.Motor.C0 = CFrame.Angles(0,0,math.pi);
		
		lowerArm.Motor.C1 = CFrame.Angles(0,-math.pi,firstAngle + (math.pi * 0.5));
		upperArm.Motor.C1 = CFrame.Angles(0,0,-secondAngle);

		Pantograph.VisualHand.Motor.C0 = CFrame.Angles(firstAngle + math.pi * 0.5, 0, 0);
	end
end

game:GetService("RunService").Heartbeat:Connect(function()
	updatePantograph(script.Parent.Panto);
end);
1 Like

Ahh thanks! This worked! Another problem, I don’t think the hand is rotating to match the wire?

1 Like