Real Physics Enabled Racing Game

Hi guys… I am working on a real racing game. Not just a simple box and wheel spheres/cylinders but a real Need For Speed style racing game. I am using low-level Ammo.js classes.

I cant seem to find any BabylonJS Racing Projects Or Demo (Especially no mechanics source to use as a guide). So I am just making shit up as i go along… As Usual :slight_smile:

Taking what VERY LIMTED bullet examples and trying to workout what unity is doing.

This lead to the creating of my Babylon Toolkit Pro Physics SDK which has built in support for Native Bullet Raycast Vehicles. Everything is working pretty good so far. But i have SO MANY questions i need to ask a developer who has made a real physics based racing game. Things like:

  • Is there a common practice for dampening high speed steering
  • How are you handing skid marks (Using Shaders or dynamically generating planes from the 4 contacts points the wheel is contacting the ground)
  • Gear shifting… Is that a real thing or is just for the engine sounds and speedometers

And the HOLY GRAIL for racing physics racing game… SIDEWAYS FRICTION

How the HECK do i actually create a subclass for Bullet Typed Constraint (Ammo.btTypeConstraint)

Basically… Create a bullet WheelFrictionConstraint to handle sideways friction (as well as proper hand braking and drifting… WHICH YOU NEED TO SUPPORT SIDEWAYS FRICTION TO ACHEIVE)

Plus more…

The closest thing to a actual racing game (or demo scene rather) is this:

It looks like he might be using Cannon.js and maybe the cannon raycast vehicle… Dunno
Whoever made that demo… Hit me up… I would luv to talk to you about racing car game development.

If there is anybody else:




Anybody who can advise me on a real racing game… And for me, the most important thing is creating a re-usable Vehicle Physics SDK that can be used from the Babylon Toolkit the SAME WAY Unity does for its Vehicle System (That really wraps the PhysX Vehicle SDK)

As aways… Thanks :slight_smile:

UPDATE: Check my Babylon Toolkit: Pro Physics SDK Preview

1 Like

Or… particles. :slight_smile:

Hi M! Thx for your enthusiasm/zeal, regarding this.

Note: I can’t get that demo to go forward or turn left. W and A keys seem dead. Firefox ESR-branch.

Ammo-only, right? Suspension design is VERY important. I’m a jumper/mudder/swamper, and less a drifter… so I prefer long-travel suspensions… you know… rock crawlers, which often have high CG’s. (center of gravity). Drifters likely want low CG’s… and might want to use ground-effect drafts, which Ammo won’t address. CG’s and suspension-design… big factors. Tires, too, and road surfaces (Ammo physics-materials?)

Turn-on all these cool things, gravel spewing, material physics, skid marks, and you have a webGL game that can have ZERO fast-scenery sailing-past, because of perf-bog. :slight_smile: To get it up to speed, you must find a faster system than JS/webGL… and at the end of the strife, you’ll have re-coded… which I believe is the next-gen of an older sim called… umm… “rigs of rods” or something like that. (“Rods” is a technique used to assist in vehicle physics sims, I hear.)

BeamNG does drifting nicely… actually wonderfully, but ya best have a steering wheel controller and some serious practicing with ONE type of car. Just like real life, that car’s CG/characteristics needs to become an extension of the driver’s body… and driver confidence needs to be high (via practice in ONE car).

But really, the question might be… who will bother drift-simming on a JS/webGL racer… which can afford only the most primitive of scenery complexity/speeds… running a JS-based physics engine? Is it worth “the grind”… to take-on something SO speed/perf-critical… with webGL? Are you setting yourself-up for disappointment/failure?

Then there’s MotorM4x and it’s frozen lake racing… drift-fest fun. AND, of course, GTA 5, which has the most amazing vehicle physics and great-detail high-speed passing-scenery… EVER (I suspect) (and great jumping, too). and MotorM4x are probably quite affordable packages, these days. It could kill any webGL-drifter/jumper popularity. But, on the other hand… if you’re chasing this challenge as… just that… a webGL challenge to test the current capabilities… it’s certainly worthy of 2-3 hours of free time. hehe. Ok, ok, maybe a week. :slight_smile:

Sorry if I am raining on parades, but when it comes to high-speed physics and passing-scenery… I think it will be rough… for webGL to top “the establishment”. Just my opinion. Stay tuned, others will surely have other views.

Thanks @Wingnut … I think i should clarify… I mean arcade style racing game so the drifting part is not really a TOTAL drifting game … but rather when taking a high speed turn i have a function that i am working on the when you are holding the DRIFT trigger button in a turn, i give a bit of Y-Rotational boost (setAngularVelocity based of the current wheel steer direction) to kinda of swing the back of the car a bit more in the turn… I also easy up a bit on the wheelInfo.m_frictionSlip…

AGAIN… I am just making all this shit up. to create a Car Controller Script

My problem with hand braking and drifting is that when i left go of drift or hand brake… it immediate goes back to using the set rolling friction (and has no support for handling SIDEWAYS FRICTION out of the box) when will CATCH and flip or roll the car cause the tire is catching the friction at such a high speed. You have to implement a Typed Constraint (btTypeConstraint) and set the min and max friction slip for both forward and sideways friction and let the bullet physics engine proper solve and LERP to the proper friction level for that wheel… Instead of always just using a constant m_frictionSlip value.

The car controller script is quite nice, if i must say so my self:

Example Car driving script using my Physics SDK… As you see …
You use it just like would a Unity Car Controller script:

 * Babylon standard rigidbody vehicle controller class (Native Bullet Physics 2.82)
 * @class StandardCarController
class StandardCarController extends BABYLON.ScriptComponent {
    private _rigidbody:BABYLON.RigidbodyPhysics = null;
    private FRONT_LEFT = -1;
    private FRONT_RIGHT = -1;
    private BACK_LEFT = -1;
    private BACK_RIGHT = -1;
    private frictionSlip:number = 0;
    private vehicleSteer:number = 0;
    private engineForce:number = 0;
    private brakingForce:number = 0;
    private forwardSpeed:number = 0;
    private absoluteSpeed:number = 0;
    private raycastVehicle:BABYLON.RaycastVehicle = null;
    private frontLeftWheelMesh:BABYLON.TransformNode = null;
    private frontRightWheelMesh:BABYLON.TransformNode = null;
    private backLeftWheelMesh:BABYLON.TransformNode = null;
    private backRightWheelMesh:BABYLON.TransformNode = null;
    private frontLeftWheelTrans:BABYLON.IUnityTransform = null;
    private frontRightWheelTrans:BABYLON.IUnityTransform = null;
    private backLeftWheelTrans:BABYLON.IUnityTransform = null;
    private backRightWheelTrans:BABYLON.IUnityTransform = null;
    private frontLeftWheelCollider:any = null;
    private frontRightWheelCollider:any = null;
    private backLeftWheelCollider:any = null;
    private backRightWheelCollider:any = null;
    private STEERING_RADIUS_RATIO: number = 0.1;

    public getRaycastVehicle():BABYLON.RaycastVehicle { return this.raycastVehicle; }
    public staticFriction:number = 25;
    public rollingFriction:number = 5;
    public dampeningSpeed:number = 25;
    public lowSpeedAngle:number = 0.3;
    public highSpeedAngle:number = 0.01;
    public maxEngineSpeed:number = 120;
    public maxEnginePower:number = 2000;
    public maxBrakingForce:number = 100;
    public maxReverseSpeed:number = 0.66;
    public handBrakingForce:number = 5000;
    public frontLockFriction:number = 1;
    public backLockFriction:number = 1;
    public frontDriftFriction:number = 1;
    public backDriftFriction:number = 1;
    public driftingInfluence:number = 1;
    public steeringIncrement:number = 0.03;

    protected m_frontLeftWheel:any = null;
    protected m_frontRightWheel:any = null;
    protected m_backLeftWheel:any = null;
    protected m_backRightWheel:any = null;
    protected m_physicsWorld:any = null;
    public constructor(transform: BABYLON.TransformNode, scene: BABYLON.Scene, properties: any = {}) {
        super(transform, scene, properties);
        this.vehicleSteer = 0;
        this.brakingForce = 0;
        this.engineForce = 0;
        this.lowSpeedAngle = this.getEditorProperty("lowSpeedAngle", this.lowSpeedAngle);
        this.highSpeedAngle = this.getEditorProperty("highSpeedRatio", this.highSpeedAngle);
        this.dampeningSpeed = this.getEditorProperty("dampeningSpeed", this.dampeningSpeed);
        this.maxEngineSpeed = this.getEditorProperty("maxEngineSpeed", this.maxEngineSpeed);
        this.maxEnginePower = this.getEditorProperty("maxEnginePower", this.maxEnginePower);
        this.maxBrakingForce = this.getEditorProperty("maxBrakingForce", this.maxBrakingForce);
        this.handBrakingForce = this.getEditorProperty("handBrakingForce", this.handBrakingForce);
        this.frontLockFriction = this.getEditorProperty("frontLockFriction", this.frontLockFriction);
        this.backLockFriction = this.getEditorProperty("backLockFriction", this.backLockFriction);
        this.frontDriftFriction = this.getEditorProperty("frontDriftFriction", this.frontDriftFriction);
        this.backDriftFriction = this.getEditorProperty("backDriftFriction", this.backDriftFriction);
        this.driftingInfluence = this.getEditorProperty("driftingInfluence", this.driftingInfluence);
        this.steeringIncrement = this.getEditorProperty("steeringIncrement", this.steeringIncrement);
        this.frontLeftWheelTrans = this.getEditorProperty("frontLeftWheelMesh", this.frontLeftWheelTrans);
        this.frontRightWheelTrans = this.getEditorProperty("frontRightWheelMesh", this.frontRightWheelTrans);
        this.backLeftWheelTrans = this.getEditorProperty("rearLeftWheelMesh", this.backLeftWheelTrans);
        this.backRightWheelTrans = this.getEditorProperty("rearRightWheelMesh", this.backRightWheelTrans);
        this.frontLeftWheelCollider = this.getEditorProperty("frontLeftWheelCollider", this.frontLeftWheelCollider);
        this.frontRightWheelCollider = this.getEditorProperty("frontRightWheelCollider", this.frontRightWheelCollider);
        this.backLeftWheelCollider = this.getEditorProperty("rearLeftWheelCollider", this.backLeftWheelCollider);
        this.backRightWheelCollider = this.getEditorProperty("rearRightWheelCollider", this.backRightWheelCollider);
        this.m_physicsWorld = BABYLON.SceneManager.GetPhysicsWorld(this.scene);
        // TODO: Handle With Wheel Friction Constraint
        this.staticFriction = this.getEditorProperty("staticFrictionSlip", this.staticFriction);
        this.rollingFriction = this.getEditorProperty("rollingFrictionSlip", this.rollingFriction);

    protected start():void { this.initVehicleState(); }
    protected update() :void {  this.updateVehicleState(); }
    protected destroy(): void { this.destroyVehicleState(); }

    // Protected Character Movement State Functions //
    protected initVehicleState(): void {
        this._rigidbody = this.getComponent("BABYLON.RigidbodyPhysics");
        if (this._rigidbody != null) {
            if (this._rigidbody.hasRaycastVehicle()) {
                this.raycastVehicle = this._rigidbody.getRaycastVehicle();
                if (this.raycastVehicle != null) {
                    const frontLeftWheelName:string = ( != null && !== "") ? : null;
                    const frontRightWheelName:string = ( != null && !== "") ? : null;
                    const backLeftWheelName:string = ( != null && !== "") ? : null;
                    const backRightWheelName:string = ( != null && !== "") ? : null;
                    const frontLeftWheelLabel:string = ( != null && !== "") ? : null;
                    const frontRightWheelLabel:string = ( != null && !== "") ? : null;
                    const backLeftWheelLabel:string = ( != null && !== "") ? : null;
                    const backRightWheelLabel:string = ( != null && !== "") ? : null;

                    if (frontLeftWheelLabel != null) this.FRONT_LEFT = this.raycastVehicle.getWheelIndexByName(frontLeftWheelLabel);
                    if (frontRightWheelLabel != null) this.FRONT_RIGHT = this.raycastVehicle.getWheelIndexByName(frontRightWheelLabel);
                    if (backLeftWheelLabel != null) this.BACK_LEFT = this.raycastVehicle.getWheelIndexByName(backLeftWheelLabel);
                    if (backRightWheelLabel != null) this.BACK_RIGHT = this.raycastVehicle.getWheelIndexByName(backRightWheelLabel);

                    if (this.raycastVehicle.getNumWheels() >= 4) {
                        if (this.FRONT_LEFT >= 0 && frontLeftWheelName != null) {
                            this.m_frontLeftWheel = this.raycastVehicle.getWheelInfo(this.FRONT_LEFT);
                            this.frontLeftWheelMesh = this.getChildTransform(frontLeftWheelName, BABYLON.SearchType.StartsWith, false);
                            if (this.frontLeftWheelMesh != null) this.raycastVehicle.setWheelTransformMesh(this.FRONT_LEFT, this.frontLeftWheelMesh);
                        if (this.FRONT_RIGHT >= 0 && frontRightWheelName != null) {
                            this.m_frontRightWheel = this.raycastVehicle.getWheelInfo(this.FRONT_RIGHT);
                            this.frontRightWheelMesh = this.getChildTransform(frontRightWheelName, BABYLON.SearchType.StartsWith, false);
                            if (this.frontRightWheelMesh != null) this.raycastVehicle.setWheelTransformMesh(this.FRONT_RIGHT, this.frontRightWheelMesh);
                        if (this.BACK_LEFT >= 0 && backLeftWheelName != null) {
                            this.m_backLeftWheel = this.raycastVehicle.getWheelInfo(this.BACK_LEFT);
                            this.backLeftWheelMesh = this.getChildTransform(backLeftWheelName, BABYLON.SearchType.StartsWith, false);
                            if (this.backLeftWheelMesh != null) this.raycastVehicle.setWheelTransformMesh(this.BACK_LEFT, this.backLeftWheelMesh);
                        if (this.BACK_RIGHT >= 0 && backRightWheelName != null) {
                            this.m_backRightWheel = this.raycastVehicle.getWheelInfo(this.BACK_RIGHT);
                            this.backRightWheelMesh = this.getChildTransform(backRightWheelName, BABYLON.SearchType.StartsWith, false);
                            if (this.backRightWheelMesh != null) this.raycastVehicle.setWheelTransformMesh(this.BACK_RIGHT, this.backRightWheelMesh);
                    } else {
                        BABYLON.Tools.Warn("Invalid vehicle controller wheel count info for: " +;
                } else {
                    BABYLON.Tools.Warn("Failed to create vehicle controller for: " +;
            } else {
                BABYLON.Tools.Warn("No wheel collider information found for: " +;
        } else {
            BABYLON.Tools.Warn("Failed to get rigidbody component: " +;
    protected updateVehicleState(): void {
        if (this._rigidbody != null && this.raycastVehicle != null) {
            this.forwardSpeed = this.raycastVehicle.getRawCurrentSpeedMph();
            this.absoluteSpeed = this.raycastVehicle.getAbsCurrentSpeedMph();
    protected destroyVehicleState(): void {
        this._rigidbody = null;
        this.m_physicsWorld = null;
        if (this.m_frontLeftWheel != null) {
            Ammo.destroy(this.m_frontLeftWheel); // ???
            this.m_frontLeftWheel = null;
        if (this.m_frontRightWheel != null) {
            Ammo.destroy(this.m_frontRightWheel); // ???
            this.m_frontRightWheel = null;
        if (this.m_backLeftWheel != null) {
            Ammo.destroy(this.m_backLeftWheel); // ???
            this.m_backLeftWheel = null;
        if (this.m_backRightWheel != null) {
            Ammo.destroy(this.m_backRightWheel); // ???
            this.m_backRightWheel = null;
        this.raycastVehicle = null;
        this.frontLeftWheelMesh = null;
        this.frontRightWheelMesh = null;
        this.backLeftWheelMesh = null;
        this.backRightWheelMesh = null;
        this.frontLeftWheelTrans = null;
        this.frontRightWheelTrans = null;
        this.backLeftWheelTrans = null;
        this.backRightWheelTrans = null;
        this.frontLeftWheelCollider = null;
        this.frontRightWheelCollider = null;
        this.backLeftWheelCollider = null;
        this.backRightWheelCollider = null;

    // Public Vehicle Controller Movement Functions   //

    /** Drives the raycast vehicle with the specfied movement and hand braking properties. */
    public drive(forward:number, turn:number, braking:boolean = false, drifting:boolean = false):void {
        if (this._rigidbody == null || this.raycastVehicle == null) return;
        if (this.FRONT_LEFT >= 0 && this.FRONT_RIGHT >= 0 && this.BACK_LEFT >= 0 && this.BACK_RIGHT >= 0) {
            this.frictionSlip = this.rollingFriction;
            this.brakingForce = 0; this.engineForce = 0;
            // ..
            // Update Turning Angle
            // ..
            let allowedTurningAngle:number = this.lowSpeedAngle;
            if (this.dampeningSpeed > 0 && this.absoluteSpeed > this.dampeningSpeed) {
                const turnSpeedGradient:number = BABYLON.Scalar.Clamp(0, 1, (this.absoluteSpeed / this.maxEngineSpeed));
                allowedTurningAngle = BABYLON.Scalar.Lerp(this.lowSpeedAngle, this.highSpeedAngle, turnSpeedGradient);
            if (turn > 0) { // Left
                if (this.vehicleSteer < allowedTurningAngle) {
                    this.vehicleSteer += (this.steeringIncrement);
            } else if (turn < 0) { // Right
                if (this.vehicleSteer > -allowedTurningAngle) {
                    this.vehicleSteer -= (this.steeringIncrement);
            } else {
                if (this.vehicleSteer < -this.steeringIncrement) {
                    this.vehicleSteer += this.steeringIncrement;
                } else {
                    if (this.vehicleSteer > this.steeringIncrement) {
                        this.vehicleSteer -= this.steeringIncrement;
                    } else {
                        this.vehicleSteer = 0;
            // ..
            // Update Engine Forces
            // ..
            let allowedEnginePower:number = (this.maxEnginePower * Math.abs(forward));
            if (forward > 0.1) { // Forward
                if (this.forwardSpeed < -1) this.brakingForce = this.maxBrakingForce;
                else this.engineForce = allowedEnginePower;
            } else if (forward < -0.1) { // Reverse
                if (this.forwardSpeed > 1) this.brakingForce = this.maxBrakingForce;
                else this.engineForce = -(allowedEnginePower * this.maxReverseSpeed);
            } else {
                this.engineForce = 0;
                this.brakingForce = 10; // Static
                this.frictionSlip = this.staticFriction;
            if (this.absoluteSpeed > this.maxEngineSpeed) this.engineForce = 0;
            // ..
            // Update Vehicle Controls
            // ..
            if (braking === true && this.handBrakingForce > 0) {
                // TODO: Fix Hand Brake Friction Zero Velocity (Use Wheel Friction Constraint)
                if (this.raycastVehicle.lockedWheelIndexes == null) this.raycastVehicle.lockedWheelIndexes = [this.BACK_LEFT, this.BACK_RIGHT];
                if (this.m_frontLeftWheel != null) this.m_frontLeftWheel.set_m_frictionSlip(this.frontLockFriction);
                if (this.m_frontRightWheel != null) this.m_frontRightWheel.set_m_frictionSlip(this.frontLockFriction);
                if (this.m_backLeftWheel != null) this.m_backLeftWheel.set_m_frictionSlip(this.backLockFriction);
                if (this.m_backRightWheel != null) this.m_backRightWheel.set_m_frictionSlip(this.backLockFriction);

                this.raycastVehicle.setSteeringAngle(this.vehicleSteer, this.FRONT_LEFT);
                this.raycastVehicle.setSteeringAngle(this.vehicleSteer, this.FRONT_RIGHT);

                this.raycastVehicle.setEngineForce(0, this.BACK_LEFT);
                this.raycastVehicle.setEngineForce(0, this.BACK_RIGHT);

                this.raycastVehicle.setBrakingForce(0, this.FRONT_LEFT);
                this.raycastVehicle.setBrakingForce(0, this.FRONT_RIGHT);
                this.raycastVehicle.setBrakingForce(this.handBrakingForce, this.BACK_LEFT);
                this.raycastVehicle.setBrakingForce(this.handBrakingForce, this.BACK_RIGHT);
            } else {
                if (this.raycastVehicle.lockedWheelIndexes != null) this.raycastVehicle.lockedWheelIndexes = null;
                if (this.m_frontLeftWheel != null) this.m_frontLeftWheel.set_m_frictionSlip(this.frictionSlip);
                if (this.m_frontRightWheel != null) this.m_frontRightWheel.set_m_frictionSlip(this.frictionSlip);
                if (this.m_backLeftWheel != null) this.m_backLeftWheel.set_m_frictionSlip(this.frictionSlip);
                if (this.m_backRightWheel != null) this.m_backRightWheel.set_m_frictionSlip(this.frictionSlip);
                if (drifting === true && this.absoluteSpeed > 0) {
                    // TODO: Drifting Support
                    // const wheelRotation:number = turn;
                    // const angularVelocity:BABYLON.Vector3 = this._rigidbody.getAngularVelocity();
                    // angularVelocity.y += (wheelRotation * this.absoluteSpeed * this.getDeltaSeconds() * this.STEERING_RADIUS_RATIO * this.driftingInfluence);
                    // this._rigidbody.setAngularVelocity(angularVelocity);

                this.raycastVehicle.setSteeringAngle(this.vehicleSteer, this.FRONT_LEFT);
                this.raycastVehicle.setSteeringAngle(this.vehicleSteer, this.FRONT_RIGHT);

                this.raycastVehicle.setEngineForce(this.engineForce, this.BACK_LEFT);
                this.raycastVehicle.setEngineForce(this.engineForce, this.BACK_RIGHT);

                this.raycastVehicle.setBrakingForce(this.brakingForce * 0.5, this.FRONT_LEFT);
                this.raycastVehicle.setBrakingForce(this.brakingForce * 0.5, this.FRONT_RIGHT);
                this.raycastVehicle.setBrakingForce(this.brakingForce, this.BACK_LEFT);
                this.raycastVehicle.setBrakingForce(this.brakingForce, this.BACK_RIGHT);
            // Trace Current Speed
            const msg:string = ("Speed: " + this.absoluteSpeed.toFixed(1) + " MPH --> Turn Angle: " + allowedTurningAngle.toFixed(5));
            BABYLON.Utilities.PrintToScreen(msg, "#008000");

nod, thx for clarification. Sorry for the overkill comments, then. :slight_smile:

You should/could… consider faking all the physics. But I realize that you have been working with AmmoJS, lately, so, I don’t think a non-physics-engine drifter/jumper… is within your current objectives. I can understand that.

Do you know if there are any other webGL/AmmoJS drifters/racers… in existence? What’s that rayCastVehicle thing? Seen one in action? (sorry if I’m domineering the thread)

I have it working… Ill make a little video…

I need to talk to someone who has made a real physics car game about some of the mechanics…

For example… I am just making shit up about:

  • Motion
  • Turning
  • Skidding
  • Drifting (Faked)
  • Handbraking


To RE-CREATE what the Unity Wheel Colliders do for Unity Developers… And that is basically Expose the PhysX Vehicle SDK via the setting on the Wheel collider… I do the same thing except i use Bullet instead of PhysX… Remeber the goal for me (The Babylon Toolkit) is to make the TOOLING and SDK to get that Unity Like Experience when developing a babylon JS game…

I wanna talk to some folks so see… Hey… is that right or … Well the industry normally does it this way…
or something … Anything from anybody… I just wanna talk to another developer about racing games and how they do things

NOT USING PHYSICS kinda of defeats the whole point of creating a Racing Game (Unity Style… Editor, Scripts, Model Setup… etc) but for our Babylon JS games :slight_smile:

Ill show you what i got so far… ill make a quick video or something :slight_smile:

I’ve been trying to make a physics based racing game myself with ammo.js. I’ve had a similar problem with trying to drift the car causing the car to just roll over instead of sliding. See here for an example

This is my first attempt at this sort of thing and I have the same questions, so I’d be super curious to know what you find out.

Kool… I will take a look at your demo.

I am not only creating a racing game. But more creating the vehicle sdk and the track tooling used to make any kind racing game from car racing to mario kart style racing.

And most important… How i architected the game project using the Babylon Toolkit.

I made a video here:

But for some reason my screen recorder software is making a blurry video. It looks sweet on my screen as i am recording it but the final video is choppy and blurry. I am using the GoToMeeting screen recording software for Mac.

Side note: Does anybody know of a good screen recording software for Mac. Something i can use to make training videos and demo ???

@Wingnut … Check out the video… kinda choppy and blurry, but you can get the gist :slight_smile:

1 Like

@Deltakosh and @samuelgirardin and @trevordev … What can you throw in about making racing games…

Do any of you know about the how use the btTypeConstraint to handle proper friction slip using a Bullet Raycast Vehicle ???

Actually @bghgary, @trevordev, @PirateJC, @PatrickRyan, @Drigax, @syntheticmagus and @PolygonalSun worked on a pet project really closed to that:


Wow. I just crashed my browser before saving a project of mine ported to the PG. Only took a couple of hours :stuck_out_tongue:

Edit: Did a quick C/P of a smaller project:

I’m using the contact points of the front wheels to update a ribbon. This makes for some pretty decent tire tracks.

Have you tried tuning your rolling influence as well as your center of mass?


:smiley: i can imagine a rocket league with this one!

HUGE! I just limited the follow camera to not go underground:

This is really amazing! Good job!!

Very Nice @Deltakosh … I do alot of the same things with ammo native api.

Qusetion about the ribbons… I can put Tire Skid mark textures on the ribbon right ???

Also… How many seperate ribbons can you leave laying around on the ground… for example a race track… I see the ribbons disappears after a few seconds in demo. But i would like to emulate skidding and leave tire tracks on the ground for that skid… A new skid should make sepearte ribbon with tire texture and leave that on ground… Maybe start taking off after a long while or when the buffer of allowed skid marks has been reached.

Do you think i can handle that of of skid mark system using the ribbons ???

Yo @Deltakosh … can you do skidding or sliding… are you messing with the friction during the slide… I am having trouble implementing good sliding or skidding I to a turn… Can you help ???

@MackeyK24 would this work Use TrailMesh - Babylon.js Documentation ???

That looks very interesting… If i can create this trail mesh for each wheel as soon as the wheel skidding threshold is reached and then STOP trailing the wheel when skidding drops below threshold but LEAVE the trail mesh on the ground… (Until a timer makes them disappear or the track manager remove the skid mark because we reach max skid marks on track…)

Can the TrailMesh do that… (Please say yes)… I will take a look at the API as soon as i can. but those are my requirements for a skidmark :slight_smile:

EDIT: I dont know… i dont think that will work as is… I need to to create skid marks on the ground like in a need for speed style racing game. So its gotta create meshes on the ground (Some kind of dynamic mesh generation or something… If i can crate those ribbons with a SKIDMARK texture and leave on the ground when i i come out of that skid… that might work)

yup, that was just in case it would be of any help.

Thanks bro

Wow nice!
My local version uses a slightly altered version of BJS, so I can have like 10 different textures and a shit ton of effects using only one texture. I see that I’m using the wrong convex hull in the PG, so the impact sparks are… well… off :stuck_out_tongue:

Here’s a version with a dirt map:
(Give it a couple of minutes for the dirt to start, although it looks more… rusty)