Input controller to steer & re steer the vehicle in two lanes

Please help me code the same input controller as the following game.

When we hold our touch then the vehicle should steer in the left lane and vice versa on releasing our touch as the vehicle continues to move forward with a uniform speed.

Project Link - PlayCanvas | HTML5 Game Engine
I am using play canvas physics vehicle and have the following code.

var VehicleControls = pc.createScript('vehicleControls');

VehicleControls.attributes.add('targetVehicle', {
    type: 'entity',
    title: 'Target Vehicle'
});

VehicleControls.prototype.initialize = function () {
    
    this.upButtonPressed = false;
    this.leftButtonPressed = false;
    this.rightButtonPressed = false;
    
    this.reSteer = false;
    this.leftLane = false;

    this.touching = false;

    this.setEventsOnOff('on');
    this.on('destroy', () => {
    this.setEventsOnOff('off');
    });
};

VehicleControls.prototype.setEventsOnOff = function (onOff) {

    const touch = this.app.touch;
    if (touch) 
    {
        this.app.touch[onOff](pc.EVENT_TOUCHSTART, this.onTouchStart, this);
        this.app.touch[onOff](pc.EVENT_TOUCHEND, this.onTouchEndCancel, this);
        this.app.touch[onOff](pc.EVENT_TOUCHCANCEL, this.onTouchEndCancel, this);
        this.app.touch[onOff](pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
    }
};

VehicleControls.prototype.onTouchStart = function(event) {

    const touches = event.touches;
    this.touching = touches.length === 1;

    if (this.touching) {
        this.leftLane = true; // Start in the left lane
    }

    event.event.preventDefault();
};

VehicleControls.prototype.onTouchEndCancel = function(event) {

    const touches = event.touches;
    this.touching = touches.length === 1;

    this.leftLane = !this.leftLane; // Switch to the right lane

    event.event.preventDefault();
};

VehicleControls.prototype.onTouchMove = function(event) {

    const touches = event.touches;
    event.event.preventDefault();
};

VehicleControls.prototype.update = function (dt) {
    var targetVehicle = this.targetVehicle ? this.targetVehicle : this.entity;

    if (targetVehicle) 
    {
        var steering = 0;
        var throttle = 0;

        this.upButtonPressed = true;

        if (this.touching && this.isTouchingGround()) {

        } 
        else if (!this.touching && this.isTouchingGround()) {
        }

        if (this.leftButtonPressed) steering++;
        if (this.rightButtonPressed) steering--;
        if (this.upButtonPressed) throttle++;

        // --- if the vehicle isn't turning, steer to get it back on track
        if (this.reSteer && this.isTouchingGround()) 
        {
            const forward = targetVehicle.forward;
            const dot = forward.dot(pc.Vec3.FORWARD);

            if (dot < 0.999) 
            {
                const isLeft = forward.x < 0;
                steering += isLeft ? -1 : 1;
            }
        }

        targetVehicle.script.vehicle.fire('vehicle:controls', steering, throttle);
    }
};

VehicleControls.prototype.isTouchingGround = function () {
    var targetVehicle = this.targetVehicle ? this.targetVehicle : this.entity;

    // Define the ground height threshold (adjust as needed)
    var groundThreshold = 0.5;

    // Get the position of the car's wheels or collider
    var position = targetVehicle.getPosition(); // Adjust with the appropriate position retrieval method

    // Compare the car's height with the ground threshold
    return position.y <= groundThreshold;
};

Hi @yash_mehrotra!

What is your current problem?

@Albertos

I have the re steering logic in the update function, but I could not put it together to get the desired movement. The vehicle should keep on moving in forward direction. Whenever I hold my touch, the vehicle should steer left to change the lane and then re steer back to face forward in the direction of motion. Same for the right lane when the touch is released. Look at the video that I have shared.

Currently I see nothing happening when I touch the screen. Did you already try to debug your script? For example line 52 of the script above looks a little bit strange to me. What does this line do?

It just checks if there is any touch, then make the touching boolean to be true.

The steering part is not yet coded. All I have is that re steering logic in update. So nothing would happen on holding your touch for now.

@Albertos

required sequence on holding the touch,
vehicle should steer left to change the lane and re steer right to face forward in the direction of motion.

required sequence on releasing the touch,
vehicle should steer right to change the lane and re steer left to face forward in the direction of motion.

I have coded two systems i.e. kinematic and dynamic entity. Kinematic entity is working fine but the dynamic one is really unstable. Please help me with the dynamic vehicle movement in the project. Just activate the respective entity in the hierarchy to test the implementations.

https://playcanvas.com/editor/scene/1555704

I have the following code to move the dynamic car with the required inputs. But after I release my touch the car starts to rotate along z axis in a boomerang fashion. Please help me fix this issue.

Full code in vehicle script.
https://playcanvas.com/editor/scene/1555704

VehicleControls.prototype.update = function (dt) {
    var targetVehicle = this.targetVehicle ? this.targetVehicle : this.entity;

    if (targetVehicle) 
    {
        var steering = 0;
        var throttle = 0;

        // Check if the car has rotated 30 degrees in the left direction
        var rotation = targetVehicle.getEulerAngles();
        var rotationThreshold = 15; // Set the rotation threshold in degrees
        // console.log(rotation.y);

        if (this.touching)
            this.touchDuration += dt;
        else if (!this.touching)
            this.touchDuration = 0;

        this.moveForward = true;

        if (this.leftKeyPressed) steering++;
        if (this.rightKeyPressed) steering--;
        if (this.moveForward) throttle++;

        // Switch lanes if moving left
        if (this.movingLeft && this.touchDuration >= this.minTouchDuration) 
        {
            if (rotation.y < rotationThreshold) { // Perform any actions you want when the car reaches the desired rotation
                steering++;
            }
            else {
                this.movingLeft = false;
            }
        }

         // Switch lanes if moving right
        if (this.movingRight) 
        {
            if (rotation.y > -rotationThreshold) { // Perform any actions you want when the car reaches the desired rotation
                steering--;
            }
            else {
                this.movingRight = false;
            }
        }

        // Smoothly rotate to face forward after completing the lane switch
        if (!this.movingLeft && !this.movingRight) 
        {
            // console.log("re steering");

            const forward = targetVehicle.forward;
            const dot = forward.dot(pc.Vec3.FORWARD);

            if (dot < 0.999) { // --- check if we are looking left/right

                const isLeft = forward.x < 0;
                steering += isLeft ? -1 : 1; // --- apply auto steering until we look forward again
            }
        }

        targetVehicle.script.vehicle.fire('vehicle:controls', steering, throttle);
    }
};

Did you already try to use a lower value on line 58?

For example 0.1 instead of 1?

I did try the value but the movement is more messy in this case.

The result looks like you steer to much to get the car back straight.

Did you debug the values of dot on line 55?

when the car is facing in straight direction then the log for dot is around 0.9999999999999982

are the rotations for the left and right lane overlapping somewhere?

Probably yes, but I don’t know how to calculate them.