[SOLVED] Have constant force applied to object when mobile screen is touched

Hello,

I am trying to make a simple game that works on both mobile and desktop/pc. I am currently stuck on the mobile controls. Here is the link to the editor and my movement script
https://playcanvas.com/editor/scene/1234829
https://playcanvas.com/editor/code/832792?tabs=55699174

I simply want a constant force applied to the ball dependent on where and how long they press a finger to the screen. If the user keeps their finger pressed on the right side of the screen a constant force is applied to the ball and vice versa if the finger is pressed on the left side of the screen.

I have been able to accomplish this control mechanism using both the keyboard and the mouse. It is fairly straightforward using these inputs through functions such as isPressed in the update method.

I have reviewed many of the discussion questions here and the playcanvas documentation and am aware that touchstart should be initialized and then called as its own method. I have accomplished this but force is only applied to the ball per touch and not constantly when the touch is pressed. There does not appear to be an applicable isTouched function similar to that of the mouse and keyboard that can be used in the update method. I know force can be applied constantly if the finger is moving, via touchmove, but I don’t want this type of function. I just want force applied when the finger touches and screen and then stopped when it is removed.

I have been debugging my efforts using the chrome developer tools and mobile device emulation.

Thanks in advance for any help!

Hi @hooymana and welcome!

I’m not a professional, but I think I would start with something like below.

Movement.prototype.initialize = function() {
    this.goRight = false;
    this.goLeft = false;
};

Movement.prototype.onTouchStart = function (event) {
    if (event.touches[0].x > screen.width/2) {
        this.goRight = true;
    } 
    
    if (event.touches[0].x < screen.width/2) {
        this.goLeft = true;
    }
};

Movement.prototype.update = function(dt) {
    if (this.goRight) {
        // apply force to right
    }

    if (this.goLeft) {
        // apply force to left
    }
};

Movement.prototype.onTouchEnd = function(event) {
    this.goRight = false;
    this.goLeft = false;
};
3 Likes

Hello @Albertos!

This worked splendidly. At first it was a little wonky because the touchend method was misspelled. It was touchend when it should have been onTouchEnd. Dope!

I am going to post the entire script here in case the links in this thread stop working. I became very interested in playcanvas, originally Unity user, because of its cross device compatibility through basic website. I was unsure of how well this would work but I have been happy with the results thus far.

I may post a tutorial on how this works if it seems of interest to others. I spent a lot of time reading through the documentation, looking through the forum, and scouring youtube for a way to do this with little luck.

var Movement = pc.createScript('movement');

Movement.attributes.add('speed', {
    type: 'number',    
    default: 0.1,
    min: 0.01,
    max: 0.5,
    precision: 2,
    description: 'Controls the movement speed'
});

//Movement.attributes.add('camera', {type: 'entity'});
// initialize code called once per entity
Movement.prototype.initialize = function() {
    this.force = new pc.Vec3();
    this.goRight = false;
    this.goLeft = false;
    
    
    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);
        //touch.on(pc.EVENT_TOUCHCANCEL, this.onTouchCancel, this);
    }
    else {
          console.log("No touch input available");
      }

    this.on('destroy', function() {
        touch.off(pc.EVENT_TOUCHSTART, this.onTouchStart, this);
        touch.off(pc.EVENT_TOUCHMOVE, this.onTouchMove, this);
        touch.off(pc.EVENT_TOUCHEND, this.onTouchEnd, this);
        touch.off(pc.EVENT_TOUCHCANCEL, this.onTouchCancel, this);       
    }, this);
   
    
};

// update code called every frame
Movement.prototype.update = function(dt) {
    
    var width = window.innerWidth;
    //var widths = screen.width;
    var forceX = 0;
    var forceZ = 0;
    
    if(this.goRight){
        forceX += this.speed;
        forceZ = -this.speed;
    }
    
    if(this.goLeft){
        forceX = -this.speed;
        forceZ += this.speed;
    }
    
    //Sanity Check
    //console.log(this.goRight);
    
    // calculate force based on pressed keys
    if (this.app.keyboard.isPressed(pc.KEY_LEFT)) {
        forceX = -this.speed;
        forceZ += this.speed;
    } 
    
    if (this.app.keyboard.isPressed(pc.KEY_RIGHT)) {
        forceX += this.speed;
        forceZ = -this.speed;
    }

    //If mouse is pressed on the left of the screen apply force
    if(this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT) && this.app.mouse._lastX > width/2 ){
        //console.log(this.app.mouse._lastX);
        //console.log(pc.MOUSEBUTTON_LEFT.length);
        forceX += this.speed;
        forceZ = -this.speed; 
    }
    
    //If mouse is pressed on the right of the screen apply force
    if(this.app.mouse.isPressed(pc.MOUSEBUTTON_LEFT) && this.app.mouse._lastX < width/2 ){
        //nsole.log(this.app.mouse._lastX);
        forceX = -this.speed;
        forceZ += this.speed;
    }
    
    this.force.x = forceX;
    this.force.z = forceZ;

    // if we have some non-zero force
    if (this.force.length()) {

        // calculate force vector
        var rX = Math.cos(-Math.PI * 0.25);
        var rY = Math.sin(-Math.PI * 0.25);
        this.force.set(this.force.x * rX - this.force.z * rY, 0, this.force.z * rX + this.force.x * rY);
        
        // clamp force to the speed
        if (this.force.length() > this.speed) {
            this.force.normalize().scale(this.speed);
        }
    }

    // apply impulse to move the entity
    this.entity.rigidbody.applyImpulse(this.force);
    
    //console.log(this.entity.position.x);
    //console.log(this.force.x);
};

Movement.prototype.onTouchStart = function (event) {
    //Only applies one unit of force per touch
    var widths = screen.width;
    //console.log(event.touches);
    //Go Right
    if (event.touches[0].x > widths/2) {
        this.goRight = true;
    } else{
        this.goRight = false;
    }
    
    //Go Left
    if (event.touches[0].x < widths/2) {
        this.goLeft = true;
    }else {
        this.goLeft = false;
    }

    // Needs to be called to remove 300ms delay and stop 
    // browsers consuming the event for something else
    // such as zooming in
    event.event.preventDefault();
};

Movement.prototype.onTouchEnd = function(event) {
    this.goLeft = false;
    this.goRight = false;
    event.event.preventDefault();
  };
1 Like

Great!

It’s to keep you sharp. :innocent:

1 Like

Would this logic work to detect if a controller is pressing forward or back on the same axis?

Hi @Gavin_Durbin,

If you can get the controller axis sensitivity then yes. I have coded something like this in Unity (C#) so I don’t have code that would work specifically for playcanvas unfortunately, but here is a bit I used for an xbox controller that can work as an example.

//Set speed(force) that should be applied to ridgidbody
private float speed = 7.5f;
void Update () {
//boolean checking if the input axis is active, set at a threshold of .5 for right and -.5 for left. In this //construct when the joystick is at center the sensitivity is 0, when it is all the way to the right it is 1 and 
//when all the way to the left -1.
bool joyActiveR = Input.GetAxis ("360_Joy") > .5;
bool joyActiveL = Input.GetAxis ("360_Joy") < -.5;
//If statement checking if joystick sensitivity is to the right, if yes then apply force (speed)
			if (joyActiveR)
			{
//Note that this is applying force to a 2D vector so speed is only being applied to X and not Y. For a 
//3D vector you would also have Z
				GetComponent<Rigidbody2D>().AddForce(new Vector2(speed, 0));
				transform.rotation = Quaternion.identity;
			}
//If joystick left then apply force in opposite direction
			if (joyActiveL)
			{
				GetComponent<Rigidbody2D>().AddForce(new Vector2(-speed, 0));
				transform.rotation = Quaternion.identity;
			}
}
1 Like