- Home /
Top Down 2D Car Physics
What I want to do is to make a top down game implementing the Unity3d 2d system. When I say top down I mean from the roof of the car. I want to be able to steer the car realistically like what the wheel collides do in car demo.
Before anyone says it: I have spent a great deal of time searching already.
I'm fairly sure you asked this question before and it got closed. (http://answers.unity3d.com/questions/685731/top-down-2d-car-physics.html), and you deleted it when there were useful comments given ....
the useful comment wasn't useful. And it was closed for being a duplicate question when it wasn't a duplicate.
I want to design a game please copy/paste code isn't what UA is for; if you have a specific question about how to accomplish a part of this, you should revise this question and be specific; this is a duplicate question (Google Unity car physics 2D) in general, but without any specifics it's also so vague.
Okay let me make this very clear one more time. I ALREADY SEARCHED THIS TOPIC FOR A GOOD COUPLE OF HOURS. THAT $$anonymous$$EANS GOGGLING UNITY3D CAR PHYSICS 2D. WHAT CO$$anonymous$$ES UP IS FRO$$anonymous$$ THE SID$$anonymous$$ NOT THE TOP DOWN. READ THE ORIGINAL POST.
The original post seems to have been deleted; there are many examples of car physics 2D you still haven't specified what part of this game design you have in $$anonymous$$d that you need help with; 'how do I write my entire car steering' isn't really a specific question, it's a code request at best.
Answer by ijidau · Nov 04, 2015 at 04:00 AM
I know it's far too late, but I used the hints above to create the following script, please excuse the verbose syntax. I have the public variables set to 5 (acceleration) and 3 (steering). I'm posting because someone may still find this useful:
using UnityEngine;
using System.Collections;
public class 2dCarController : MonoBehaviour {
public float acceleration;
public float steering;
private Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
}
void FixedUpdate () {
float h = -Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector2 speed = transform.up * (v * acceleration);
rb.AddForce(speed);
float direction = Vector2.Dot(rb.velocity, rb.GetRelativeVector(Vector2.up));
if(direction >= 0.0f) {
rb.rotation += h * steering * (rb.velocity.magnitude / 5.0f);
//rb.AddTorque((h * steering) * (rb.velocity.magnitude / 10.0f));
} else {
rb.rotation -= h * steering * (rb.velocity.magnitude / 5.0f);
//rb.AddTorque((-h * steering) * (rb.velocity.magnitude / 10.0f));
}
Vector2 forward = new Vector2(0.0f, 0.5f);
float steeringRightAngle;
if(rb.angularVelocity > 0) {
steeringRightAngle = -90;
} else {
steeringRightAngle = 90;
}
Vector2 rightAngleFromForward = Quaternion.AngleAxis(steeringRightAngle, Vector3.forward) * forward;
Debug.DrawLine((Vector3)rb.position, (Vector3)rb.GetRelativePoint(rightAngleFromForward), Color.green);
float driftForce = Vector2.Dot(rb.velocity, rb.GetRelativeVector(rightAngleFromForward.normalized));
Vector2 relativeForce = (rightAngleFromForward.normalized * -1.0f) * (driftForce * 10.0f);
Debug.DrawLine((Vector3)rb.position, (Vector3)rb.GetRelativePoint(relativeForce), Color.red);
rb.AddForce(rb.GetRelativeVector(relativeForce));
}
}
Obviously this is just a model of 2D topdown car physics (no tyre model). It calculates the drift and counteracts this with an opposing force, shown with the debug.draw red line. The steering is reduced to zero when stationary to prevent the car spinning on the spot. Rigidbody drag and angularDrag are both set to 1.
The most interesting calculation is the dirftForce, which I got the concept from: http://docs.unity3d.com/Manual/AmountVectorMagnitudeInAnotherDirection.html
Note that I modify RigidBody2D rotation directly, but you can try AddTorque as shown (commented out).
I'm not terribly good with maths, but I hacked away at this until I got it roughly working as intended.
I liked this version a lot, and decided to simplify the math and add some comments. Also, I added a speed limit to the car.
For anyone who's interested:
using UnityEngine;
using UnityEngine.Tilemaps;
public class CarController : $$anonymous$$onoBehaviour {
public float maxSpeed;
public float acceleration;
public float steering;
private Rigidbody2D rb;
private float currentSpeed;
private void Start()
{
this.rb = GetComponent<Rigidbody2D>();
}
private void FixedUpdate()
{
// Get input
float h = -Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
// Calculate speed from input and acceleration (transform.up is forward)
Vector2 speed = transform.up * (v * acceleration);
rb.AddForce(speed);
// Create car rotation
float direction = Vector2.Dot(rb.velocity, rb.GetRelativeVector(Vector2.up));
if (direction >= 0.0f)
{
rb.rotation += h * steering * (rb.velocity.magnitude / maxSpeed);
}
else
{
rb.rotation -= h * steering * (rb.velocity.magnitude / maxSpeed);
}
// Change velocity based on rotation
float driftForce = Vector2.Dot(rb.velocity, rb.GetRelativeVector(Vector2.left)) * 2.0f;
Vector2 relativeForce = Vector2.right * driftForce;
Debug.DrawLine(rb.position, rb.GetRelativePoint(relativeForce), Color.green);
rb.AddForce(rb.GetRelativeVector(relativeForce));
// Force max speed limit
if (rb.velocity.magnitude > maxSpeed)
{
rb.velocity = rb.velocity.normalized * maxSpeed;
}
currentSpeed = rb.velocity.magnitude;
}
}
This is the code I've been looking for! Thanks a Million!
Answer by nexis717 · Oct 22, 2015 at 08:11 AM
A bit of an old question but, thought I would pitch in, in case anyone else comes across the question, looking for an answer. Jeff and Major have pretty much worked it out but, to provide a little more fleshed out answer in C# I found that playing around with the rigidbody 2d drags helped with getting more realistic feeling car movements. You could modify or remove the noGas() method, and move it into the FixedUpdate() if you wanted. I found that this helped with braking and a more realistic stop, when not accelerating.
Add a Rigidbody 2D component to your Car object (turn the Gravity Scale to 0) and then implement a script along the lines of the following:
public float power = 3; public float maxspeed = 5; public float turnpower = 2; public float friction = 3; public Vector2 curspeed ; Rigidbody2D rigidbody2D; // Use this for initialization void Start () { rigidbody2D = GetComponent<Rigidbody2D>(); } void FixedUpdate() { curspeed = new Vector2(rigidbody2D.velocity.x, rigidbody2D.velocity.y); if (curspeed.magnitude > maxspeed) { curspeed = curspeed.normalized; curspeed *= maxspeed; } if (Input.GetKey(KeyCode.W)) { rigidbody2D.AddForce(transform.up * power); rigidbody2D.drag = friction; } if (Input.GetKey(KeyCode.S)) { rigidbody2D.AddForce(-(transform.up) * (power/2)); rigidbody2D.drag = friction; } if (Input.GetKey(KeyCode.A)) { transform.Rotate(Vector3.forward * turnpower); } if (Input.GetKey(KeyCode.D)) { transform.Rotate(Vector3.forward * -turnpower); } noGas(); } void noGas() { bool gas; if(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S)) { gas = true; } else { gas = false; } if (!gas) { rigidbody2D.drag = friction * 2; } }
Answer by Jeff-Kesselman · Apr 14, 2014 at 12:24 AM
So, you can work this out yourself if you know what a force is and what acceleration is.
(1) Start with a basic model: Track velocity in X and Y and add it times delta time into your position on update Try that and see how it behaves like an object in space.
(2) When you add velocity, add it in the "steering direction". See how it behaves like a car with no traction
(3) Add an opposing force at right angles to the steering direction and proportional to the velocity on that angle, this adds traction.
I have all of that already except I have no idea how to implement 3. I have been working on it for a while, but I just don't understand enough to work it out. :(
var power : float = 3;
var maxspeed : float = 5;
var turnpower : float = 2;
var friction : float = 10;
var curspeed : Vector2;
function Update ()
{
curspeed = Vector2(rigidbody2D.velocity.x, rigidbody2D.velocity.y);
if(curspeed.magnitude > maxspeed)
{
curspeed = curspeed.normalized;
curspeed *= maxspeed;
}
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.W))
{
rigidbody2D.AddForce(transform.up * power);
}
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.S))
{
rigidbody2D.AddForce(-(transform.up) * power);
}
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.A))
{
transform.Rotate(Vector3.forward * turnpower);
}
if(Input.Get$$anonymous$$ey($$anonymous$$eyCode.D))
{
transform.Rotate(Vector3.forward * -turnpower);
}
}
Answer by sandro_lord · Feb 25, 2019 at 05:51 PM
ok i am 5 years late but just in case somone stumbles on this. i have made a simple script which works but has no friction so you cant drift with this one, but its shorter than others.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class drive : MonoBehaviour
{
Rigidbody2D rb;
float rotation;
float x;
float y;
public float speed=1;
public float turnspeed = 1;
int temp=0;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
rotation = rb.rotation;
rb.rotation = rotation - Input.GetAxis("Horizontal")*turnspeed*Time.deltaTime*10;
rotation=Mathf.Deg2Rad* rotation;
x = Mathf.Sin(rotation) * speed * Time.deltaTime*10;
y = Mathf.Cos(rotation) * speed * Time.deltaTime*10;
rb.velocity=new Vector2(-x,y);
}
}
Your answer was helpful for me, Sandro_lord ....I am a complete newbie, I am trying to improve your code adding code so that the car can go backwards...I'll let you know! :)
Your answer
Follow this Question
Related Questions
Top Down 2D Car Physics 0 Answers
Multiple Cars not working 1 Answer
TOP down 2d car physics 0 Answers
stabilize car? help! 0 Answers