Pew pew! Making a Sport with Compose Canvas on Put on OS 👾 | by Ataul Munim | Android Builders | Dec, 2022


A number of weeks in the past, Sara Hamilton and I took a slight detour from our normal areas of curiosity by making a Put on OS sport utilizing Compose for Put on OS.

Our objectives included:

Pixel Watch showing an arrow-shaped spaceship drawn with 4 white lines in the center of a black screen.

We began by constructing a clone of the Chrome Dino sport during which a T-Rex jumps over cacti (besides ours was a duck that jumped over desserts — it makes simply as a lot sense, people!), and ended up with a demo of a laser-shooting spaceship in order that we’d have a bit extra… house to discover.

The muse of this sport is powered by an infinite loop which intermittently calls a perform to course of sport state and produce UI state. Since GameEngineViewModel is the screen-level state holder, that is the place the sport loop (the enterprise logic) will reside.

Diagram showing user input events flowing from the SpaceCanvas to the GameEngineViewModel and UiState flowing from the ViewModel to the SpaceCanvas. Both the update() function and user input modify GameState which is internal to the ViewModel.

replace() is a non-public perform within the ViewModel the place we are able to course of modifications to GameState, and use it to provide a brand new UiState.

Our composable perform, SpaceCanvas, renders the UiState every time a brand new one is emitted, and notifies the ViewModel about consumer enter occasions.

Rendering our sport world with Compose Canvas is good as a result of it has a easy coordinate system and contains APIs for drawing, which work on Put on OS too.

The Canvas composable’s onDraw parameter offers entry to a DrawScope, letting us draw every ingredient individually, utilizing extension capabilities to maintain our SpaceCanvas composable quick and manageable.

Every time the parameters of SpaceCanvas change, it recomposes and a brand new body is drawn. Lasers have been drawn with drawCircle():

And the spaceship itself was drawn with drawPath().

Utilizing the rotate() transformation lets us orient the ship with out having to take care of a lot of math.

There are three actions that we have to carry out as a consumer: flip, thrust and fireplace. Rotary enter appears excellent for the primary use case: turning.

Put on OS units, such because the Pixel Watch, can function a bodily rotating facet button or a rotating bezel across the watch face. The bezel may be part of the bodily {hardware} or simply part of the software program, just like the Samsung Galaxy Watch5. The rotating facet button and bezels ship details about the enter occasion to the targeted view.

We will purchase deal with the Canvas in order that these rotary scroll occasions are despatched there. The modifier ordering issues: each the focusRequester and onRotaryScrollEvent have to be utilized on one thing that’s focusable. This implies they need to come earlier than the focusable() modifier, both in the identical modifier chain (as on this case), or in one of many guardian composables:

Now, we are able to modify the ship state within the ViewModel:

and when a brand new UiState is generated on the following name to replace(), the Canvas will use the rotationDegrees to rework the spaceship’s path.

Spaceship, shaped like a white arrow, rotates both clockwise and counter-clockwise on its center, rendered on a black Pixel Watch

We will consider thrusting as a boolean state; whereas the spaceship’s thrusters are engaged, we need to apply a ahead pressure, and after they’re disengaged, we need to apply “friction” so the spaceship slows down. For this, we detect presses on the display screen utilizing the pointerInput modifier with the detectTapGestures perform:

Within the earlier snippet, onPress isn’t a easy callback — it’s a suspending perform with a PressGestureScope receiver. Right here, we are able to use tryAwaitRelease() to distinguish the down and up occasions.

Whereas the consumer presses the display screen (thrusting == true), the ViewModel will apply the ahead pressure, which can both trigger the ship to speed up or decelerate, relying on the ship’s bearing and momentum.

Spaceship accelerates towards the right of the screen, disappearing at the edge and reappearing from the opposite side. A flashing jet appears while the user is thrusting.

detectTapGestures receives one other helpful parameter, the onDoubleTap lambda, that we are able to use to detect when the consumer double-taps to make the ship fireplace a laser, as proven under.

A double tap on the screen triggers a white single-pixel laser to emit from the nose of the spaceship and move away

One of many sport’s mechanics contains “teleporting” the spaceship in order that when it flies outdoors the viewport, it reappears on the opposite facet.

On an oblong gadget, when the spaceship’s x-coordinate is lower than 0 or better than the viewport width, we set it to the other worth (and related logic for the y-coordinate and viewport top), e.g. from A to B under.

A dotted square representing the canvas with two circles labeled “A” and “B”. The “A” is on the inside of the square at the right edge, and the “B” is on the outside of the square at the left edge.
“A” signifies the present place of the spaceship because it flies off in the direction of the precise fringe of the display screen, and “B” signifies its subsequent place

This doesn’t work on a spherical gadget for 2 causes:

Left: exhibits the identical habits with a circle canvas the place the Y-coordinate doesn’t change, Proper: exhibits the specified habits with a circle canvas, the place “B” is on the other facet of the circle to “A”.

To repair this, we apply totally different logic for teleporting relying on the display screen kind, which we are able to examine from a composable perform:

A right-angled triangle is used to represent the offset of the spaceship from the center of the circle. The sides are labeled “a” (x-direction), “b” (y-direction) and “c” (distance from spaceship to center of the circle). The second image shows that we can use the same triangle to calculate the opposite side of the circle.

We all know “a” and “b” as a result of it’s absolutely the distinction between the place of the spaceship and the middle of the circle. Utilizing Pythagoras’ Theorem, we are able to calculate “c”.

If “c” is larger than the circle’s radius, it’s outdoors of the circle and we have to teleport the spaceship to the other facet, utilizing “a” and “b” to calculate the brand new place.

Demo of the spaceship flying and shooting. As it disappears from one side of the round Pixel Watch, it reappears on the opposite.

Utilizing Canvas on Put on OS is not any totally different from utilizing Canvas on cell. This is smart as a result of it’s from the compose-foundation artifact, which works on Put on OS, cell, and different surfaces that help Jetpack Compose.

We added rotary enter help to a customized part, and took gadget form under consideration with a single boolean examine! We will use the identical strategies for constructing apps on Put on OS, not simply video games, so what else do we have to take into account?

Preserving the battery is a precedence on wearables. Utilizing darkish or muted colours (as we now have) can assist the show use much less power. Should you’re making an app that requires web entry, be thoughtful of community utilization, and like to sync when the gadget is related to WiFi and a charger.

Whenever you’re utilizing gadget options like rotary enter, ensure that they’re enhancements for units which help them, however not required for ones that don’t. In our case, we must always add one other approach for the spaceship to rotate, for instance, onPressDownEvent() might change the spaceship’s bearing in addition to controlling the thrust.

Do you may have an concept for a Put on OS app, sport or demo? Present us within the #wear-compose Slack channel, on Mastodon, Twitter or under!

The code proven on this demo is accessible right here.



Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles