Why isn't there a stationary phase for touch event?

It would be great to handle a case where player hold the touch while moving or dragging (swerve mechanics).

Hi @yash_mehrotra! Maybe the tutorial project below can help you.

https://developer.playcanvas.com/en/tutorials/basic-touch-input/

Yeah I have followed this tutorial.

There are four phases i.e. start, moved, end and cancel. But there is a stationary phase (drag hold) while moving the entity through touch events.

In that case the entity stutters.

I don’t see this happening in the tutorial project, or are you using a different approach?

Naah this issue is not related to the project you shared. I am facing it in a game where an entity is moving through swerve mechanics.

I wrote this code in unity using c# to move an entity through swerve mechanics. You could see a stationary phase that unity provide for touch events.

 private float startTouch;
 private float swipeDelta;
 
 private void Update()
     {
         if(Input.touchCount > 0)
         {
             Touch touch = Input.GetTouch(0);
             if(touch.phase == TouchPhase.Began)
             {
                 startTouch = touch.position.x;
             }
             if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary) 
             {
                 swipeDelta = touch.position.x - startTouch;
                 startTouch = touch.position.x;
             }
             if(touch.phase == TouchPhase.Ended)
             {
                 swipeDelta = 0;
             }
         }
         dir.x = swipeDelta * sideSpeed;
     }

Unity’s Touch Phases -

I don’t know why this phase doesn’t exist in PlayCanvas. Maybe you can create this phase for yourself, using the existing events. Below a related topic.

PlayCanvas input events generally mirror what you get from the browser. The browser does not have a stationary touch event so PlayCanvas doesn’t have one either

Taking your code here, the way I would do it is:

 private float startTouch;
 private float swipeDelta;
 
 private void Update()
     {
         if(Input.touchCount > 0)
         {
             Touch touch = Input.GetTouch(0);
             if(touch.phase == TouchPhase.Began)
             {
                 startTouch = touch.position.x;
             }
             if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary) 
             {
                 swipeDelta = touch.position.x - startTouch;
                 startTouch = touch.position.x;
             }
             if(touch.phase == TouchPhase.Ended)
             {
                 swipeDelta = 0;
             }
         }
         dir.x = swipeDelta * sideSpeed;
     }

Would translate to something like this:

var TouchTest = pc.createScript('touchTest');

// initialize code called once per entity
TouchTest.prototype.initialize = function() {
    this.touching = false;
    this.startPosition = new pc.Vec2();
    this.currentPosition = new pc.Vec2();
    this.setEventsOnOff('on');
    this.on('destroy', () => {
        this.setEventsOnOff('off');
    });
};


TouchTest.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);
    }
};


// update code called every frame
TouchTest.prototype.update = function(dt) {
    let swipeDelta = 0;
    if (this.touching) {
        swipeDelta = this.currentPosition.x - this.startPosition.x;
        this.startPosition.copy(this.currentPosition);
        console.log(swipeDelta);
    }
};


TouchTest.prototype.onTouchStart = function(event) {
    const touches = event.touches;
    this.touching = touches.length === 1;
    if (this.touching) {
        this.startPosition.set(touches[0].x, touches[0].y);
        this.currentPosition.set(touches[0].x, touches[0].y);
    }
};


TouchTest.prototype.onTouchEndCancel = function(event) {
    const touches = event.touches;
    this.touching = touches.length === 1;
};


TouchTest.prototype.onTouchMove = function(event) {
    const touches = event.touches;
    if (this.touching) {
        this.currentPosition.set(touches[0].x, touches[0].y);
    }
};

// swap method called for script hot-reloading
// inherit your script state here
// TouchTest.prototype.swap = function(old) { };

// to learn more about script anatomy, please read:
// https://developer.playcanvas.com/en/user-manual/scripting/

Alternatively, you could try https://github.com/Maksims/mr-Tap as an alternative input system

Thankyou for this. I would verify the same.