AR Game Mechanics Across Devices

My dear babylonians, I thank you for all you brought to the world. This game engine is amazing. We made an AR game where you basically vote during a viral pandemic. However the game is much easier on a phone where babylon runs slower. I’m wondering if anyone has general ideas on how to deal with this varied experience on platforms. I don’t mind stuff being slower but the slowness makes the game easier to win and there is my issue. I’m looking for general high level advice on this kind of issue. The game is live here: Viral Vote

So in the game there are virus falling and accumulating on your face (using jeeliz face filter), while you try to vote by opening your mouth (and spewing voting icons). The voting icons that spew from an opened mouth fly towards the camera where there is a 3d model of a politician. When the viral icons strike the 3d model, you gain vote points. The goal is reach the politician with enough votes before the viral accumulation kills you. It’s pretty weird as is, but the fact that it’s easier on a phone than on a desktop is rather annoying. I didn’t anticipate the render speed of the game engine to map to game difficulty in this way. (the project code is here, not that I expect you to look at it GitHub - mishawagon/ViralVote: Quick and dirty AR game for the browser game by Caitlin & Misha that takes advantage of jeelizFaceFilter)

What should I do besides write really long, whiny emails to online communities? Maybe I can profile performance across platforms and introduce some game logic to make it harder on desktops (but this sounds moronic).

Hey @mishawagon. Welcome to the Babylon family! Awesome to have you here!

As a general rule, adding platform specific logic, especially to influence the core game itself, is a dangerous and tricky road to go down. Your instincts are correct, you’d be far better off going down the performance optimization road than adding platform specific code.

Given that you have an AR experience, let’s bring @syntheticmagus into this thread to see if he can offer us some advice.

1 Like

Hi mishawagon,

I haven’t dived deeply into your implementation, but usually when a game’s difficulty is based on performance, it’s because behavior is being dictated by frames rather than time. (Interestingly, this is how Space Invaders accidentally invented difficulty curves.) A common approach to solving this problem is to use velocities and frame times instead of just constants per frame when determining things like object movement. For example, when moving an entity down the screen, instead of adding entityDisplacementPerFrame to the entity’s position every frame, you might instead add entityDisplacementPerSecond * lastFrameTimeInSeconds, where lastFrameTimeInSeconds is a measured value. This would cause your entity to move at the same perceived speed regardless of the execution platform’s framerate.

There may be other ways to accomplish this as well, but one simple way to get the frame time in Babylon is to just use a PerformanceMonitor.

var perfMon = new BABYLON.PerformanceMonitor(1);
perfMon.enable();
scene.onBeforeRenderObservable.add(() => {
    perfMon.sampleFrame();
    console.log("This frame took " + perfMon.instantaneousFrameTime + " milliseconds.");
});

That variable, perMon.instantaneousFrameTime, will give you the measured frame time of the executing platform, which you can then multiply by a velocity to make your game’s behavior more or less immune to render time. Can you give that a shot and see if it solves your difficulty problem?

3 Likes

Thank you so much for your feedback @syntheticmagus and @ PirateJC! It makes sense to update the rates based on perMon.instantaneousFrameTime, but that value is 0 when my solid particle systems are initialized. You see, I’m generating the game objects as particles that fly around and collide.

I think that speed is just set once at SPS initialization, so maybe I can hold off on initializing them until the animation starts and I get some frametime values?

To ensure frame rate agnostic animations, use scene.getAnimationRatio().

Gets the animation ratio (which is 1.0 is the scene renders at 60fps and 2 if the scene renders at 30fps, etc.)

2 Likes

Thank you so much @bghgary! Bizarrely my ratio is always 0.06 on macbook pro and android pixel phone. perfMon.instantaneousFrameTime does change cross-platform. I’m gonna keep digging.

I’m gonna see if I can update the rate when the particle is recycled actually. Thanks for the ideas so far!

Are you using deterministic lock step? That will cause the animation ratio to be fixed.

Doesn’t look like it @bghgary, although that would be a good explanation. If I turn on deterministic lock step I get 0.99 animation ratio on both devices. With it off and this below I get 0.06 animation ratio on both.

I’m doing: BABYLONENGINE = new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });

@syntheticmagus @bghgary Hey just to follow up I improved the cross platform performance a little bit (link to the game) by manually calculating performance using performance.now() and adjusting the particle system speeds based on that.

  //https://stackoverflow.com/questions/8279729/calculate-fps-in-canvas-using-requestanimationframe
  var lastCalledTime;
  var fps;
  var averageFPS = 0;

  function requestAnimFrame() {

    if(!lastCalledTime) {
       lastCalledTime = performance.now();
       fps = 0;
       return;
    }
    var delta = (performance.now() - lastCalledTime)/1000;



    lastCalledTime = performance.now();
    fps = 1/delta;

    averageFPS = (averageFPS + fps)/2;

    var manualAnimRatio = standardSpeed/averageFPS; //standardSpeed globalz is what I get on my computer so that's my base. ~ 38

    return manualAnimRatio;
1 Like