How to add friction to Unity HingeJoint? - unity3d

I attach a rigidbody to a HingeJoint in Unity.
It's attached no at the the center of an anchor of a joint.
To stop it from falling I set Use Motor = true, Target Velocity = 0 and apply some force to the motor.
However, this does not help, see video:
http://g.recordit.co/JJ0cmfT1Mb.gif
Here is the sample project: https://drive.google.com/open?id=0B8QGeF3SuAgTNnozX05wTVJGZHc
Screen to reproduce the issue (there is no code):
How can I apply a friction to a joint to stop rigidbody from moving?
Setting spring with damper or applying a limit is not an option for me, because I need to rotate the rigidbody correctly when I apply enough torque (force) to a motor.
If I switch damper/limit on and off, the rigidbody will move faster when it is rotated in a direction of falling and slower when it is rotated in opposite direction.

I've put together a behaviour that applies friction on a hinge joint. Here it is:
using UnityEngine;
public class JointFriction : MonoBehaviour {
[Tooltip("mulitiplier for the angular velocity for the torque to apply.")]
public float Friction = 0.4f;
private HingeJoint _hinge;
private Rigidbody _thisBody;
private Rigidbody _connectedBody;
private Vector3 _axis; //local space
// Use this for initialization
void Start () {
_hinge = GetComponent<HingeJoint>();
_connectedBody = _hinge.connectedBody;
_axis = _hinge.axis;
_thisBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate () {
var angularV = _hinge.velocity;
//Debug.Log("angularV " + angularV);
var worldAxis = transform.TransformVector(_axis);
var worldTorque = Friction * angularV * worldAxis;
_thisBody.AddTorque(-worldTorque);
_connectedBody.AddTorque(worldTorque);
}
}
This answers the headline of your question, and is what I was looking for when I found it. However this probably won't work for what you want from your more detailed description.
This applies friction that is proportional to the angular velocity, if there's no angular velocity, no force is applied. This means that under a constant force, like gravity in your example, it will always move at some reduced speed. In reality, imperfections in materials and other real world messiness mean that applying friction to joints can keep them still against a constant torque, but in a game engine, you will need some other torque to counter your constant force.

It sounds like you don't want gravity. You can just turn gravity off in the rigid body's inspector.

Related

Detect collisions between 2 objects

I'm trying to do a little game on mobile using Unity and I've got a problem with the rotation of a maze.
To add context :
When your moving your finger on the screen, the maze is rotating on himself. There is a ball in it and you need to make it go on a cell to win the level.
When the maze is rotating too fast, the ball falls down and go through the ground and I don't know how to fix it.
I tried to play with the gravity, colliders...
This is the same when the ball is jumping (when the maze is going up and down quickly).
For the moment I just reset the ball position when you're falling.
{
ball.transform.position = new Vector3(0, 2, 0);
maze.transform.position = Vector3.zero;
maze.transform.rotation = Quaternion.identity;
}
Do you guys have some ideas ? Thanks
I had a similar problem in a tilt maze mini-game I worked on. Ideally implementing jkimishere's solution will work but I assume the maze is moving too fast for the collisions to register properly. You'll need to smooth the maze's rotation with a Lerp. In our case we had pressure plates with a tilt value, so it doesn't directly translate to your mobile use but perhaps give you a nudge in the right direction. We used:
public GameObject maze;
private float _lerpTime;
private bool _isRotating;
private Quaternion _startingRot, _desiredRot;
private void Awake()
{
_startingRot = maze.transform.localRotation;
}
private void Update()
{
//Don't want to move the maze if we don't ask for it
if(!_isRotating)
return;
//Lerp the maze's rotation
_lerpTime = Mathf.Clamp(_lerpTime + Time.deltaTime * 0.5f, 0f, 1f);
maze.transform.localRotation = Quaternion.Lerp(_startingRot, _desiredRot, _lerpTime);
//Once the maze gets where it needs to be, stop moving it
if(affectedObject.transform.localRotation.Equals(_desiredRot)
_isRotating = false;
}
private void ActivateTilt()
{
//Set the new starting point of the rotation.
_startingRot = maze.transform.localRotation;
//However you want to calculate the desired rotation here
//Reset our lerp and start rotating again
_lerpTime = 0f;
_isRotating = true;
}
This will ease the rotation of your maze over time. So that the ball can adapt to the new collider positions.
In the rigidbody(for the ball), make the collision detection to continuous, and in the rigidbody for the maze(if you have one) set the collision detection to continuous dynamic. Hope this helps!
I think that is unavoidable if you allow the player to move the platform freely. I suggest you restrain the speed at wich the player can tilt the platform. This way, the ball will have more frames to adapt to the new slope

Circle Collider Slides on Box Collider when Velocity is slowing down?

I am trying to create a carrom 2D game for learning, i added box colliders 2D all sides and for striker circle collider 2D, and set physics material for all as friction 0 and bounciness 1. and Linear Drag to 1 for stiker.
It all works fine when velocity of impact of striker with sides but velocity is slow its dragging on slides instead of bouncing. where am i doing it wrong?
I am not sure what the problem is but seems like something to do with how the engine is resolving the physics. Try resolving the collision for the individual carrom tokens manually when they hit a surface instead of relying on physics material.
Here is a simple 2D example:
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class ReflectingObject : MonoBehaviour {
[Range(0f, 1f)]
public float bounciness = 1;
private Rigidbody2D m_Rb;
void Awake() {
m_Rb = GetComponent<Rigidbody2D>();
}
void OnCollisionEnter2D(Collision2D col) {
if(col.contactCount > 0) {
// Get the collision contact point
ContactPoint2D point = col.contacts[0];
// Get the current speed of this object
float speed = m_Rb.velocity.magnitude;
// Get the direction where this object is heading to
Vector2 oldDirection = (Vector2)m_Rb.velocity.normalized;
// Get the reflected direction
Vector2 newDirection = Vector2.Reflect(oldDirection, point.normal).normalized;
// Calculate new velocity based on bounciness
Vector2 newVelocity = newDirection * speed * bounciness;
// Assign the velocity
m_Rb.velocity = newVelocity;
}
}
}
Something like this.
Assign this Component to the objects which you want to reflect on collision.

Rotate a Rigidbody to align with an orientation

I'm currently setting the rotation of a player object so that it "stands up" relative to the spheroid the user stands on.
However, that will break Rigidbody physics.
I already have the direction of gravity as a Quaternion, how can add torque to the Rigidbody so that it aligns with that direction?
Here's my code on Github, which does allow the player to move around the surface of the planet.
I have tried various approaches using AddTorque and Vector3.Cross, but they have all only ended in the Rigidbody spinning wildly.
Instead of using transform whenever a Rigidbody is involved rather first calculate the needed final Quaternion ad then apply it using theRigidbody.MoveRotation which does not break the physics.
The same also accounts to the position where you should rather use theRigidbody.MovePosition.
Both should be used in FixedUpdate so
either move the entire code from Update to FixedUpdate
or split the input and the physics and do your API stuff in Update, store the relevant values into fields but apply anything related to the Rigidbod transformations reactive in FixedUpdate.
Your code is quite complex so I will only give an example as a pseudo code and hope you can take it from there
So instead of doing e.g.
private void Update ()
{
player.transform.position = XYZ;
// Applies a world space rotation
player.transform.rotation = XYZW;
// Adds a relative rotation in local space
player.transform.Rotate(x,y,z);
}
You would rather do something like
[SerializeField] Rigidbody playerRb;
private Vector3 targetPosition;
private Quaternion targetRotation;
private void Awake ()
{
if(!playerRb) playerRb = player.GetComponent<Rigidbody>();
}
private void Update ()
{
targetPosition = XYZ;
targetRotation = XYZW * Quaternion.Euler(x,y,z);
}
private void FixedUpdate ()
{
playerRb.MovePosition(targetPosition);
playerRb.MoveRotation(targetRotation);
}

Unity 3D realistic accelerometer control

How do we achieve a control similar to this game?
https://play.google.com/store/apps/details?id=com.fridgecat.android.atiltlite&hl=en
You can do this with builtin physics:
create a level from some simple scaled cubes (don't forget the ground).
add the ball - a sphere, then and add a RigidBody to it. Set a constraint on the rigidbody - check freeze position y (or it will be able to jump out of the level if you put the device upside down).
add this script anywhere on the scene (for example to the camera):
using UnityEngine;
public class GravityFromAccelerometer : MonoBehaviour {
// gravity constant
public float g=9.8f;
void Update() {
// normalize axis
Physics.gravity=new Vector3(
Input.acceleration.x,
Input.acceleration.z,
Input.acceleration.y
)*g;
}
}
or if you want the physics to just affect this one object, add this script to the object and turn off it's rigidbody's affected by gravity:
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class ForceFromAccelerometer : MonoBehaviour {
// gravity constant
public float g=9.8f;
void FixedUpdate() {
// normalize axis
var gravity = new Vector3 (
Input.acceleration.x,
Input.acceleration.z,
Input.acceleration.y
) * g;
GetComponent<Rigidbody>().AddForce (gravity, ForceMode.Acceleration);
}
}
And now you have working ball physics. To make the ball behave as you'd like, try to play with the rigidbody properties. For example, change the drag to something like 0.1.

How to add friction to a Wheel of Fortune in Unity3D

First of all I am new to unity as will as C#. I want to create a Wheel of Fortune for my game using C# where you can rotate it with the mouse. I wrote this code in C# - it works well, the only problem is I don’t know how to add friction to it so that if I release the mouse button it still continues rotating and slows down until it is fully stopped (Just like a realistic Fortune Wheel).
using UnityEngine;
using System.Collections;
public class RotateCSharp : MonoBehaviour
{
public int speed;
public float lerpSpeed;
float xDeg;
float yDeg;
Quaternion fromRotation;
Quaternion toRotation;
void Update()
{
if (Input.GetMouseButton(0))
{
xDeg -= Input.GetAxis("Mouse X") * speed;
fromRotation = transform.rotation;
toRotation = Quaternion.Euler (yDeg,xDeg,0);
transform.rotation = Quaternion.Lerp(fromRotation, toRotation, Time.deltaTime * lerpSpeed);
}
}
}
How can I accomplish this?
Full Disclosure--I don't do Unity, and not much C#, but this is mostly math.
Friction from sliding or rolling is almost exactly constant deceleration. Deceleration is negative acceleration, and acceleration is (velocity change)/(elapsed time).
Figure out how long you want the wheel to spin at a the maximum initial angular speed you'll allow, and that speed/time ratio is your deceleration rate. That's a constant for the wheel.
Now, in the code either before or after adjusting the angular position, decrease the speed by the deceleration rate * time interval, being careful not to overshoot 0:
if (speed > 0)
speed = Math.max(0, speed - decelRate*Time.deltaTime);
else
speed = Math.min(0, speed + decelRate*Time.deltaTime);
That assumes that decelRate is a positive value, and will handle spins in either direction.
You may have to adjust the syntax a bit, but that's the basic idea.
I've put together a behaviour that applies friction on a hinge joint. Here it is:
using UnityEngine;
public class JointFriction : MonoBehaviour {
[Tooltip("mulitiplier for the angular velocity for the torque to apply.")]
public float Friction = 0.4f;
private HingeJoint _hinge;
private Rigidbody _thisBody;
private Rigidbody _connectedBody;
private Vector3 _axis; //local space
// Use this for initialization
void Start () {
_hinge = GetComponent<HingeJoint>();
_connectedBody = _hinge.connectedBody;
_axis = _hinge.axis;
_thisBody = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate () {
var angularV = _hinge.velocity;
//Debug.Log("angularV " + angularV);
var worldAxis = transform.TransformVector(_axis);
var worldTorque = Friction * angularV * worldAxis;
_thisBody.AddTorque(-worldTorque);
_connectedBody.AddTorque(worldTorque);
}
}
You can apply this as a separate behaviour to the object with the hinge joint, or you can take bits of it and incorporate them into your behaviour.
This code assumes the hinge joint has a connected rigidbody that it is rubbing against, if that is not the case, simply remove the lines that refer to the _connectedRigidbody.

Categories