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:
- Utilizing our current information of Jetpack Compose (on cell) with Compose for Put on OS
- Attempting inputs distinctive to Put on OS units (like rotary enter through rotating bezels and facet buttons)
- Understanding what different issues wanted to be made for gaming on Put on OS
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.
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.
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.
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.
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.
This doesn’t work on a spherical gadget for 2 causes:
- The corners of the Canvas are clipped by the gadget body in order that they’re invisible to the consumer however nonetheless exist nearly. This implies if the spaceship is flying in the direction of the corners, it disappears however takes longer to reappear on the opposite facet as a result of it’s nonetheless traversing the “invisible” house
- The “reverse” facet is conceptually totally different for circles
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:
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.
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.