[SOLVED] Problem with pantograph

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

Sorry about that, here:

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;

		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);
		
		local handAngle = (upperArm.Orientation - Wire.Orientation).X; --Added your code here
		Pantograph.VisualHand.Motor.C1 = CFrame.fromOrientation(math.rad(-handAngle) + math.pi, 0, 0);
	end
end

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

Thanks!

With the rotation fixed its still a little bit too high how would I fix this?

image

Also a question, this model isn’t the final model so when it comes time for me to re rig it what should the code be if all motors C0 and C1 and A and B parts orientations and positions are all at 0, 0, 0? So basically like the first model I gave you

  1. You can just subtract the distance variable by a set amount, for example, the width of that rope. So like - 0.1 or so.

  2. Assuming the model is similar you just need to do the same you did up to this point. Then just copy over the C0 and C1 values from the model I gave you. It should work the same.

Ok I’ll give that ago.

Changing C0 and C1 properties of motors and welds isn’t exactly easy… it always messes up the part and stuff, keeping the default values are just easier

I’ve managed to fix these.

Issue 1 was fixed and issue 2 was solved after changing some of the values around.

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