[SOLVED] How to convert a swipe input into a force applied to an object (Paper Toss clone)

Hey,

I am currently working to create an AR paper toss clone. I am able to swipe to launch an orange towards a basket. But the impulse force right now is predefined and hence works the same every time, regardless of my swipe distance/time. This does not make for a fun game. I need help in figuring out how to convert my swipe input into an impulse force, so that every time I swipe, based on my swipe the force applied to the object changes.

This is the link to my project.
https://playcanvas.com/project/673559/overview/orangetoss

This is the link to my published build for testing. Please open this link on your phone

This is the link to the hiro marker. Please open this link on your laptop/desktop so you can test from your phone.

Instruction - Swipe up to toss an orange.

Hi @Nishant_Fernandez and welcome!

You can take a look at the Model Viewer template (available when creating a new project) how it calculates a panning or zooming distance when you touch and drag. You can do something similar on touch end:

TouchInput.prototype.getPinchDistance = function (pointA, pointB) {
    // Return the distance between the two points
    var dx = pointA.x - pointB.x;
    var dy = pointA.y - pointB.y;    
    
    return Math.sqrt((dx * dx) + (dy * dy));
};

TouchInput.prototype.onTouchMove = function(event) {
    
    // ...
    if (touches.length == 2) {
        // Calculate the difference in pinch distance since the last event
        var currentPinchDistance = this.getPinchDistance(touches[0], touches[1]);
        var diffInPinchDistance = currentPinchDistance - this.lastPinchDistance;
        this.lastPinchDistance = currentPinchDistance;
    }
};

You can then use that pinch distance to create and scale a force to push your object to a direction:

// example force facing upwards scaled to match the swipe distance
var force = new pc.Vec3();
var baseStrength = 100;
force.set(0, 1, 0).scale(diffInPinchDistance * baseStrength);
coinEntity.rigidbody.applyForce(force);
1 Like

Hey @Leonidas,

Thanks for this, will try to implement this logic using swipe instead of pinch and get back to you on how I do.

1 Like

For anyone else who might struggle with this, here is the way I used touch Input to calculate the power generated by a swipe to apply to a ball(orange in my use case).

Test.prototype.initialize = function ()
{
    var touch = this.app.touch;
    if(touch)
    {
        touch.on(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
        touch.on(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
        touch.on(pc.EVENT_TOUCHEND, this.onTouchEnd, this);
    }
   //Define the Variables required
    this.velocity = new pc.Vec3(0,0,0);
    this.direction = new pc.Vec3();
    this.distance = 0;
    this.power = 0;
    
    this.StartWorldPos = new pc.Vec3(0,0,0);
    this.EndWorldPos = new pc.Vec3(0,0,0);
    
    this.touchStarted = false;
    this.touchEnded = false;
    
    this.startPos = new pc.Vec2(0,0);
    this.EndPos = new pc.Vec2(0,0);
    
    this.time = 0;
    this.duration = 0;
    
    this.startX = 0;
    this.startY = 0;
    
    this.endX = 0;
    this.endY = 0;
    this.canThrow = false;
}

Test.prototype.onTouchStart = function (event)
{
    this.time = 0;
    this.duration = 0 ;
    this.touchStarted = true;
    this.touchEnded = false;
    
    //Get touch start position
    var touch = event.touches[0];
    this.startPos.set(touch.x,touch.y);
    
    this.startX = touch.x;
    this.startY = touch.y;

   //reset the power.
    this.power = 0;
    //console.log("startPos = " + this.startPos);
};


Test.prototype.onTouchEnd = function (event)
{
    this.touchStarted = false;
    this.touchEnded = true;
    this.CameraEntity.camera.screenToWorld(this.startX,this.startY,0.1,this.StartWorldPos); 
    this.CameraEntity.camera.screenToWorld(this.endX,this.endY,0.1,this.EndWorldPos);
};

Test.prototype.onTouchMove = function (event)
{
    //Get touch end position
    var touch = event.touches[0];
    this.EndPos.set(touch.x,touch.y);
    this.canThrow = true;
    this.endX = touch.x;
    this.endY = touch.y;
};

Test.prototype.update = function (event)
{
    if(this.touchStarted){
        this.time += dt;
    }else
    {
        this.duration = this.time;
    }
    if(this.touchEnded)
    {  
         //Calculate direction by subtracting startPos from endPos
         this.direction.sub2(this.EndWorldPos,this.StartWorldPos);
         this.distance = this.direction.length();
         
         //Calculate the power.
         this.power = this.distance / this.duration;

         //apply the power to the object
         var y = this.power * 10 * 2;
         var z = this.power * 10 * 2;
         this.orange.rigidbody.applyImpulse(0,y,-z);
     }
}
3 Likes

Thanks for sharing @Nishant_Fernandez!