I am trying to make a game by myself and I encountered a difficulty.
I have this object and I need it to accelerate towards a vector 3 point.
I tried using the Vector3.MoveTowards command, but the object moves with a constant velocity and stops at the destination.
What I need to do is have the object accelerate from 0 velocity towards a vector 3 point and not stop at the point, but continue at the same direction after it went through the point.
Does anyone know how to do this?
Thank you!
Perform these steps in a method that is called in the Update or FixedUpdate method. FixedUpdate is recommended if you are using rigid bodies.
First, you need to find the direction from your position to the point, and define a velocity instance variable in your script if not using Rigid Bodies. If you are using a Rigidbody, use rigidbody.velocity instead. target is the Vector3 position that you want to accelerate towards.
// Use rigidbody.velocity instead of velocity if using a Rigidbody
private Vector3 velocity; // Only if you are NOT using a RigidBody
Vector3 direction = (target - transform.position).normalized;
Then you need to check if we have already passed the target or not. This check makes sure that the velocity remains the same
// If our velocity and the direction point in different directions
// we have already passed the target, return
if(Vector3.Dot(velocity, direction) < 0)
return;
Once we have done this we need to accelerate our Transform or Rigidbody.
// If you do NOT use rigidbodies
// Perform Euler integration
velocity += (accelMagnitude * direction) * Time.deltaTime;
transform.position += velocity * Time.deltaTime;
// If you DO use rigidbodies
// Simply add a force to the rigidbody
// We scale the acceleration by the mass to cancel it out
rigidbody.AddForce(rigidbody.mass * (accelMagnitude * direction));
I recommend that you use a Rigidbody since it makes much more sense when doing something like this.
Related
So my rigidbody controller has a speed limiter with the following code:
Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
// limit velocity if needed
if (flatVel.magnitude > moveSpeed)
{
Vector3 limitedVel = flatVel.normalized * moveSpeed;
rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
}
but for some reason that last line of code:
rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
causes my character's falling speed to reset when moving in midair, when it reaches about -50 units of speed. I've tried modifiying rb.velocity.x and rb.velocity.z seperately, but Unity doesn't allow that. Is there any other way to cap rigidbody speeds without using rb.velocity?
According to the Unity documentation here.
In most cases you should not modify the velocity directly, as this can result in unrealistic behaviour - use AddForce instead Do not set the velocity of an object every physics step, this will lead to unrealistic physics simulation. A typical usage is where you would change the velocity is when jumping in a first person shooter, because you want an immediate change in velocity.
I'd say this is the reason you are encountering the behaviour that you are.
A Unity forum post, found here, suggests the correct way to do this is:
The 'proper' way would be to apply a force in the opposite direction of the rigidbody's velocity. The amount of force should be proportional to the extent to which the rigidbody is exceeding its speed limit.
Another Unity forum post suggests to make use of the ClampMagnitude method, the post can be found here.
private void FixedUpdate()
{
var force = new Vector3(input.x, 0f, input.y) * acceleration;
var velocity = playerRigidbody.velocity + force;
playerRigidbody.velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
}
Hope this helps.
I am playing around with cubes and making a box aim at a cube in unity, but to use quaternion.LookRotation I need to subtract the long box's position from the cube's position, I don't get why. What if I just use quaternion.LookRotation with the cube's position.
void Update()
{
Vector3 directionToFace = cube.position - transform.position;
transform.rotation = Quaternion.LookRotation(directionToFace);
// Idk why but this line worked too : transform.rotation = Quaternion(directionToFace);
}
When I use just the cube's position to aim at, it aims slightly higher but when I subtract it it aims exactly at the cube, and also what's the use of using Quaternion.LookRotation, using just Quaternion works fine too.
cube.position - transform.position is a direction (actually a verctor .. a direction usually is additionally normalized) from your transform.position towards the cube.position.
Only using the cube.position would rather be a direction from the World's origin 0,0,0 towards the cube.
So in case your transform.position is coincidentally currently placed on (or close to) 0,0,0 anyway it might result in (almost) the same direction.
But using cube.position - transform.position is correct in a general usage regardless of if your transform.position matches exactly the world origin 0,0,0.
Unless you have your own implementation of a method called Quaternion taking a Vector3 as parameter your given code would not even compile with Quaternion(directionToFace).
There is no such method we know about.
Also the constructor of Quaternion does not take a Vector3. So it also wouldn't compile if you used new like
transform.rotation = new Quaternion(directionToFace);
I'm trying to use the .AddForce code alongside the .movePosition one, but the .movePosition making the .AddForce do nothing. I think is because the line: " Vector2 movement = new Vector2 (moveHorizontal, 0);" but I really don't know how to fix it. The .AddForce code works as inteded by itself.
Edit: posted full code.
using UnityEngine;
using System.Collections;
public class CompletePlayerController : MonoBehaviour {
public float speed; //Floating point variable to store the player's movement speed.
public float jumpforce;
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
// Use this for initialization
void Start()
{
//Get and store a reference to the Rigidbody2D component so that we can access it.
rb2d = GetComponent<Rigidbody2D> ();
}
//FixedUpdate is called at a fixed interval and is independent of frame rate. Put physics code here.
void FixedUpdate()
{
Jump();
//Store the current horizontal input in the float moveHorizontal.
float moveHorizontal = Input.GetAxis ("Horizontal");
//Store the current vertical input in the float moveVertical.
//Use the two store floats to create a new Vector2 variable movement.
Vector2 movement = new Vector2 (moveHorizontal, 0);
//Call the AddForce function of our Rigidbody2D rb2d supplying movement multiplied by speed to move our player.
rb2d.MovePosition ((Vector2)transform.position + (movement * speed * Time.deltaTime));
}
void Jump(){
if (Input.GetButtonDown("Vertical")){
rb2d.AddForce(new Vector2(0, jumpforce), ForceMode2D.Impulse);
}
}
}
As the names say:
MovePosition
Moves the rigidbody to the specified position by calculating the appropriate linear velocity required to move the rigidbody to that position during the next physics update. During the move, neither gravity or linear drag will affect the body.
AddForce
Adds a force to the Rigidbody
The force is specified as two separate components in the X and Y directions (there is no Z direction in 2D physics). The object will be accelerated by the force according to the law force = mass x acceleration - the larger the mass, the greater the force required to accelerate to a given speed.
So according to the mass and friction of the object it causes it to move with a certain velocity according to the physics.
Mixing both makes not much sense since MovePosition is usually used for isKinematic rigidbodies, so ones that are fully controlled via script while AddForce only has effect on not isKinematic ones, thus fully controlled by physics alone; by mixing both you don't give AddForce a chance to work since you overwrite the linear velocity of the rigodbody by using MovePosition which adjusts an absolute velocity to the Rigidbody thus completely overruling the AddForce.
rb2d.MovePosition (transform.position + (movement * speed * Time.deltaTime));
this target position you want it to move towards has always the same Y as transform.position.y so you basically nail your object to that height.
However, if you think about it, all physics actions have one thing in common: In the end they are all different ways to under the hood apply a certain velocity to the rigodbody.
So instead of letting these methods calculate that velocity you could instead rather directly change the velocity yourself and thereby let AddForce fully control the Y velocity while you control only X component:
rb2d.velocity = new Vector2(movement * speed, rb2d.velocity.y);
in the game that I'm producing, the player can shoot and I'd like to make the projectile rotates continuously when the player shoot it. Each player have an empty gameobject called SpawBala which instantiates the projectile.
I'm using these lines of code to instantiate it, but the rotation is not working:
//instantiates the bullet
GameObject tiro = Instantiate(projetil, SpawBala.transform.position, SpawBala.transform.rotation);
Rigidbody BalaRigid = tiro.GetComponent<Rigidbody>();
if (SpawBala.tag == "Bala1" && gameManager.playerTurn == 1)
{
BalaRigid.AddForce(Vector3.forward * ProjetilVeloc);
BalaRigid.transform.Rotate(new Vector3(Bulletspeed * Time.deltaTime, 0, 0));
gameManager.PontoAcaop1--;
}
How could I solve it?
Your call to Rotate only happens exactly once and rotates the object about a given amount.
Anyway since there is a Rigidbody in play you shouldn't set transforms via the transform component at all because it breaks the physics.
Rather always go through the Rigidbody component.
I actually would not use AddForce and for rotation btw AddTorque when spawning a bullet. You would have to calculate the required forces depending on the bullet's weight in order to get the desired velocity(s).
Instead rather set a fix initial velocity and for the rotation angularVelocity.
Also note that currently you are always shooting in global World-Space Z direction no matter how your SpawnBala object is oriented in space. You should rather use SpawnBala.transform.forward as direction vector:
BalaRigid.velocity = SpawnBala.transform.forward * ProjetilVeloc;
// Note that your variable names are confusing
// You should probably rename it to BulletRotationSpeed e.g.
BalaRigid.angularVelocity = SpawnBala.transform.right * Bulletspeed;
I have a GameObject (camera) which is moving on the spline (using a library). I want to set its orientation towards its movement. What I mean is, the object should be looking in the direction that it is moving. I tried some things to achieve this, but I was unsuccessful. Here are my attempts:
transform.rotation = Quaternion.LookRotation(transform.position);
I have also tried this
transform.rotation = Quaternion.LookRotation(transform.forward);
Neither transform.position (a point in space) nor transform.forward (the direction an object is already facing) will necessarily give you the direction an object is moving in.
For an object with a RigidBody, you'd access this through the velocity variable - but since it sounds like you're using a proprietary spline library and have no access to the object's actual movement direction, you may need to keep track of it yourself.
The simplest solution (if the library really doesn't provide movement information), is to store the object's present position and previous position each frame, and manually calculating the delta position (aka. The distance travelled between the frames) to find the velocity vector. For example:
public class MovingObject : MonoBehaviour {
private Vector3 prevPosition;
void Start() {
// Starting off last position as current position
prevPosition = transform.position;
}
void Update() {
// Calculate position change between frames
Vector3 deltaPosition = transform.position - prevPosition;
if (deltaPosition != Vector3.zero) {
// Same effect as rotating with quaternions, but simpler to read
transform.forward = deltaPosition;
}
// Recording current position as previous position for next frame
prevPosition = transform.position;
}
}
Hope this helps! Let me know if you have any questions.
Try
transform.rotation = Quaternion.LookRotation(transform.position - currentPosition);
where currentPosition is the position on the spline where your game object is right now (before applying the transformation transform).
Keep in mind that Quaternion.LookRotation() does not expect the position to look at but the direction where to look instead. See the documentation and FAQ.
You are on the right track, but you should use your movement direction: transform.rotation = Quaternion.LookRotation(movementDirection), as transform.forward is already the objects' orientation.
If you do not know/have access to the objects' current movement direction but you know the target position, you can rotate towards the target position: transform.rotation = Quaternion.LookRotation(targetPosition - transform.position)