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
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