ssatguru / BabylonJS-CharacterController

A CharacterController for BabylonJS
Apache License 2.0
216 stars 46 forks source link

Mobile support #6

Open craze3 opened 4 years ago

craze3 commented 4 years ago

First off, I just wanted to say thanks for such a great, helpful repository! You rock!

Second, I was wondering what's the best way to tackle mobile support? I would love to be able to hold & drag my finger around the screen to walk, and pinch to zoom in/out. There's a good bablyonJS example here (load it on mobile to see what I mean): https://www.babylonjs.com/demos/sponza/

How can I implement such an option?

ssatguru commented 4 years ago

Not much support for mobile right now. On my TODO list now :)

craze3 commented 4 years ago

It seems like most modern mobile games use "joysticks" as their mobile controls. I found a great JS repo offering the same functionality: https://github.com/yoannmoinet/nipplejs

See the live demo here: https://yoannmoi.net/nipplejs/#demo (Drag & click around within the colored div to see it in action. Load on mobile to see how we would use it)

What do you think? I was thinking of implementing this myself, as a placeholder until you officially add it as a feature 😅

ssatguru commented 4 years ago

nipplejs seems like a very capable library. Maybe you can use that to generate keyboard events which can then control the CharacterController. This way you won't have to touch the CharacterController code at all. When I get some time maybe I will add a demo to show how to use nipplejs with CharacterController.

craze3 commented 4 years ago

Yes, I did a basic implementation that supports walking/running/turning in every direction. Feels really smooth on mobile! There's no reduction in performance. Here's what it looks like:

Here's how to implement it:

1. Add the following to your index.html template + styles + scripts:

<style> 
  #joystick {
    width: 50vw;
    height: 100vh;
  }
  @media only screen and (min-device-width : 768px) {
    #joystick {
      display: none;
    }
  }
</style>

<div id="joystick"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/nipplejs/0.7.3/nipplejs.js" crossorigin="anonymous"></script>

2. Add the following functions to your javascript file, and call enableJoystick() when you initialize your game:

function simulateKey (keyCode, type, modifiers) {
    var evtName = (typeof(type) === "string") ? "key" + type : "keydown";
    var modifier = (typeof(modifiers) === "object") ? modifier : {};

    var event = document.createEvent("HTMLEvents");
    event.initEvent(evtName, true, false);
    event.keyCode = keyCode;

    for (var i in modifiers) {
        event[i] = modifiers[i];
    }

    document.dispatchEvent(event);
}

function enableJoystick() {
  var sensitivity = 16;
  var options = {
      zone: document.getElementById('joystick'),
  };
  var manager = nipplejs.create(options);

  manager.on('added', function (evt, nipple) {
      nipple.on('start move end dir plain dir:up plain:up dir:left plain:left dir:down ' +
  'plain:down dir:right plain:right', function (evt) {
          //console.log(evt.target);

          // MOVING
          if(evt.target && evt.target.position) {
            var x = evt.target.collection.nipples[0].frontPosition.x;
            var y = evt.target.collection.nipples[0].frontPosition.y;
            //console.log(x.toString(),y.toString());

            // Enable/Disable Running
            if(y < -Math.abs(sensitivity*2) || y > sensitivity*2) {
              simulateKey(16, 'down');
            } else {
              simulateKey(16, 'up');
            }

            // Moving Forward
            if(y < -sensitivity){
              simulateKey(40, 'up');
              simulateKey(38, 'down'); // up arrow
            }
            else{
              simulateKey(38, 'up');
            }

            // Moving Backward
            if(y > sensitivity){
              simulateKey(38, 'up');
              simulateKey(40, 'down'); // down arrow
            }
            else {
              simulateKey(40, 'up');
            }

            // Turning Left
            if(x < -sensitivity){
              simulateKey(39, 'up');
              simulateKey(37, 'down'); // left arrow
            }
            else {
              simulateKey(37, 'up');
            }

            // Turning Right
            if(x > sensitivity){
              simulateKey(37, 'up');
              simulateKey(39, 'down'); // right arrow
            }
            else {
              simulateKey(39, 'up');
            }
          }

          // STOPPING
          if(evt.type == "end") {
            simulateKey(37, 'up'); // left
            simulateKey(38, 'up'); // up
            simulateKey(39, 'up'); // right
            simulateKey(40, 'up'); // down
            simulateKey(16, 'up'); // shift
          }
      });
    }).on('removed', function (evt, nipple) {
        nipple.off('start move end dir plain dir:up plain:up dir:left plain:left dir:down ' +
    'plain:down dir:right plain:right');
  });
}

Joystick Sensitivity: Change the var sensitivity = 16; value to change the joystick's pseudo-sensitivity. This value dictates the threshold required to start movement in any one direction.

Joystick Zone Size & Position: By default, the joystick zone will cover the entire left side of the screen. If you'd like to change this, you can modify the width: 50vw; style to change it from 50% to a different width. Or you can add float: right; or right: 0; to make it cover the right side of the screen. The opposite side of the screen will work with the standard babylonjs camera controls implemented by the CharacterController (touch & drag to rotate camera).

Joystick Zone Enabling/Disabling: By default, the joystick zone will only be enabled for for mobile/tablet screens that are < 768px in width. You can disable this by removing the display: none; style above, or by using a different @media query in style.

Future Improvements:

Hope you like! Let me know what you think.

ssatguru commented 4 years ago

Just tried out you code. Works great. Surprised how smooth it works. Awesome. :)

Do you think you can add a small demo here https://github.com/ssatguru/BabylonJS-CharacterController-Samples/tree/master/demo Or maybe create one on your github site and I can link to it?

ssatguru commented 4 years ago

@craze3 I have created a bunch of new methods to make it easy to interface with the CharacterController. See https://github.com/ssatguru/BabylonJS-CharacterController/blob/master/src/CharacterController.ts#L977 and https://github.com/ssatguru/BabylonJS-CharacterController/issues/10 I am planning to release the new version (0.4.0) by end of this week,