Porting Interdiction to Android with CocoonJS - overcoming mouse position offset problem

For the month of August I am porting Interdiction to Android using CocoonJS. The AI is far from perfect right now, but it works. I am going to keep improving it. For now, however, Android port it is. If I’m lucky I can get it all ported before this year’s js13kGames challenge starts mid-month. If that’s the case I may participate in that and release that game as the September One Game a Month project, but we’ll see.

There are quite a few modifications to be made to the game for the Android port. For one, I had to remove hover states from all the tiles because you can’t really show hover states reliably on touch screen devices. I also have to add a way to easily go back to the menu/restart the game on Android. In a browser it’s as easy as reloading the page, but on mobile having to restart the app when you want to start again without finishing the current game would get annoying.

The main problem I had with using CocoonJS is a weird mouse offset issue. The game has a Pointer entity that follows the mouse cursor position and interacts with other entities (like buttons and tiles). For some reason when running the game via the CocoonJS launched on my Nexus 4, the position seemed to become offset as I dragged from left to right of the screen. You could actually see the pointer entity being positioned farther and farther to the right of where I was actually tapping as I tapped from left to right. This wasn’t noticeable in single player Human vs AI mode because the player only had to tap on the left side of the screen, but in local two player mode this problem made it very difficult to pick up tiles belonging to Player 2.

After unsuccessfully trying to figure it out on my own, I went to the ImpactJS forum for help. And voila! Dan from the Impact forums (and the ImpactJS Facebook group) pointed me in the right direction with a code snippet. He, too, had a similar problem and ended up solving it by binding touch events and then manually calculating where the player touched and what sprite was being hit.

His code snippet didn’t actually work for me exactly, but I used the same method - adding two slightly modified event listeners for touchstart and touchmove, then using those to position the pointer entity and check against other entities instead of the ImpactJS mouse binding:

var c = document.createElement('canvas');
ig.touchLocation = {x: 0, y: 0};
c.addEventListener(
    "touchstart",
    function(touchEvent) {
        var e = touchEvent.targetTouches[0];
        var touch = Object();
        touch['x'] = e.pageX;
        touch['y'] = e.pageY;
        ig.touchLocation = touch;
        ig.touchactive = true;
    }
);

c.addEventListener(
    "touchmove",
    function(touchEvent) {
        var e = touchEvent.targetTouches[0];
        var touch = Object();
        touch['x'] = e.pageX;
        touch['y'] = e.pageY;
        ig.touchLocation = touch;
        ig.touchactive = true;
    }
);

c.id = 'canvas';
document.body.appendChild(c);
ig.main( '#canvas', Interdiction, 60, 1280, 768, 1 );

Then, in the pointer update function:

            this.pos.x = ig.touchLocation.x;
            this.pos.y = ig.touchLocation.y;

And it works! The pointer position now matches the tap/drag position perfectly.

In other news, Indie Impressions recently featured Alien Tree. Check it out.

comments powered by Disqus