I create a game and I need use inertia for object.
Example:
The image shows all what I need.
When I touch on screen, blueObject no longer uses the position of brownObject and rotation of redObject. And I add component Rigidbody. The object just falls down. I need him to fall further along his trajectory (inertia).
I tried to use addForce(transform.forward * float), this not work.
By setting the position of the transform, you don't use Unity Physics engine. Your cube must have a rigidbody from the begin of the simulation and what you need here is a spring joint (https://docs.unity3d.com/Manual/class-SpringJoint.html) or a fixed joint.
You need to calculate the current speed, when releasing the object.
Track the positions over the last frame & current frame, and use Time.deltaTime to compensate different frame-rates.
Then set this velocity to your objects rigidbody. (AddForce is just manipulating the velocity, but depending on the ForceMode it respects mass etc.)
public Vector3 lastPosition = Vector3.zero;
void Update()
{
// maybe do : if(lastPosition != Vector3.zero) to be sure
Vector3 obj_velocity = (lastPosition - transform.position) * Time.deltaTime;
lastPosition = transform.position;
// if you release the object, do your thing, add rigidbody, then:
rb.velocity = obj_velocity;
}
That should create the "inertia". the velocity contains the direction and the speed.
Related
First off: I am very new to Unity, as in VERY new.
I want to do the following: I want to rotate a cube around a stationary point (in my case a camera) with a radius that is adjustable in the inspector. The cube should always have its Z-axis oriented towards the camera's position. While the cube is orbiting around the camera, it should additionally follow a sine function to move up and down with a magnitude of 2.
I have some working code, the only problem is an increase in distance over time. The longer the runtime, the higher the distance between the cube and the camera.
Here is what I currently have:
void Awake()
{
cameraPosition = GameObject.FindGameObjectWithTag("MainCamera").transform;
transform.position = new Vector3(x: transform.position.x,
y: transform.position.y,
z: cameraPosition.position.z + radius);
movement = transform.position;
}
I instantiate some variables in the Awake()-method and set the cube's position to where it should be (do you instantiate in Awake()?). I'll use the Vector3 movement later in my code for the "swinging" of the cube.
void Update()
{
transform.LookAt(cameraPosition);
transform.RotateAround(cameraPosition.position, cameraPosition.transform.up, 30 * Time.deltaTime * rotationSpeed);
MoveAndRotate();
}
Here I set the orientation of the cube's z-axis and rotate it around the camera. 30 is just a constant i am using for tests.
void MoveAndRotate()
{
movement += transform.right * Time.deltaTime * movementSpeed;
transform.position = movement + Vector3.up * Mathf.Sin(Time.time * frequency) * magnitude;
}
To be quite frank, I do not understand this bit of code completely. I do however understand that this includes a rotation as it moves the cube along it's x-axis as well as along the world's y-axis. I have yet to get into Vector and matrices, so if you could share your knowledge on that topic as well I'd be grateful for that.
It seems like I have found the solution for my problem, and it is an easy one at that.
First of all we need the initial position of our cube because we need to have access to its original y-coordinate to account for offsets.
So in Awake(), instead of
movement = transform.position;
We simply change it to
initialPosition = transform.position;
To have more readable code.
Next, we change our MoveAndRotate()-method to only be a single line long.
void MoveAndRotate()
{
transform.position = new Vector3(transform.position.x,
Mathf.Sin(Time.time * frequency) * magnitude + initialPosition.y,
transform.position.z);
}
What exactly does that line then? It sets the position of our cube to a new Vector3. This Vector consists of
its current x-value
our newly calculated y-value (our height, if you want to say so) + the offset from our original position
its current z value
With this, the cube will only bop up and down with distancing itself from the camera.
I have also found the reason for the increase in distance: My method of movement does not describe a sphere (which would keep the distance the same no matter how you rotate the cube) but rather a plane. Of course, moving the cube along a plane will automatically increase the distance for some points of the movement.
For instantiating variables in Awake it should be fine, but you could also do it in the Start(){} Method that Unity provides if you wanted to.
For the main problem itself I'm guessing that calling this function every frame is the Problem, because you add on to the position.
movement += transform.right * Time.deltaTime * movementSpeed;
Would be nice if you could try to replace it with this code and see if it helped.
movement = transform.right * Time.deltaTime * movementSpeed;
My ball can only bounce on the y axis. X and Z movement as well as all rotation are locked in the rigidbody component. Originally I was planning to handle this using a combination of the two methods below. I'm adding my own faux-gravity to the object in FixedUpdate and bouncing the ball upwards when it collides with a platform in OnCollisionEnter. Esentially sending it bouncing up and down forever.
void OnCollisionEnter(Collision collision)
{
ball.AddForce(Vector3.up * force, ForceMode.Impulse);
}
void FixedUpdate()
{
Vector3 gravity = globalGravity * Vector3.up;
ball.AddForce(gravity, ForceMode.Acceleration);
}
The problem is that if I place an angled platform under the ball, it no longer bounces vertically with the same force. I believe this is because Unity Physics is calculating the angle/force the object should bounce in a 3D space, and then because of my script only applying the upward force of that calculation. However, I'd like my ball to bounce with a consistent vertical force regardless of the angle of the platform placed under it.
This could be achieved using a coroutine and Lerp to a certain height, which I tried using the script below, using Physics gravity this time, but it didn't have the same natural bouncing feel as Unity Physics. I'd like to go back to using the Physics system but I don't know how to stop Unity from doing the angular calculation and just launch my ball vertically with the force I want.
IEnumerator MoveBall(Vector2 newPos, float time)
{
ball.useGravity = false;
float elapsedTime = 0;
Vector2 startingPos = transform.position;
while (elapsedTime < time)
{
transform.position = Vector2.Lerp(startingPos, newPos, (elapsedTime / time));
elapsedTime += Time.deltaTime;
yield return null;
}
ball.useGravity = true;
}
It sounds like you want your collider to be setup as a trigger. On your ball's collider, set isTrigger to true and then use OnTriggerEnter instead of OnCollisionEnter. This will prevent Unity's physics engine from creating and resolving a Collision between the ball and whatever it hits.
If you'd also want the ball to bounce off other objects in way that uses Unity's Physics, you'll need to then get creative with which colliders are/arent' triggers, and which physics layers they belong to.
I am developing a 2.5D game. In that game I want my character (which has Rigidbody component attached to) to just move on x and y axises. So I use this code snippet:
private void LockZAxis () {
Vector3 currentPosition = _rigidbody.position;
currentPosition.z = 0;
_rigidbody.position = currentPosition;
}
I call this LockZAxis method in the end of both Update, FixedUpdate and LateUpdate. But it doesn't work. When my character run forward for a while, its z position is still changed.
For additional information, in my code, there are two times I manipulate the position of RegidBody. The first is when my character jump, that time I use this:
jumpVelocityVector = Vector3.up * jumpForceUp + transform.forward * jumpForceForward;
_rigidbody.velocity = jumpVelocityVector;
And each frame when I want my character to move a bit faster, so in the update method, I have this:
void Update () {
Vector3 newPosition = transform.position + transform.forward * speed * Time.deltaTime;
newPosition.z = 0;
_rigidbody.MovePosition (newPosition);
LockZAxis ();
}
A rigidbody is used to simulate physics, by setting the rigidbody's position every frame you're essentially teleporting the character every frame. You can restrict movement in z-axis, this will prevent it to move in z-axis when physics is applied, which is what a rigidbody typically is used for.
Here is how to restrict rigidbody positional change:
If you run your LockZAxis() after you've changed the position it should teleport the object to the z-position of 0 every frame. Please make sure that the z-axis is the correct axis. You can debug this by pausing a running game and manipulating the Transform values to see how each axis moves your Object.
Here is how you can do it with C# Script:
Freeze All Positions
rigidbody.constraints = RigidbodyConstraints.FreezePosition;
Freeze Specific Positions:
rigidbody.constraints = RigidbodyConstraints.FreezePositionY | RigidbodyConstraints.FreezePositionZ;
Unity Documentation
Is physics gravity set to only affect the Y position ?
Physics.gravity = new Vector3(0, -1.0F, 0);
And set these also
rigidbody.angularVelocity = Vector3.zero;
rigidbody.velocity.z=0;
make sure your rigidbody is set to kinematic since you are using Rigidbody.moveposition() and using moveposition() will directly effect velocity internally on a kinematic rigidbody
Try using moveposition() for you jump instead of velocity
I am trying to create a third person spaceship movement.
The spaceship rotates about all axes at its position, and has a throttle control to move in forward direction. There is a camera which is always behind it. I am not making the camera a child because I want the camera to NOT follow the rotation about z axes.
The camera has a script, which keeps its position a fixed distance behind the spaceship, and then calls transform.LookAt(spaceShipTarget).
The problem is that as I rotate the ship around global x axes 90 degrees, the y axis of camera suddenly does a 180 degree rotation. The camera control script is below:
using UnityEngine;
namespace UnityStandardAssets.Utility
{
public class FollowBehind : MonoBehaviour
{
public Transform target;
public float distance;
public float delay;
private Vector3 velocity = Vector3.zero;
private void LateUpdate()
{
Vector3 offset = target.transform.TransformVector(0, 0, distance);
Vector3 currentPosition = transform.position;
Vector3 finalPosition = target.position + offset;
transform.position = Vector3.SmoothDamp(currentPosition,
finalPosition, ref velocity, delay);
transform.LookAt(target);
}
}
}
Why would that happen and how can I fix it?
The problem you have with the rotation of the camera is probably caused by the script you use to make the camera follow the spaceship, probably because when you rotate the spaceship the rotation (and probably the position) of the camera are affected.
What you could do instead is make both the spaceship and camera child of another object, and then add a script to this parent object. Now you can put some code in the script of the parent to move the parent itself (this way both camera and spaceship will move together, and you don't need to keep them together manually) and also in the script of the parent you can put some code to rotate the spaceship and camera individually or together based on specific inputs.
I have a script attached to a mesh with a kinematic, rigid body with a convex mesh collider that I'd like to move around. Here's what I call in my update function:
if (Input.GetKey(forwards)) {
Debug.Log("forwards!!");
//get current velocity in local space
Vector3 localVel = transform.InverseTransformDirection(body.velocity);
//alter so that forward component = speed
localVel = new Vector3(localVel.x, localVel.y, linearSpeed);
//convert back into world space and set to body
Vector3 worldVel = transform.TransformDirection(localVel);
body.velocity = worldVel;
}
Other Info:
body is a Rigidbody variable that I assign in Start() using GetComponent<Rigidbody>();
linearSpeed is a float with value 1
I'm getting the Debug.Log output, but my mesh is not moving. Is there anything obvious I'm missing here? This is my first script for a 3D, as opposed to a 2D game.
public float speed = 20;
Rigidbody r;
void Start(){
r = gameObject.GetComponent<Rigidbody> (); //Put's reference to local rigidbody into variable "r"
}
void FixedUpdate () {
Vector3 direction = Vector3.zero; //set's current direction to none
//Adds vectors in case that user is pressing the button
if(Input.GetKey(KeyCode.W)) direction += Vector3.forward;
if(Input.GetKey(KeyCode.S)) direction -= Vector3.forward;
if(Input.GetKey(KeyCode.D)) direction += Vector3.right;
if(Input.GetKey(KeyCode.A)) direction -= Vector3.right;
//Normalizez direction (put's it's magnitude to 1) so object moves at same speeds in all directions
r.AddForce (direction.normalized * speed); //Adds direction with magnitude of "speed" to rigidbody
}
Rigidbody MUST be attached to same GO as this script. This script uses world directions, because working with local directions is much harder (the object is rotating and changes directions rapidly, you can use it if you want just by replacing reference to Vector3 to transform like this:
if(Input.GetKey(KeyCode.W)) direction += transform.forward;
Of course for all direction.
This is very basic way to move the object along it's local axises, to do it more better you need to write specific scripts for specific sets of objects, it all depends what kind of object are you moving and how you want to move it. (is it sphere, cube..., will it ever fly up, should it rotate....).
If the RigidBody is Kinematic it is meant to be moved by means other than the physics system; animations, transform.position, etc. Make your rigid body non-kinematic and it should move when you set velocity.