4ian / GDevelop

🎮 Open-source, cross-platform 2D/3D/multiplayer game engine designed for everyone.
https://gdevelop.io
Other
11.14k stars 862 forks source link

Permissions required for device orientation extension #1333

Open Bouh opened 4 years ago

Bouh commented 4 years ago

Describe the bug

Work on exported game from web app version presently online, but not from export from application on PC.

To Reproduce

Other details

4ian commented 4 years ago

I'm wondering what could have happen as nothing was changed in this extension? 😕

Bouh commented 4 years ago

I tested with the chrome debugger, there's a simulator for orientation sensor. So it works in the simulator, in fact the problem seems to be the method to separate the objects.

code0.js:107 Uncaught TypeError: gdjs.evtTools.object.separateObjects is not a function
    at Object.gdjs.ballgameCode.eventsList0xb59d0 (code0.js:107)
    at gdjs.RuntimeScene.gdjs.ballgameCode.func [as _eventsFunction] (code0.js:162)
    at gdjs.RuntimeScene.renderAndStep (runtimescene.js:265)
    at gdjs.SceneStack.step (scenestack.js:30)
    at runtimegame.js:401
    at gameLoop (runtimegame-pixi-renderer.js:373)

Game exported from the example "ball game"

I test it on real device wait few minutes.

4ian commented 4 years ago

in fact the problem seems to be the method to separate the objects.

Yep I think there is something that was either wrongly refactored recently or I did not update the web-app GDJS runtime, or something like this.

Bouh commented 4 years ago

Even this website doesn't work on my Android devices. https://timvolodine.github.io/deviceorientation-test/

So Chrome mobile have a issue with orientation sensor at least on my devices

Gragamel commented 4 years ago

issue is that you need the ask concent via areal click on an HTML button. I raised this as a bug. I solved it editing the HTML code like this below. Notice I show a banner which click results in the consent popup:

window.onload = function () {

// Check if is IOS 13 when page loads. if ( window.DeviceMotionEvent && typeof window.DeviceMotionEvent.requestPermission === 'function' ){

  // Everything here is just a lazy banner. You can do the banner your way.
  let banner = document.createElement('div')
  banner.innerHTML = `<div style="z-index: 1; position: absolute; width: 100%; background-color:#000; color: #fff"><p style="padding: 10px">Click here to enable DeviceMotion</p></div>`
  banner.onclick = ClickRequestDeviceMotionEvent // You NEED to bind the function into a onClick event. An artificial 'onClick' will NOT work.
  banner.id='banner';
  document.querySelector('body').appendChild(banner)

} }

function ClickRequestDeviceMotionEvent () { if (typeof(DeviceMotionEvent) !== 'undefined' && typeof(DeviceMotionEvent.requestPermission) === 'function') { alert('enter'); DeviceMotionEvent.requestPermission() .then(response => { alert('resp'+ response); if (response == 'granted') { document.getElementById('banner').style.visibility='hidden';

                //Initialization
                gdjs.registerObjects();
                gdjs.registerBehaviors();
                gdjs.registerGlobalCallbacks();

                var game = new gdjs.RuntimeGame(gdjs.projectData, {});

                //Create a renderer
                game.getRenderer().createStandardCanvas(document.body);

                //Bind keyboards/mouse/touch events
                game.getRenderer().bindStandardEvents(game.getInputManager(), window, document);

                //Load all assets and start the game
                game.loadAllAssets(function() {
                    game.startGameLoop();
                });

        }
      })
  .catch(console.error)
  }else {
        alert('DeviceMotionEvent is not defined');
        gdjs.registerObjects();
        gdjs.registerBehaviors();
        gdjs.registerGlobalCallbacks();

        var game = new gdjs.RuntimeGame(gdjs.projectData, {});

        //Create a renderer
        game.getRenderer().createStandardCanvas(document.body);

        //Bind keyboards/mouse/touch events
        game.getRenderer().bindStandardEvents(game.getInputManager(), window, document);

        //Load all assets and start the game
        game.loadAllAssets(function() {
            game.startGameLoop();
        });
  }

}

arthuro555 commented 4 years ago

I think the proper approach would be to add an action "request permission" that uses DOM to add a banner (like proposed above) and add an optional text field to add custom css to the banner.

4ian commented 4 years ago

Ideally if we can, it would be great to avoid dealing with DOM/CSS entirely (as much as possible, it's good to have the whole game being rendered by WebGL, this will avoid issue with future ports to other platforms that don't have HTML/DOM/CSS). A custom banner might work, but I would do it as a very last resort.

DeviceMotionEvent.requestPermission can be called in a callback of a user gesture. An alternative approach would be to have an action (or a setting to do it automatically at game startup, if required) that set up a boolean "ask for permissions at next user gesture" to true. When this boolean is true, the game engine will call this function DeviceMotionEvent.requestPermission whenever there is a click/keyboard input.

This allow the developer to create a start screen "Touch or press a button to continue". Note that this is also already required for musics/sounds on the web (you have to touch/click the screen (or press a key?) before the web browser allow musics and sounds to play).

An even solution would be to have an action "ask for permission" that would show the permission dialog to the user, but as we can only do this in a callback to a user gesture (onClick, onTouch etc...), I'm not sure there is a way to transfer this to events :/

It's the same problem for fullscreen btw on web browser. Fullscreen won't work as it's not being done in reaction to a user gesture :/