- Home /
rotate a hand crank with circular mouse motion?
hello. I have here a little problem which I cannot solve. I have not really a good idea how I could achieve this in my game.
my Game should be a 3D first person horror game.
basically it should work like this.
I want that the mouse controls for the player are deactivated and activated for the crank so that I can control the crank. that would no problem.
but I want that the player needs to rotate his mouse in a circular motion to rotate the crank to wind someting up or open a door. like in this picture.
with one axis it would be no problem because I can map that to a float. but like in the middle picture a circular motion needs X and Y ....
the crank on the right picture should only show how the crank could look like in my game.
what I already got coded was not that good. it was a empty that moves in its own vector2 and it is clamped to a distance to its parent. so I thought I could then just model a crank and let the Z axis look at the empty and then it would rotate with my mouse... but if I would rotate the mouse in a very small circle or would move the mouse from left to right it would instantly snap to the other side or it would rotate way too fast.... so that idea is not good.....
please help.
Answer by sparkzbarca · Dec 28, 2013 at 12:39 AM
the way i would do this
create a mesh which is just a circular plane in your modeling program so you got a circle
tahts going to be your collider mesh
create an empty game object with that mesh collider attached and center it on your crank. it should basically be a circle the outside edge of which the crank handle would trace in movement. Got that?
Good
now your going to take the mouse position in word space and place it on the same plane as this collider of course. Since the mouse position is only 2d on the screen you get the third dimension (in this case the Z depth) by making it equal to the collider object Z.
Now you are going to do a raycast from the mouse position to the center of this mesh collider object.
that will give you info about the point on the edge of the collider closest to the mouse
with that info you now know what you need to know
you move the crank handle from current position to the closest point on bounds
if you like you can do this through a simple rotation around the Z axis
the angle to rotate is the angle between A & B where
A = crankknobpiece.transform.position - crank center point.transform.position
basiscally your going to need to know 2 things where the handle part of the crank is and where the actual shaft it rotates part is
B = nearest point on bounds so the raycasthit.point - crank center point
now you have
mouse - - - handle---crank center
and you can use vector3.angle(A,B) to find the angle between mouse and handle from crank center point
then you rotate around the z axis angle degrees and arrive
YAY
... ok... I think that is almost the same I already coded...... somewhat... but would't it then also rotate very fast if my mouse makes very small circles?
here look that is the script I use now... it has a parent that is the center of my crank so its an empty. then I have the object that is for now just a sphere.
var Parent : Transform;
var Obj : Transform;
var Radius = 5;
var Dist : float;
var $$anonymous$$ousePosX : float;
var $$anonymous$$ousePosY : float;
var $$anonymous$$ouse$$anonymous$$atrix : Vector2;
var $$anonymous$$ouseOffset : Vector3;
var NormOffset : Vector3;
var Norm2Offset : Vector3;
function Update()
{
$$anonymous$$ousePosX += Input.GetAxis ("$$anonymous$$ouse X");
$$anonymous$$ousePosY += Input.GetAxis ("$$anonymous$$ouse Y");
$$anonymous$$ousePosX = $$anonymous$$athf.Clamp ($$anonymous$$ousePosX, -5, 5);
$$anonymous$$ousePosY = $$anonymous$$athf.Clamp ($$anonymous$$ousePosY, -5, 5);
$$anonymous$$ouse$$anonymous$$atrix = Vector2 ( $$anonymous$$ousePosX, $$anonymous$$ousePosY );
ParentVec = Vector2 (Parent.position.x, Parent.position.y);
$$anonymous$$ouseOffset = $$anonymous$$ouse$$anonymous$$atrix - ParentVec;
Obj.position.x = $$anonymous$$ousePosX;
Obj.position.y = $$anonymous$$ousePosY;
Dist = Vector2.Distance(Vector2(Obj.position.x, Obj.position.y), Vector2(Parent.position.x, Parent.position.y));
if(Dist > Radius)
{
var norm = $$anonymous$$ouseOffset.normalized;
NormOffset = norm;
Obj.position.x = norm.x*Radius + Parent.position.x;
Obj.position.y = norm.y*Radius + Parent.position.y;
}
if(Dist < Radius)
{
var norm2 = $$anonymous$$ouseOffset.normalized;
Norm2Offset = norm2;
Obj.position.x = norm2.x*Radius + Parent.position.x;
Obj.position.y = norm2.y*Radius + Parent.position.y;
}
}
the way i described was to find the point nearest the mouse, the thing is unless the crank is really small, basically its going to take however long it takes you to draw a circle around the mouse.
I did forget to deal with yea that you'd have to make sure they were not inside the crank radius drawing small cirlces
for that i'd just do a collider.contains(mousepos)
if so dont turn the crank, so they have to draw a circle around the outside not the inside of the crank
is there really no other way to do this? I mean many games have done this... but on Google I did not find anything useful...
i mean the thing is the way i described isn't actually that hard, honestly you could bang out that code and debug it in maybe 45 $$anonymous$$utes to an hour max.
most games that have that feature use it enough to justify an hour spent coding.
I have now played around again with that code from above and now it works like I want it. I have now 2 vesions made. one that uses the speed of my mouse to rotate and one that uses a SmoothDampAngle function with a fixed speed.
Your answer
![](https://koobas.hobune.stream/wayback/20220613125008im_/https://answers.unity.com/themes/thub/images/avi.jpg)