3

I've been battling with this for two days. I'm using an HTML5/JS game engine called ImpactJS and someone made a very useful plugin to create joystick touch zones for mobile devices. The idea is that you specify a zone on the screen where the joystick is activated when that area is touched.

The code for the plugin I am using is here. I have modified it slightly to add "curPos" (x and y coordinates of the spot that the user is currently touching), otherwise all code is identical. I have been trying to solve this problem myself as well as contacting the original creator, but they seem to be unreachable at this time and I'm getting nowhere.

I'm sure I'm doing something very wrong here, but while I can get the touch zones to work perfectly on their own, every time I try to use both joysticks at the same time they partially overwrite each other.

I have specified two zones as follows when my game initializes:

    this.joystick1 = new TouchJoystickZone(0, 0, ig.system.width / 2, ig.system.height);
    this.joystick2 = new TouchJoystickZone(ig.system.width / 2, 0, ig.system.width / 2, ig.system.height);

this.joystick1 is responsible for player rotation. this.joystick2 is responsible for player acceleration. In my Player entity I have the following movement code for the two joysticks. Again, this works perfectly when I only have one finger on the screen/one joystick in use:

            if( ig.ua.mobile ) {
            // ROTATION
            if (ig.game.joystick1.touchStart.x > 0 && ig.game.joystick1.touchStart.x < ig.system.width/2) {
                if (Math.abs(ig.game.joystick1.delta.x) >= 50 || Math.abs(ig.game.joystick1.delta.y) >= 50) {
                    this.joystickAngle = ig.game.Controller.toDegrees(ig.game.Controller.joystickAngle());
                    if (this.angle > this.joystickAngle + 20) {
                        this.angle -= this.turnSpeed * ig.system.tick;
                    }

                    else if (this.angle < this.joystickAngle - 20) {
                        this.angle += this.turnSpeed * ig.system.tick;
                    }

                    else {
                        this.angle = this.joystickAngle;
                    }
                } 
            }

            // THRUST
            if (ig.game.joystick2.touchStart.x > ig.system.width / 2) {
                if (ig.game.joystick2.delta.y <= -50) {
                    this.accel.x = Math.cos(this.angle*Math.PI/180)*this.thrust;
                    this.accel.y = (Math.sin(this.angle*Math.PI/180)*this.thrust);
                    this.fuel -= 0.1;
                }

                else if (ig.game.joystick2.delta.y >= 50) {
                    this.accel.x = Math.cos(this.angle*Math.PI/180)*-this.thrust;
                    this.accel.y = (Math.sin(this.angle*Math.PI/180)*-this.thrust);
                    this.fuel -= 0.1;
                }

            }

            else {
                this.accel.x = 0;
                this.accel.y = 0;
            }
        }

As soon as I place a second finger on the screen, however, the first joystick becomes overwritten. I can rotate and then move or move and then rotate and it works fine, but I need to do both at the same time.

I found out that touchStart.x and touchStart.y seems to be being set for both joysticks when I tap to use the other stick and not just the relevant joystick1 or joystick2, even though in the plugin code those coordinates are only meant to be affected if the touch for that joystick is within the specified zone. I believe this is partly what is contributing to the issue. At this stage I've spent hours trying to figure this out and am just as lost as when I started.

Can someone possibly point me in the right direction with using both of these joysticks at the same time?

spectralbat
  • 407
  • 2
  • 12
  • i think it is not possible in javascript because it is not multithreaded to handle this in parallel – Memos Electron Oct 23 '12 at 11:50
  • 2
    What device are you testing it on? - Does this device support multitouch outside of pinching/rotating – Rob Hardy Oct 23 '12 at 11:53
  • Sorry, I forgot to mention device details. I am testing on iPhone 4 by compiling in Xcode with Ejecta and deploying to iOS (which this plugin allegedly supports and is actually designed for). Multitouch is mentioned in the creator's forum post - there's one known bug with it not registering, but that apparently only applies if I'm using another specific plugin at the same time, which I'm not. – spectralbat Oct 23 '12 at 12:00
  • @memosdp Can't Workers be used for that? The main thread is only required for accessing the DOM, right? – Constantino Tsarouhas Mar 02 '13 at 13:08

2 Answers2

2

The joystick script you are using is only looking for the first finger. The following is from lines 47-48

    var x = ev.touches[0].pageX - pos.left,
        y = ev.touches[0].pageY - pos.top;

The '0' determines which finger to track.

The script would have the be changed to be aware which finger is on which element and then only track that finger. You could do that by either determining which element was pressed first or by location.

JSFiddle Example: http://jsfiddle.net/7WR88/5/

http://www.sitepen.com/blog/2008/07/10/touching-and-gesturing-on-the-iphone/

Dcullen
  • 669
  • 4
  • 11
  • The thing is, I thought that because I'm creating two instances of that object (one for joystick1 and another for joystick2) each time "ev" is used it refers only to touches that are relevant to that particular joystick. Would this not be the case? (I notice if I put two fingers down in each joystick's zone both joystick1.startTouch.x and joystick2.startTouch.x have values and are not 0, the values are just identical to the x coordinate of the second touch). – spectralbat Oct 23 '12 at 14:32
  • If the other finger is already pressed when you tap the second area, the other finger is the "first" touched. The tricky part is that this also works the other way around. The "first" touch is the one that is already pressed. I'll try and get an example up in jsfiddle. – Dcullen Oct 23 '12 at 14:36
  • http://jsfiddle.net/7WR88/5/ You can see in this jsfiddle on the iPhone, if you press one with each finger it is registering 2 touches on each. – Dcullen Oct 23 '12 at 15:03
  • Thanks for clarifying! However does this mean that there is no point in my creating joystick1 and joystick2 at all in my init? I've also printed the length of ev.touches to the console and consistently get '1' regardless of whether I have two fingers down or one (except strangely when _first_ putting down another tap it sometimes says '2' for a few frames, then goes back to 1). However, both joysticks' startTouch coords still register (except they both become identical on the second touch)- – spectralbat Oct 23 '12 at 17:28
  • -I'm just not sure why the plugin would require so much modification when it was allegedly designed for multitouch on iOS, with this engine. I just assumed it was a matter of me using it incorrectly. – spectralbat Oct 23 '12 at 17:28
  • Nope, looks like you did everything correct. Maybe submit an issue and he can add the functionality. The project seems pretty recently created. Sorry! – Dcullen Oct 23 '12 at 20:45
0

As mentioned by @Dcullen, there may be multiple touches in each event starting at the first touch.

It would be a simple solution to iterate through the ev.touches collection and see if each touch falls into a hotzone. If it falls under hot zone 1, treat it as a touch for joystick 1. If it falls under hotzone 2, treat it as a touch for joystick 2.

This would mean that it doesn't matter in which order the touches appear, because they will always map to the correct joystick if they are near to it.

Rob Hardy
  • 1,735
  • 13
  • 15