- Home /
Relative Movement & Momentum problem - Space sim
Hi,
We've been working on trying to move a spaceship in zero G. Using the engine we want to boost forward then rotate so that it flies backwards.
I can do that with this code below but it will always move it on the Z axis which is not the desirable result.
transform.position += Vector3.forward * velocity * mass * Time.deltaTime;
We can get the ship to realistically move forward relative to the way it is facing using this script but with this we cannot then boost forward and rotate so that it flies backwards. As it naturally carries its forward momentum relative to the way it is facing.
transform.position += transform.forward * velocity * mass * Time.deltaTime;
All velocity is this. When the controls are held down its incremented.
velocity = currentVelocity += engineForce;
Is there a way to achieve what we are trying to achieve. Do I need to be using something like Transform.TransformDirection because I have never used that.
Any help or suggestions would be greatly appreciated.
Thanks in advance
![alt text][2]
EDIT: The code is there, I feel like I need to be doing something else to it. Like copying the players facing rotation, applying the force and momentum to that copy so it wasn't constantly updating the velocity in the direction the player is facing. If that makes sense. [2]: /storage/temp/82846-transformforward.jpg
Answer by ElijahShadbolt · Nov 25, 2016 at 09:50 PM
The built-in Rigidbody component is superior to custom scripts in almost every way when it comes to simulating physics in Unity. I would add a Rigidbody to the ship GameObject and use AddForce() to move the ship around. You just need to uncheck 'Use Gravity' in the Rigidbody's inspector, to simulate Zero G.
Engine.cs
using UnityEngine;
public class Engine : MonoBehaviour
{
public float engineForce;
void Update()
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(transform.forward * engineForce);
}
}
BUT, if you have a good reason not to use a Rigidbody, you could make your own sort of rigidbody script to handle velocity, like you were doing in your question.
CustomRigidbody,cs
using UnityEngine;
public class CustomRigidbody : MonoBehaviour
{
public float mass;
public float engineForce;
private Vector3 velocity;
void Update()
{
// F = m*a = m*dv/dt therefore dv = F*dt/m
Vector3 deltaVelocity = transform.forward * (engineForce * Time.deltaTime / mass);
velocity += deltaVelocity;
// v = ds/dt therefore ds = v*dt
Vector3 deltaDisplacement = velocity * Time.deltaTime;
transform.position += deltaDisplacement;
}
}
Thanks for the response @Sublimegamer. I'm really excited to try out;
// F = m*a = m*dv/dt therefore dv = F*dt/m
Vector3 deltaVelocity = transform.forward * (engineForce * Time.deltaTime / mass);
velocity += deltaVelocity;
// v = ds/dt therefore ds = v*dt
Vector3 deltaDisplacement = velocity * Time.deltaTime;
transform.position += deltaDisplacement;
but it errors because velocity is a float and deltavelocity is a vector?
EDIT: Ignore that. I got round it by this but Im still restricted to movement on the Z. So I have that drift where I can turn around but I couldn't then rotate to face 'upwards' and add speed in that direction. If that makes sense.
Vector3 newVelocity = new Vector3(0, 0, velocity);
newVelocity += deltaVelocity;
EDIT: thinking about it I probably did that.
Ok we've had time to try it out properly. We have recoded so we are actually calculating velocity correctly and then tried the code you supplied us with but it hasn't achieved the desired result. The ship is still carrying its' momentum in the direction its facing rather than when we rotate carrying on and "gliding" backward. If that makes sense @SublimeGamer
Are you sure you copied all of my code? In my CustomRigidbody class, I specified velocity
as a Vector3, not a float. This represents the GameObject's velocity in 3 spatial dimensions, at this specific moment in time. I then added a different Vector3 to it, deltaVelocity (in the forward direction of the object). This means the world-space velocity is changed, not just the forwards velocity like your float is doing.
If you take my CustomRigidbody.cs class, exactly like it is in my answer, it works perfectly fine. $$anonymous$$aybe you did something wrong in how you combined it with your old script?
Thanks a lot @SublimeGamer! We worked on it for a couple of hours and it started to make sense and finally worked. We weren't calculating velocity properly, as soon as we did it worked.
Hey guys hoping this isn't a dead thread...
I have the F =m*a equation in my script but now I want to use it to slow and bring my ship to a complete stop when I'm pulling back on the right thumbstick. I don't want the ship to go in reverse...at least not at this time.
// F = m*a = m*dv/dt therefore dv = F*dt/m
Vector3 deltaVelocity = transform.forward * forwardInput * (moveSettings.engineForce * Time.deltaTime / physSettings.mass);
velocity += deltaVelocity;
// v = ds/dt therefore ds = v*dt
Vector3 deltaDisplacement = velocity * Time.deltaTime;
transform.position += deltaDisplacement;
}
Negative your engine force? Stop subtracting the force when the ship stops.
Here is something that should head you in the right direction. It works for keyboard control. For use with the 'right thumbstick' you may need a separate script like the one here. If you get into trouble with input, I would make a new question and post about it there.
This implementation adds force in forwards and backwards directions based on the default input axis "Vertical" (up/down or w/s). The ship continues accelerating backwards even if it reaches zero (just like in real outer space).
void Update()
{
float force = engineForce * Input.GetAxis("Vertical");
// F = m*a = m*dv/dt therefore dv = F*dt/m
Vector3 deltaVelocity = transform.forward * (force * Time.deltaTime / mass);
velocity += deltaVelocity;
if (velocity.sqr$$anonymous$$agnitude > 0.001f) // if velocity is not zero
{
// v = ds/dt therefore ds = v*dt
Vector3 deltaDisplacement = velocity * Time.deltaTime;
transform.position += deltaDisplacement;
}
}
This next implementation does not continue accelerating backwards if it reaches zero.
float force = engineForce * Input.GetAxis("Vertical");
// if force is forwards or velocity is forwards, add dv
if (force > 0 || Vector3.Angle(velocity, transform.forward) < 90f)
{
// F = m*a = m*dv/dt therefore dv = F*dt/m
Vector3 deltaVelocity = transform.forward * (force * Time.deltaTime / mass);
velocity += deltaVelocity;
}
if (velocity.sqr$$anonymous$$agnitude > 0.001f) // if velocity is not zero
{
// v = ds/dt therefore ds = v*dt
Vector3 deltaDisplacement = velocity * Time.deltaTime;
transform.position += deltaDisplacement;
}
would that be written in there as an if statment....im having trouble figureing how to write it out...correct me if im wrong though.
In my input section I turned engine force on and off and that would used to calculate the force. The switch would be, if ship is moving forward then pressing backwards/brake would switch engine force to negative 1 ins$$anonymous$$d of 1. The way Ive got it set up is how I would do it.
Your answer
Follow this Question
Related Questions
Adding speed relative to move vector (Rigidbody2D) 1 Answer
Continuing the momentum of the rigidbody 0 Answers
Relative Velocity for Spaceship Braking 1 Answer
Velocity powered rigidbody on a moving platform without parenting. 3 Answers
Is it possible to increase stopping distance with forcemode.velocitychange? 0 Answers