I have been using MelonJS for about 10 weeks, and so far everything I have coded has been pretty straight forward to implement with this engine.
I am having a problem with touch events on mobile.
Tried multiple ways of setting up a dpad, using GUI_OBJECT's, using sprites.
for example.
me.input.registerPointerEvent('pointerdown', this.padR, function (e) {
game.data._right = true;
return true;
});
me.input.registerPointerEvent('pointerup', this.padR, function (e) {
game.data._right = false;
return true;
});
me.input.registerPointerEvent('pointercancel', this.padR, function (e) {
game.data._right = false;
return true;
});
me.input.registerPointerEvent('pointerleave', this.padR, function (e) {
game.data._right = false;
return true;
});
All touchstart("pointerdown") fire correctly.
After some debugging,
it seems to be if there are 2 or more touches, the first touch never gets a "pointerup, leave or cancel" event.
Before I attempt to re-write the event handling, I would like to know
if I am doing something wrong or if this is a bug or a limitation of the engine?
Many thanks,
David
Trying out the multitouch example on my phone this morning, and the second element doesn't really respond when i interact (move) the other. We handle events by binding the pointer events to the viewport/canvas. Then proxy them down to any registered entities based on screen coordinates. Because it's the same element that might be why things are going wrong. Or it could also be in how we're handling multiple events, i'd have to test it. Sorry about this going wrong. I have an open ticket that I've been working on to re-work event detection, I'll try and solve this with it as well.
For a dpad, you should be able to get it to work with one finger at a time. But if you want two fingers down (for player to go 45 degrees), that could be an issue. If you do need to support different angles, you're probably best making a single rectangle you bind the events to, and the angle from the touch coordinate to the center of the rectangle. Use that as your movement direction.
We have a dpad, as well as jump, fire and throw.
So could have from 1 to 5 multiple touches.
I will continue with my attempts to handle the browser touch events myself and kinda fudge/hack it into your engine.
Thanks again,
David.
Ughhhh lol. I feel bad about this happening.
If it helps, I did some multi touch for a babylon js game of mine: https://github.com/agmcleod/wrathofthecube/blob/master/mouse_controls.js. Not the best of code, but handle some minor coordinate detection, and basically setting state (is this finger down or not?)
Think I'll take a break on my project the next couple of days, see if I can fix, and we can roll into 4.0 or 4.0.1
Did you try as well checking on the pointerId provided in the Event object, and only set your flag back to false when the given id is the one that initially triggerer the initial pointerdow event ?
I will see if I can get you a simple test case to look it.
Work wants me to get this fixed asap.
From my initial tests, using an extended GUI_OBJECT for each pad direction
game.dpadButtonDown = me.GUI_Object.extend(
{
init:function (x, y, padImage)
{
var settings = {};
settings.image = padImage;
this._super(me.GUI_Object, "init", [x, y, settings]);
this.pos.z = 1;
this.anchorPoint.set(0.0, 0.0);
this.isClickable = false;
},
onClick:function (event)
{
this.alpha = 0.5;
game.data._down = true;
game.data._up = false;
// don't propagate the event
return true;//false;
},
onRelease:function(event)
{
this.alpha = 1.0;
game.data._down = false;
},
onOut:function(event)
{
this.alpha = 1.0;
game.data._down = false;
}
});
the same code basically for the other directions.
Same issue first button pressed when multiple touches, first button never fires onRelease or onOut.
Doing it this way:
me.input.registerPointerEvent('pointerdown', this.padR, function (e) {
game.data._right = true;
return true;
});
me.input.registerPointerEvent('pointerup', this.padR, function (e) {
game.data._right = false;
return true;
});
me.input.registerPointerEvent('pointercancel', this.padR, function (e) {
game.data._right = false;
return true;
});
me.input.registerPointerEvent('pointerleave', this.padR, function (e) {
game.data._right = false;
return true;
});
Same result first button pressed on multiple touches, never fires up, cancel or leave.
I put some debug info in the code that handles touchstart and touchend,leave cancel.
Touchstart has/had the correct length array for the multiple touches, the array length of touchend,leave or cancel is always 1 less than touchstart, again only if there is 2 more touches happening.
I am wondering if somehow on multiple touches, the first touch(0) is being tagged as a pointer event.
I have got something working so far, for touchstart and touchend, and so far it is doing what I expected. Need to handle leave/cancel which I think I will have to handle in touchmove.
very hacky snippet of what I am doing to override your handlers.
function registerEventListener(eventList, callback) {
for (var x = 2; x < eventList.length; ++x) {
if (typeof(eventList[x]) !== "undefined")
{
//console.log(callback);
if (eventList[x].includes("touch"))
{
console.log(eventList[x]);
if (eventList[x].includes("start"))
{
console.log("start handler");
me.video.renderer.getScreenCanvas().addEventListener(eventList[x], myHandlerStart, false);
}
else if (eventList[x].includes("end"))
{
console.log("end handler");
me.video.renderer.getScreenCanvas().addEventListener(eventList[x], myHandlerEnd, false);
}
else if (eventList[x].includes("leave"))
{
console.log("leave handler");
me.video.renderer.getScreenCanvas().addEventListener(eventList[x], myHandlerLeave, false);
}
else if (eventList[x].includes("cancel"))
{
console.log("cancel handler");
me.video.renderer.getScreenCanvas().addEventListener(eventList[x], myHandlerCancel, false);
}
}
else
{
me.video.renderer.getScreenCanvas().addEventListener(eventList[x], callback, false);
}
}
}
}
The leave and cancel never get triggered for me, but that's nothing to do with MelonJS :)
Been coding since 1985 mainly in the games industry :)
Thanks again for all your help,
David.
Forgot to add in the previous post,
I keep a global list of refs to my buttons as they are added/removed
My handlers do the collision checks, touchID's and call backs from this global list.
Thanks,
David
Just saw that "this.isClickable = false;" in the code snippet
pasted an old version of that, should be "this.isClickable = true";
Thanks,
David.
The ID's all matched, the main problem I found is that if 2 or more "touchstart" events are fired.
For example I press right, then press up, both fingers touching at same time, 2 "touchstart" events are triggered.
If I then lift fingers off right and up, only 1 "touchend,leave or cancel" event is triggered, and that matches the ID of the last button pressed.
I have got my own version of it working now, its a bit hacky and very specific to the game I am working on, but the bosses are happier now.
Thanks for all your help and insight.
I looked at impactJS, phaser and cocos creator as well.
MelonJS was by far the easiest to understand and had great tutorials, which is why I choose to use it.Keep up the great work.
David.
Thank you for the feedback. It would really be great though if you would have the time to share an tiny running extract (in a zip) so that we can debug it and see how to fix it properly :)
Can't wait as well to see what you are working on !
Oliver