New API to make a resizable window

Hajime Hoshi
2019-12-23

TL;DR

We have introduced these new APIs in the master branch:

You can create a resizable window by calling SetWindowResizable(true). You can specify how the screen size will be updated after resizing the window by Game's Layout function. The notion of the screen scale is deprecated, which means that you should not have to care about the screen scale.

Background

There has been a request to have a resizable window by the user for a few years. While implementation is not difficult, we hesitated to introduce the API because there is no clear answer what is the best behavior. When a window size is changed by the user, should the game (logical) screen also be resized, or be the same but the scale should be updated? Both would make sense and be useful. There was no clear answer which is better.

Changing the window size is actually a new notion to Ebiten. Ebiten has SetScreenSize and SetScreenScale. SetScreenSize changes the logical screen size, and SetScreenScale changes the scale without changing the logical size. Both change the window size as a side effect. Both work only with window mode on desktops, and not with fullscreen mode or browsers or mobiles. There is no API to change the window size directly so far.

When the window size is changed, should the game screen size be changed, or be just scaled?

The new interface Game

We have introduced a brand new interface Game, and a new function RunGame that takes a Game, in the master branch.


  

Game has Update function and Layout function. Update proceeds the game state. Update is called every frame (per 1/60 [s] by default). This is the same as the function given to Run. Layout calculates the logical screen size based on the given outside size. The unit is device-independent pixels. The outside size is a window size on desktops (window mode). The scale is automatically adjusted based on the returned screen scale.

Actually the mobile environments already has the same interface.


  

RunGame is a very similar function to Run, but takes a Game instead of an updating function. RunGame does not determine the window size, so you have to call SetWindowSize before RunGame if necessary. Otherwise, a default window size is adopted. RunGame also does not take a window title, so you have to call SetWindowTitle instead.

Layout function

Let's see how to implement Layout function.

func (g *Game) Layout(outsideWidth, outsideHeight int)
        (screenWidth, screenHeight int) {
    return outsideWidth, outsideHeight
}

If Layout returns the outside size without changing them, the game screen size is adjusted to the outside size without changing the scale.

func (g *Game) Layout(outsideWidth, outsideHeight int)
        (screenWidth, screenHeight int) {
    return 320, 240
}

If Layout returns ignores the outside size and returns a fixed size, the game screen size is not changed but the screen scale is adjusted instead.

Layout implementation now can determine which way the game adopts. Besides, you can do more complex things by implementing your own logic!

Layout implementation can determine which way the game adopts.

Making a resizable window

To make a window resizable, call SetWindowResizable function with true. That's it! You can call it both before and after RunGame. After SetWindowResizable(true), the player can resize the window by dragging. The user can even maximize the window.

Note that SetWindowResizable(true) does not work with Run, but RunGame.

SetWindowSize is an API to change the window size directly, and this has nothing to do with SetWindowResizable. No matter what the window is resizable (by the user), SetWindowSize works.

To summarize, the new way to run the game will be in the next diagram. The new way is a little redundant compared to the current way, but the new way is more flexible for a resizable window.

Comparison between the current way (Run) and the new way (RunGame).

Example

You can see actual examples in examples/widowsize. A flag -autoadjusting switches the Layout function implementation.

Scale

After the RunGame world, the notion of the screen scale is deprecated. You don't have to care how much the screen is scaled. With the new APIs, Ebiten's game screen is automatically scaled along with the outside world (a window on desktop for example). Actually, the game was automatically scaled on browsers and mobiles no matter what the specified screen scale was. The notion of scale will be incognitive from the developer.

Deprecated functions

These functions still work, but only with Run. SetScreenSize is deprecated since the new window size is calculated based on the current screen scale. Instead of this, you can use SetWindowSize to change the window size directly. Of course, this works only on desktops.

Run is not deprecated yet, but we might deprecate this in the near future. Run is still useful as a shorthand.