To move and rotate a boat, I use addrelativeforce and addrelativetorque.
Now it turns out that the boat starts to drift sometimes, i.e. it moves in a direction perpendicular to it’s forward direction (sideways, like a crab’s walk). I’m a bit puzzled about how this can happen. Anyone any insights on this?
Some code would help ![]()
Here is my code:
function OnMouseDown(){
aDefault = stickReference.transform.localEulerAngles;
aCurr = aDefault;
}
function OnMouseUp(){
//reset joystick to default Position
transform.localEulerAngles = aDefault;
aCurr = aDefault;
}
function OnMouseDrag(){
aDefault = stickReference.transform.localEulerAngles;
ray = Camera.mainCamera.ScreenPointToRay (Input.mousePosition);
//ray.origin -- the mouse position in world space at the near plane of the camera
//ray.direction -- the direction of the mouse in world Space
transform.LookAt( ray.origin );
aCurr = transform.localEulerAngles;
}
function FixedUpdate(){
//eulerAngles.y is related to accelleration; eulerAngles.x is related to direction
ship.rigidbody.AddRelativeForce(Vector3.forward * Mathf.Clamp(Mathf.Repeat(( aCurr.x - aDefault.x ) + 180, 360) - 180, -aMax, aMax ) * speedScale * -1 );// need to change [0,360] to [-180,180]
//stop drifting of the ship
if (ship.rigidbody.velocity.magnitude >= speedMax){
ship.rigidbody.velocity = ship.rigidbody.velocity.normalized * (speedMax - 0.1);
}
ship.rigidbody.AddRelativeTorque(Vector3.up * Mathf.Clamp(aCurr.y - aDefault.y, -aMax, aMax ) * aScale );
}
Some explanation:
I have a virtual joystick controlling the boat.
That joystick is a child of the main camera, that actually follows the boat.
This code is in the joystick.
Dragging the joystick creates an angle (the mousedrag function); that angle is used to control movement and rotation of the boat. LocalEulerAngles.x controls forward / backward movement of the boat; localEulerAngles.y controls left and right rotation of the boat. This all happens in the FixedUpdate function.
I had to do some extra code because:
- the x angle was in the range of 0 to 30 and 330 to 360 degrees. So I had to convert that to a -180, 180 range [Mathf.Clamp(Mathf.Repeat(( aCurr.x - aDefault.x ) + 180, 360) - 180, -aMax, aMax )].
- the speed of the boat increased endlessly, so I did kind of a hack to keep it below a certain maximum speed [ if (ship.rigidbody. … etc].
- the Clamp function was needed because I wanted to keep the values in a certain range.
Maybe it will help to post a test project, so you people can easily inspect the behaviour of the boat.
Drag the joystick and the boat will move and rotate. Dragging up / down = forward / backward. Dragging left / right = rotate right / left.
To get the behaviout I’m having troubles with:
move and rotate the boat somewhat, then stop the boat by dragging the joystick down. You’ll see that the (relative) forward movements stops, but there still is some sideways movement.
Why does that happen? What can I do about it?
Hi Henk,
I played with this a bit and am not 100% sure what it is you’re trying to simulate and the issue you’re running into. I toyed with the rigid body’s drag and angular drag settings a bit until it felt closer to being “right” and I’m not seeing what you’re describing, but I think I know what you’re talking about. Most boats/ships have a fair bit of “forward directional stability” thanks to deep, long hulls and keels, so they tend to not to drift sideways. How your boat behaves is more like a hovercraft that very easily slides sideways as it turns. So what you’ll need to do is simulate a form of “relative drag” that is higher when the boat tries to move sideways. One way of doing this is for your script to sense whether the boat is moving sideways and then to add Rigidbody.AddRelativeForce to counteract it. Another is to write your own mini-physics engine to simulate this and not use rigid bodies and force.
Hope this helps…
Ah that makes sense! Indeed, it acts like a hovercraft.
I’ll see if I can correct this by adding an extra relative force.
One more bit: What type of boat are you trying to simulate? Usually when a joystick is used to control a boat (ships and tugs have these) pushing the joystick to the left turns the boat to the left (the opposite of how your example behaves). I’ve been driving ships and boats most of my life, so I can be a bit fussy about little things like that! ![]()
The boat is a fishing trawler.
I wasn’t sure whether it would turn right or left. Now I know. Thanks!
You can probably do this with one line of code.
You can calculate the force with Vector3.Project:-
rigidbody.AddForce(-Vector3.Project(rigidbody.velocity, transform.right) * resistance);
Basically, this determines how much of the velocity is in the boat’s sideways direction. The “resistance” value is just for scaling - experiment with it a bit while the game is running to get a value that feels right.