Skip to content

Commit

Permalink
fix: Add defense around middling safari fullscreen support
Browse files Browse the repository at this point in the history
  • Loading branch information
eonarheim committed Dec 31, 2024
1 parent 9b2ea06 commit 28a9a18
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

- Add defense around middling Safari fullscreen support and update documentation
- Fixed issue where non-standard gamepad buttons would not be emitted by Excalibur
- Fixed issue where Realistic solver would not sort contacts by distance causing some artifacts on seams
- Fixed issue with CompositeCollider where large TileMaps would sometimes causes odd collision behavior in the Realistic Solver when the body & collider components are far apart in a TileMap.
Expand Down
6 changes: 3 additions & 3 deletions sandbox/src/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,10 @@ game.on('fallbackgraphicscontext', (ctx) => {
// game.graphicsContext.addPostProcessor(colorblind);

fullscreenButton.addEventListener('click', () => {
if (game.screen.isFullScreen) {
game.screen.exitFullScreen();
if (game.screen.isFullscreen) {
game.screen.exitFullscreen();
} else {
game.screen.goFullScreen('container');
game.screen.enterFullscreen('container');
}
});
game.showDebug(true);
Expand Down
21 changes: 13 additions & 8 deletions site/docs/03-screen-viewport/screens-display-modes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const game = new ex.Engine({

[[DisplayMode.FitScreen]] Fit to screen using as much space as possible while maintaining aspect ratio and resolution.

This is not the same as [[Screen.goFullScreen]], which uses the fullscreen api, but behaves in a similar way maintaining aspect ratio.
This is not the same as [[Screen.enterFullscreen]], which uses the fullscreen api, but behaves in a similar way maintaining aspect ratio.

You may want to center your game and fit to the screen here is an example:

Expand Down Expand Up @@ -75,7 +75,7 @@ Click and drag right corner to resize!

### Fill Screen Display Mode

[[DisplayMode.FillScreen]] Fill the entire screen's css width/height for the game resolution dynamically. This means the resolution of the game will change dynamically as the window is resized. This is not the same as [[Screen.goFullScreen]]
[[DisplayMode.FillScreen]] Fill the entire screen's css width/height for the game resolution dynamically. This means the resolution of the game will change dynamically as the window is resized. This is not the same as [[Screen.enterFullscreen]]

```ts twoslash {1}
// @include: ex
Expand Down Expand Up @@ -141,7 +141,7 @@ Click and drag right corner to resize!

### Fill Container Display Mode

[[DisplayMode.FillContainer]] will fill the entire screen's css width/height for the game resolution dynamically. This means the resolution of the game will change dynamically as the window is resized. This is not the same as [[Screen.goFullScreen]]
[[DisplayMode.FillContainer]] will fill the entire screen's css width/height for the game resolution dynamically. This means the resolution of the game will change dynamically as the window is resized. This is not the same as [[Screen.enterFullscreen]]

```css
.container {
Expand Down Expand Up @@ -206,6 +206,11 @@ Click and drag right corner to resize!
Click and drag right corner to resize!

## Fullscreen API
:::warning

Currently Apple does not support fullscreen API on iPhones, it does however work on later model iPads.

:::

The screen abstraction now supports the [browser fullscreen api](https://developer.mozilla.org/en-US/docs/Web/API/Fullscreen_API). This will cause the game to be displayed fullscreen until the user exits (usually with the escape key or by gesturing to the exit button at the top of the browser window).

Expand All @@ -225,17 +230,17 @@ This requires an explicit user gesture due to browser security, so wiring it int

```typescript
document.getElementById('go-fullscreen')!.addEventListener('click', () => {
game.screen.goFullScreen();
game.screen.enterFullscreen();
});
```


```typescript
await game.screen.goFullScreen();
await game.screen.enterFullscreen();

await game.screen.exitFullScreen();
await game.screen.exitFullscreen();
```

By default `goFullScreen()` will use the canvas element as the root of full screen mode. If your game uses [HTML based UI](/docs/ui#html-based-ui), the HTML UI will not be included because it is not a child of the canvas element.
By default `enterFullscreen()` will use the canvas element as the root of full screen mode. If your game uses [HTML based UI](/docs/ui#html-based-ui), the HTML UI will not be included because it is not a child of the canvas element.

To include both the HTML based game UI as well as the game canvas, pass an id of an element that is the parent of both the canvas and UI. For example `goFullScreen('root')`
To include both the HTML based game UI as well as the game canvas, pass an id of an element that is the parent of both the canvas and UI. For example `enterFullscreen('root')`
2 changes: 1 addition & 1 deletion src/engine/Director/Loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ export class Loader extends DefaultLoader {
if (this._originalOptions.fullscreenContainer instanceof HTMLElement) {
this._originalOptions.fullscreenContainer.requestFullscreen();
} else {
this.engine.screen.goFullScreen(this._originalOptions.fullscreenContainer);
this.engine.screen.enterFullscreen(this._originalOptions.fullscreenContainer);
}
} catch (error) {
this._logger.error('could not go fullscreen', error);
Expand Down
24 changes: 17 additions & 7 deletions src/engine/Screen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export enum DisplayMode {

/**
* Fit to screen using as much space as possible while maintaining aspect ratio and resolution.
* This is not the same as {@apilink Screen.goFullScreen} but behaves in a similar way maintaining aspect ratio.
* This is not the same as {@apilink Screen.enterFullscreen} but behaves in a similar way maintaining aspect ratio.
*
* You may want to center your game here is an example
* ```html
Expand All @@ -79,7 +79,7 @@ export enum DisplayMode {

/**
* Fill the entire screen's css width/height for the game resolution dynamically. This means the resolution of the game will
* change dynamically as the window is resized. This is not the same as {@apilink Screen.goFullScreen}
* change dynamically as the window is resized. This is not the same as {@apilink Screen.enterFullscreen}
*/
FillScreen = 'FillScreen',

Expand Down Expand Up @@ -347,7 +347,7 @@ export class Screen {
this._isFullscreen = !this._isFullscreen;
this._logger.debug('Fullscreen Change', this._isFullscreen);
this.events.emit('fullscreen', {
fullscreen: this.isFullScreen
fullscreen: this.isFullscreen
} satisfies FullScreenChangeEvent);
};

Expand Down Expand Up @@ -639,16 +639,26 @@ export class Screen {
public enterFullscreen(elementId?: string): Promise<void> {
if (elementId) {
const maybeElement = document.getElementById(elementId);
if (maybeElement) {
// workaround for safari partial support
if (maybeElement?.requestFullscreen || (maybeElement as any)?.webkitRequestFullscreen) {
if (!maybeElement.getAttribute('ex-fullscreen-listener')) {
maybeElement.setAttribute('ex-fullscreen-listener', 'true');
maybeElement.addEventListener('fullscreenchange', this._fullscreenChangeHandler);
}
const fullscreenPromise = maybeElement.requestFullscreen();
return fullscreenPromise;
if (maybeElement.requestFullscreen) {
return maybeElement.requestFullscreen() ?? Promise.resolve();
} else if ((maybeElement as any).webkitRequestFullscreen) {
return (maybeElement as any).webkitRequestFullscreen() ?? Promise.resolve();
}
}
}
return this._canvas.requestFullscreen();
if (this._canvas?.requestFullscreen) {
return this._canvas?.requestFullscreen() ?? Promise.resolve();
} else if ((this._canvas as any).webkitRequestFullscreen) {
return (this._canvas as any).webkitRequestFullscreen() ?? Promise.resolve();
}
this._logger.warnOnce('Could not go fullscreen, is this an iPhone? Currently Apple does not support fullscreen on iPhones');
return Promise.resolve();
}

/**
Expand Down
4 changes: 2 additions & 2 deletions src/spec/ScreenSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ describe('A Screen', () => {
viewport: { width: 800, height: 600 }
});

sut.goFullScreen();
sut.enterFullscreen();

expect(mockCanvas.requestFullscreen).toHaveBeenCalled();
});
Expand All @@ -461,7 +461,7 @@ describe('A Screen', () => {
const fakeElement = jasmine.createSpyObj('element', ['requestFullscreen', 'getAttribute', 'setAttribute', 'addEventListener']);
spyOn(document, 'getElementById').and.returnValue(fakeElement);

sut.goFullScreen('some-id');
sut.enterFullscreen('some-id');

expect(document.getElementById).toHaveBeenCalledWith('some-id');
expect(fakeElement.getAttribute).toHaveBeenCalledWith('ex-fullscreen-listener');
Expand Down

0 comments on commit 28a9a18

Please sign in to comment.