From to Rotation Glitching My Character Controller - c#

So I am making a character controller which uses Quaternion.FromToRotation to align the player with the gravity center in this piece of code:
this_body.transform.rotation *= Quaternion.FromToRotation(this_body.transform.up,gravity_up);
And when I am on certain parts of the sphere planet it starts flipping out everywhere, like in this video, and I don't know how to remedy this, although maybe the gravity implementation could be the problem, or the character controller, although I think using relative force should not mess with it.
Gravity Implementation:
float distance = direction.magnitude;
float forceMagnitude = G * (obj.GetComponent<MultiAttractor>().rb.mass * rb.mass) / Mathf.Pow(distance, 2);
Vector3 force = direction.normalized * forceMagnitude;
rb.AddForce(force);
My character controller script is a bit long so I don't think I should bore you with it, although if needed I could provide it.

This is for anyone who is having issues with using Quaternion.FromToRotation with a rigid body character controller:
I did not dig much into your problem but you are manipulating the rotation directly in the code with Quaternion.FromToRotation and also with physics. I think you need to stick to one of the two, because using both might lead to unexpected behaviours. If you introduce a "raw" rotation modification, the physics engine deals with it. – rustyBucketBay
Basically just use physics rotation like Rigidbody.rotation for rotating things like Transform.Rotate or if you want to rotate physics objects like you are adding force, but instead of moving things it rotates things, then use Rigidbody.AddTorque, or just don't use any physics rotations with other types of rotation as it can cause problems, as stated by rustyBucketBay

Related

Unity player collision with horizontal small colliders

I know the title isnt very explanatory, but here's my problem:
I have a player (merely a cube with a rigidbody, a collider and a movement script), and I have a floor made of small 1 by 1 by 1 cubes (cubes with box colliders).
For some reason unknown to me, when my player cube falls and tries to collide horizontally with the floor, he just phases through... But want him to get blocked by the cubes just like it does vertically. Any help would be greatly appreciated ;)
heres how the scene looks like
heres a cube object
heres the player object
Here's a gif of the player going through the floor
Here's my c# player movement script (I know its very bad, but I prefer to put this here just in case its linked to my problem) :
void ApplyMovement()
{
transform.position += new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
}
If you need any more info to help me just tell me, I'll provide it as fast as I can.
The value of
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"))
is framerate-dependent. This means the faster the framerate the faster your object will move. This is usually not what you want. Instead use Time.deltaTime
// Adjust the speed in the inspector
public float speedMultiplicator = 1;
//...
new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")) * speedMultiplicator * Time.deltaTime
to get a framerate-independent movement. Also see the example in Input.GetAxis.
When dealing with RigidBody never change the transform.position (and rotation) directly!
If you would want to make the RigidBody jump to a certain position rather use
rigidBody.position = transform.position + ...;
However what you want is a smooth movement in order to keep the collision detection intact. So you should use RigidBody.MovePosition instead
rigidBody.MovePosition(transform.position + ...);
You don't have to deal with force etc.
Also add a RigidBody component to the floor objects. Even ifnthe object is not moving this improves the collision detection (at the cost of performance in the Physics engine ofcourse). And since the objects are not supposed to move set
isKinematic -> true
use Gravity -> false
you can also set freeze position and freeze rotation.
On both floor and player objects set Collision Detection -> Continous Dynamic. This improves the collision detection and looks for collisions also between frames.
Be aware, however, that dynamic detection is quite expensive so use it only if there is still trouble with too fast objects.
On the player you might want to also use interpolate as well.
Finally
Note that continuous collision detection is intended as a safety net to catch collisions in cases where objects would otherwise pass through each other, but will not deliver physically accurate collision results, so you might still consider decreasing the fixed Time step value in the TimeManager inspector
to make the simulation more precise, if you run into problems with fast moving objects.
For more information see the RigidBody manual and the Colliders manual
I recreated the scenario you described on my end. I put your "ApplyMovement" code in "Update". I was basically able to reproduce your results.
It seems to me that the issue might be Freezing Position X/Z on the Player. I think since you are doing that, you're telling the Rigidbody component that it is not allowed to modify the X/Z positions of the objects as part of it's collision resolution and physics simulation. When I turn those two off, I get results that are (I think) closer to what you're looking for.
One note: your "ApplyMovement" code is frame-locked, meaning your player will move at different speeds at different frame rates. To solve this, you'd need to multiply your Input.GetAxis values by Time.deltaTime.
Also, if your player moves too fast, it'll still be able to pass through collisions and cause odd behavior, so be sure to limit the max movement rate of the player to some reasonable value.
You should be applying a force to the Rigidbody of the character instead of directly manipulating the transform.position (this is preventing the physics engine from resolving the collisions). You're also freezing the X and Z position on the Rigidbody; you don't want that because it entirely prevents the Rigidbody from manipulating those values.
Instead of transform.postion += ... first get a reference to the Rigidbody somewhere in your script (best done in an Awake() method):
private Rigidbody _body;
private void Awake() {
_body = GetComponent<Rigidbody>();
}
Then make sure the vector built from your inputs is being applied to the object's "movement," not its position:
Vector3 inputVector = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// You can multiply this vector by a float to adjust "speed"
_body.ApplyForce(inputVector, ForceMode.VelocityChange);
Finally, you should read up on the different ForceMode options and decide which one fits your preferences: https://docs.unity3d.com/ScriptReference/ForceMode.html
Don't forget this should happen in a FixedUpdate(), not an Update() (all physics operations should be done in FixedUpdate())
As a side note, there is also the possibility your rigidbodies still up moving too quickly and passing through each-other. Even when you're using forces and velocities, this is possible so if your run into this case down the line, investigate Collision Detection Modes. TLDR; they're settings for performance vs accuracy trade-offs.

Unity 2D launch gameObject at a specific angle without affecting speed

I am working on a game where i need to shoot the ball at an angle and power defined by 2 sliders (1 angle slider, 1 power slider). I currently have this code to control the launching of the ball:
public void shoot()
{
float angle = angleSlider.GetComponent<Slider>().value;
float power = powerSlider.GetComponent<Slider>().value;
gameObject.SetActive(false);
ball.GetComponent<Rigidbody2D>().simulated = true;
Vector2 releaseVector = Quaternion.AngleAxis(angle, transform.up) * transform.forward;
ball.GetComponent<Rigidbody2D>().velocity = releaseVector * (power/3);
}
with this current code it works almost perfect apart from one thing. When the angle is like between 30 and 60, the ball is launched well but if i set it to 0 degrees the ball would barely move and on the contrary if i set it to 90 degrees, the ball launches with much more power. How can i set a constant speed for all degrees so that the speed is only affected by the power slider only please? Thanks.
Typically, you shouldn't set the velocity of a rigidbody directly. Per the Unity docs...
In most cases you should not modify the velocity directly, as this can result in unrealistic behaviour.
Instead, you usually want to impart a physical impulse to the ball using an API like AddForce or AddRelativeForce
That is easy.. You have to normalize the releaseVector.
ball.GetComponent<Rigidbody2D>().velocity = releaseVector.normalized * (power/3);
Then adjust the power to what you want. That way you will have the direction u wanted and speed depends on the power value.
If you want to know what normalize do, you can find more information here;
https://docs.unity3d.com/ScriptReference/Vector3.Normalize.html

Unity 2D scripted friction equation

I am working on the friction for a square object for after it is done being pushed by the player. The block's movements are controlled purely through script using transform.Translate(velocity) each frame and only a boxcollider2D. I am speculating that because i am controlling the block's movements each frame manually is the reason i can't seem to get the boxcolliders2D's physics material 2D friction to work.
Basically, I am trying to recreate the built in physics similar to rigidbodies by using transform.translate, or use the built in physics if possible. So far, i've landed on something like this
newVelocity.x -= ( 1 / (newVelocity.x * newVelocity.x));
In an attempt to reduce the velocity.x each frame until it hits 0 and shorts out. Obviously, this falls apart when the velocity.x becomes a decimal number. I'm stumped on what i should be doing to achieve a friction similar to rigid bodies where it slows down a little at first and then much faster towards the end as it stops. Any and all help appreciated, thanks in advance!
You could compare the signs of the velocity before and after calculating the change in velocity, and set the velocity to zero when the sign changes, like so:
newVelocity.x -= ( 1 / (newVelocity.x * newVelocity.x));
if(Mathf.Sign(previousVelocity.x) != Mathf.Sign(newVelocity.x)) {
newVelocity.x = 0f;
}
One thing, though, is that normal friction is not calculated using the above equation, it's calculated as follows:
newVelocity.x -= frictionCoefficient*Time.fixedDeltaTime;
And with this, you wouldn't need to compare the velocity to the previous velocity as you can just say if the velocity is low, it's zero. You could still compare the previous velocity sign stuff if you wanted to though, but this is probably more efficient
if(newVelocity.x < 0.01f) {
newVelocty.x = 0f;
}

Rigidbody not acting as expected

For the past few days I have been working on some custom car physics as a coding exercise.
What my ultimate goal is to have some semi-realistic car physics something in between the quality of the older GTA games and the recent GTA 5.
Now what I got so far is a quite intricate process which eventually gives me a float which is the exact speed I want the car to go until the next frame, so far I have used the following code to do that;
this.transform.Translate (0, 0, speed * Time.deltaTime);
However because I want to use the Unity build in physics for collision detection I realised this wouldn't work because transform.Translate (as far as I know) literally places the object at that position, thus the object could (if going fast enough) suddenly be halfway stuck through a wall or just completely ignore the collision and appear on the other side of the wall. Now instead I decided to do this:
rb.velocity = transform.forward * speed;
To quickly note, I am doing both of these in my FixedUpdate and I am currently only using the second example (or at least trying to use it and am miserably failing at it). Due to it being in the fixed update I should be able to at least test it to a certain extend without Time.deltaTime usage, which is why you aren't seeing that in the second example right now.
To continue my story, for some reason when I set the velocity of the rigidbody instead of using transform.Translate my collision acts really strangely. The car becomes all floaty and nudges forward (stands on its nose) when I hit the wall, I have no clue what could be causing this seeing as I am using my own gravity (the gravity from the original Rigidbody is turned off in favor of my own custom gravity, which does result in a downward rigidbody force) and the drag, and angular drag of the rigidbody have been turned down to 0.
Basically my question is do any of you guys have an idea of what could be causing my rigidbody to be reacting in such a manner, literally the only difference between my normal code and the code that is acting up is that single line change.
I've looked in to using rigidbody.AddForce() instead but that just doesn't seem to do anything at all and on top of that the whole reason why I am writing my car script is to determine the velocity the object should be moving at thus making something like rigidbody.AddForce() which adds it to the velocity of the car more or less redundant and shouldn't be necesarry.
The only reason why I'm even using a rigidbody in the first place is so I can do two things: 1. Easy collisions. It means I can add simple forces such as gravity to it and not have to worry about it going through the floor. 2. easy rotations when affected by physics such as collisions.
If anyone has any ideas on how to do these two things in a custom script I'd much rather do that because as much as I like unity the Unity rigidbody physics are practically worthless in my eyes, however a must have because I can't write my own custom rigidbody and I can't find the source code of the Unity Rigidbody either. What I'd rather have is a stripped down version of the rigidbody which allows for easy collisions and easy rotation but without all the stuff like the build in drag or velocity because these are the exact things I want to be able to control myself and have been able to control myself so far when I use transform.Translate, but I lose this control when I have to use rigidbody.velocity.
according to the documentation you shouldn't use rb.velocity to change the velocity regularly - it could result in unrealistic physics
http://docs.unity3d.com/ScriptReference/Rigidbody-velocity.html
instead use rb.addforce
http://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html
hopefully that will solve the issue!
Replace the Translate with the following:
rb.MovePosition(transform.position + transform.forward * (speed * Time.deltaTime));
MovePosition basically acts as a translate (if you do it like this) except it also counts collisions in to it.
If you want super realistic 3D car physics, should look into ready assets like:
Edy's Vehice Physics https://www.assetstore.unity3d.com/en/#!/content/403
Also from Unite2015 talks, see example project: "EasySuspension" to build sample 3D car by script:
http://bit.ly/1y8ucNW (from video: https://youtu.be/WGvuP6vV6j4?t=17m8s )
Or is the game top down 2D game? (like early GTA's)

Simple 2D rocket dynamics

I am currently experimenting with some physics toys in XNA using the Farseer Physics library, however my question isn't specific to XNA or Farseer - but to any 2D physics library.
I would like to add "rocket"-like movement (I say rocket-like in the sense that it doesn't have to be a rocket - it could be a plane or a boat on the water or any number of similar situations) for certain objects in my 2D scene. I know how to implement this using a kinematic simulation, but I want to implement it using a dynamic simulation (i.e. applying forces over time). I'm sort of lost on how to implement this.
To simplify things, I don't need the dynamics to rotate the geometry, just to affect the velocity of the body. I'm using a circle geometry that is set to not rotate in Farseer, so I am only concerned with the velocity of the object.
I'm not even sure what the best abstraction should be. Conceptually, I have the direction the body is currently moving (unit vector), a direction I want it to go, and a value representing how fast I want it to change direction, while keeping speed relatively constant (small variations are acceptable).
I could use this abstraction directly, or use something like a "rudder" value which controls how fast the object changes directions (either clockwise or counter clockwise).
What kind of forces should I apply to the body to simulate the movement I'm looking for? Keep in mind that I would also like to be able to adjust the "thrust" of the rocket on the fly.
Edit:
The way I see it, and correct me if I'm wrong, you have two forces (ignoring the main thrust force for now):
1) You have a static "fin" that is always pointed in the same direction as the body. If the body rotates such that the fin is not aligned with the direction of movement, air resistance will apply forces to along the length of the fin, proportional to the angle between the direction of movement and the fin.
2) You have a "rudder", which can rotate freely within a specified range, which is attached some distance from the body's center of mass (in this case we have a circle). Again, when this plane is not parallel to the direction of movement, air resistance causes proportional forces along the length of the rudder.
My question is, differently stated, how do I calculate these proportional forces from air resistance against the fin and rudder?
Edit:
For reference, here is some code I wrote to test the accepted answer:
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
float dc = 0.001f;
float lc = 0.025f;
float angle = MathHelper.ToRadians(45);
Vector2 vel = new Vector2(1, 0);
Vector2 pos = new Vector2(0, 0);
for (int i = 0; i < 200; i++)
{
Vector2 drag = vel * angle * dc;
Vector2 sideForce = angle * lc * vel;
//sideForce = new Vector2(sideForce.Y, -sideForce.X); // rotate 90 degrees CW
sideForce = new Vector2(-sideForce.Y, sideForce.X); // rotate 90 degrees CCW
vel = vel + (-drag) + sideForce;
pos = pos + vel;
if(i % 10 == 0)
System.Console.WriteLine("{0}\t{1}\t{2}", pos.X, pos.Y, vel.Length());
}
}
When you graph the output of this program, you'll see a nice smooth circular curve, which is exactly what I was looking for!
If you already have code to integrate force and mass to acceleration and velocity, then you just need to calculate the individual part of each of the two elements you're talking about.
Keeping it simple, I'd forget about the fin for a moment and just say that anytime the body of your rocket is at an angle to it's velocity, it will generate a linearly increasing side-force and drag. Just play around with the coefficients until it looks and feels how you want.
Drag = angle*drag_coefficient*velocity + base_drag
SideForce = angle*lift_coefficent*velocity
For the rudder, the effect generated is a moment, but unless your game absolutely needs to go into angular dynamics, the simpler thing to do is let the rudder control put in a fixed amount of change to your rocket body angle per time tick in your game.
I suddenly "get" it.
You want to simulate a rocket powered missile flying in air, OK. That's a different problem than the one I have detailed below, and imposes different limits. You need an aerospace geek. Or you could just punt.
To do it "right" (for space):
The simulated body should be provided with a moment of inertia around its center of mass, and must also have a pointing direction and an angular velocity. Then you compute the angular acceleration from the applied impulse and distance from the CoM, and add that to the angular velocity. This allows you to compute the current "pointing" of the craft (if you don't use gyros or paired attitude jets, you also get a (typically very small) linear acceleration).
To generate a turn, you point the craft off the current direction of movement and apply the main drive.
And if you are serious about this you also need to subtract the mass of burned fuel from the total mass and make the appropriate corrections to the moment of inertia at each time increment.
BTW--This may be more trouble than it is worth: maneuvering a rocket in free-fall is tricky (You may recall that the Russians bungled a docking maneuver at the ISS a few years ago; well, that's not because they are stupid.). Unless you tell us your use case we can't really advise you on that.
A little pseudocode to hint at what you're getting into here:
rocket {
float structuralMass;
float fuelMass;
point position;
point velocity;
float heading;
float omega; // Angular velocity
float structuralI; // moment of inertia from craft
float fuelI; // moemnt of inertia from the fuel load
float Mass(){return struturalMass + fuelMass};
float I(){return struturalI + fuelI};
float Thrust(float t);
float AdjustAttitude(float a);
}
The upshot is: maybe you want a "game physics" version.
For reason I won't both to go into here, the most efficient way to run a "real" rocket is generally not to make gradual turns and slow acceleration, but to push hard when ever you want to change direction. In this case you get the angle to thrust by subtracting the desired vector (full vector, not the unit) from the current one. Then you pointing in that direction, and trusting all out until the desired course is reached.
Imagine your in floating in empty space... And you have a big rock in your hand... If you throw the rock, a small impulse will be applied to you in the exact opposite direction you throw the rock. You can model your rocket as something that rapidly converts quantum's of fuel into some amount of force (a vector quantity) that you can add to your direction vector.

Categories