NOTE: This slide contains animated GIFs which are not supported SpeakerDeck. You can watch the original animated version at http://slides.com/wajahatkarim/trex
Although Jetpack Compose is a toolkit to create Android UI in a declarative form with the power of Kotlin language. But it can be used as a canvas for generative art, animations, or even games.
In this session, we'll take a look at the capabilities of Canvas API for Jetpack Compose and how can we implement Chrome's T-Rex Dino game. We'll discuss some challenges such as game loop, game state management, infinite parallax scrolling etc.
By the end of this talk, you'll be more familiar with the concepts of Canvas in Jetpack Compose and how you can use it for games.
💻 Code available at: https://github.com/wajahatkarim3/DinoCompose
Compose ❤ Dino
Building Chrome’s T-Rex Game in Jetpack
Compose
Wajahat Karim
wajahatkarim.com
WajahatKarim
Google Dev Expert (GDE) in Android .
Android Dev. Open Source Contributor .
Technical Writer . Public Speaker
1
Compose ❤ Dino
Building Chrome’s T-Rex Game in Jetpack
Compose
2
Jetpack Compose
“ a modern UI toolkit which simplifies and
accelerates UI development on Android with
less code, powerful tools, and intuitive Kotlin
APIs.
d.android.com/jetpack/compose
3
But... wait?
“ a modern UI toolkit which simplifies and
accelerates UI development on Android with
less code, powerful tools, and intuitive Kotlin
APIs.
4
Why Games? Why not UI?
Games are more fun.
Canvas is more friendly in Compose.
Will help in making custom views
Perfect for animations.
https://github.com/alexjlockwood/bees-and-bombs-compose/
5
Game Development 101
Games have different structure than software/apps
Startup
Intro Movie
Main Menu & Settings
Loading
Main Game
Intro
Gameplay
Pause Options
Game Over / Outro
End Game / Levels
Credits
6
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
5
6
7
8
9
10
11
shutdown();
12
}
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
5
6
7
8
9
10
11
shutdown();
12
}
13
processInputs();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
5
6
7
8
9
10
11
shutdown();
12
}
13
processInputs();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
updateGameData();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
5
6
7
8
9
10
11
shutdown();
12
}
13
processInputs();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
updateGameData();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
renderGame();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
9
checkShutdown();
10
}
11
shutdown();
12
}
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
5
6
7
8
9
10
11
shutdown();
12
}
13
processInputs();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
updateGameData();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
renderGame();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
9
checkShutdown();
10
}
11
shutdown();
12
}
13
checkShutdown();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
10
}
11
shutdown();
12
}
13
7
Game Development 101
Game Loop
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
initialize();
shutdown();
// A Simple Game Loop
1
int main()
2
{
3
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
12
}
13
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
5
6
7
8
9
10
11
shutdown();
12
}
13
processInputs();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
7
updateGameData();
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
updateGameData();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
8
renderGame();
9
checkShutdown();
10
}
11
shutdown();
12
}
13
renderGame();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
9
checkShutdown();
10
}
11
shutdown();
12
}
13
checkShutdown();
// A Simple Game Loop
1
int main()
2
{
3
initialize();
4
while(true)
5
{
6
processInputs();
7
updateGameData();
8
renderGame();
9
10
}
11
shutdown();
12
}
13
// A Simple Game Loop
int main()
{
initialize();
while(true)
{
processInputs();
updateGameData();
renderGame();
checkShutdown();
}
shutdown();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
7
Compose Canvas 101
A simple Spacer() to allow you to draw anything on it
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
1
2
3
4
5
6
8
Compose Canvas 101
A simple Spacer() to allow you to draw anything on it
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
1
2
3
4
5
6 ) = Spacer(modifier.drawBehind(onDraw))
@Composable
1
fun Canvas
2
(
3
modifier: Modifier,
4
onDraw: DrawScope.() -> Unit
5
6
8
Compose Canvas 101
A simple Spacer() to allow you to draw anything on it
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
1
2
3
4
5
6 ) = Spacer(modifier.drawBehind(onDraw))
@Composable
1
fun Canvas
2
(
3
modifier: Modifier,
4
onDraw: DrawScope.() -> Unit
5
6
modifier: Modifier,
@Composable
1
fun Canvas
2
(
3
4
onDraw: DrawScope.() -> Unit
5
) = Spacer(modifier.drawBehind(onDraw))
6
8
Compose Canvas 101
A simple Spacer() to allow you to draw anything on it
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
1
2
3
4
5
6 ) = Spacer(modifier.drawBehind(onDraw))
@Composable
1
fun Canvas
2
(
3
modifier: Modifier,
4
onDraw: DrawScope.() -> Unit
5
6
modifier: Modifier,
@Composable
1
fun Canvas
2
(
3
4
onDraw: DrawScope.() -> Unit
5
) = Spacer(modifier.drawBehind(onDraw))
6
onDraw: DrawScope.() -> Unit
@Composable
1
fun Canvas
2
(
3
modifier: Modifier,
4
5
) = Spacer(modifier.drawBehind(onDraw))
6
8
Compose Canvas 101
A simple Spacer() to allow you to draw anything on it
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
1
2
3
4
5
6 ) = Spacer(modifier.drawBehind(onDraw))
@Composable
1
fun Canvas
2
(
3
modifier: Modifier,
4
onDraw: DrawScope.() -> Unit
5
6
modifier: Modifier,
@Composable
1
fun Canvas
2
(
3
4
onDraw: DrawScope.() -> Unit
5
) = Spacer(modifier.drawBehind(onDraw))
6
onDraw: DrawScope.() -> Unit
@Composable
1
fun Canvas
2
(
3
modifier: Modifier,
4
5
) = Spacer(modifier.drawBehind(onDraw))
6
@Composable
fun Canvas
(
modifier: Modifier,
onDraw: DrawScope.() -> Unit
) = Spacer(modifier.drawBehind(onDraw))
1
2
3
4
5
6
8
Compose Canvas 101
DrawScope - Handles the drawing API
drawRect() drawOval() drawLine() drawImage()
drawRoundRect() drawCircle() drawArc() drawPath()
fun DrawScope.drawMyShape() { }
9
Compose Canvas 101
Custom View Example in Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
10
Compose Canvas 101
Custom View Example in Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Canvas(modifier = Modifier.fillMaxSize()) {
1
drawCircle(
2
color = Color.Red,
3
radius = 300f
4
)
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
10
Compose Canvas 101
Custom View Example in Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Canvas(modifier = Modifier.fillMaxSize()) {
1
drawCircle(
2
color = Color.Red,
3
radius = 300f
4
)
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
drawCircle(
color = Color.Red,
radius = 300f
)
Canvas(modifier = Modifier.fillMaxSize()) {
1
2
3
4
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
10
Compose Canvas 101
Custom View Example in Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Canvas(modifier = Modifier.fillMaxSize()) {
1
drawCircle(
2
color = Color.Red,
3
radius = 300f
4
)
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
drawCircle(
color = Color.Red,
radius = 300f
)
Canvas(modifier = Modifier.fillMaxSize()) {
1
2
3
4
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
drawCircle(
color = Color.Green,
radius = 200f
)
Canvas(modifier = Modifier.fillMaxSize()) {
1
drawCircle(
2
color = Color.Red,
3
radius = 300f
4
)
5
6
7
8
9
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
10
Compose Canvas 101
Custom View Example in Canvas
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Canvas(modifier = Modifier.fillMaxSize()) {
1
drawCircle(
2
color = Color.Red,
3
radius = 300f
4
)
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
drawCircle(
color = Color.Red,
radius = 300f
)
Canvas(modifier = Modifier.fillMaxSize()) {
1
2
3
4
5
6
drawCircle(
7
color = Color.Green,
8
radius = 200f
9
)
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
drawCircle(
color = Color.Green,
radius = 200f
)
Canvas(modifier = Modifier.fillMaxSize()) {
1
drawCircle(
2
color = Color.Red,
3
radius = 300f
4
)
5
6
7
8
9
10
11
drawCircle(
12
color = Color.Blue,
13
radius = 100f
14
)
15
}
16
Canvas(modifier = Modifier.fillMaxSize()) {
drawCircle(
color = Color.Red,
radius = 300f
)
drawCircle(
color = Color.Green,
radius = 200f
)
drawCircle(
color = Color.Blue,
radius = 100f
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
10
Wanna make Dino Game?
11
Drawing Game Scene
Basics
12
Drawing Game Scene
Basics
X
12
Drawing Game Scene
Basics
X
Y
12
Drawing Game Scene
Basics
deviceWithInPixels
X
Y
12
Drawing Game Scene
Basics
deviceWithInPixels
X
Y
Earth Y
12
Drawing Game Scene
Basics
// Device Width in Pixels
var deviceMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(deviceMetrics)
deviceWidthInPixels = deviceMetrics.widthPixels
1
2
3
4
5
// Earth Y position
6
const val EARTH_Y_POSITION = 500f
7
deviceWithInPixels
X
Y
Earth Y
12
Drawing Game Scene
Basics
// Device Width in Pixels
var deviceMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(deviceMetrics)
deviceWidthInPixels = deviceMetrics.widthPixels
1
2
3
4
5
// Earth Y position
6
const val EARTH_Y_POSITION = 500f
7
// Earth Y position
const val EARTH_Y_POSITION = 500f
// Device Width in Pixels
1
var deviceMetrics = DisplayMetrics()
2
windowManager.defaultDisplay.getMetrics(deviceMetrics)
3
deviceWidthInPixels = deviceMetrics.widthPixels
4
5
6
7
deviceWithInPixels
X
Y
Earth Y
12
Drawing Game Scene
Basics
// Device Width in Pixels
var deviceMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(deviceMetrics)
deviceWidthInPixels = deviceMetrics.widthPixels
1
2
3
4
5
// Earth Y position
6
const val EARTH_Y_POSITION = 500f
7
// Earth Y position
const val EARTH_Y_POSITION = 500f
// Device Width in Pixels
1
var deviceMetrics = DisplayMetrics()
2
windowManager.defaultDisplay.getMetrics(deviceMetrics)
3
deviceWidthInPixels = deviceMetrics.widthPixels
4
5
6
7
// Device Width in Pixels
var deviceMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(deviceMetrics)
deviceWidthInPixels = deviceMetrics.widthPixels
// Earth Y position
const val EARTH_Y_POSITION = 500f
1
2
3
4
5
6
7
deviceWithInPixels
X
Y
Earth Y
12
Drawing Game Scene
Earth
13
Drawing Game Scene
Earth
fun DrawScope.EarthView(earthState: EarthState)
{
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
// Dirt Line 1
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
)
// Dirt Line 2
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
13
Drawing Game Scene
Earth
fun DrawScope.EarthView(earthState: EarthState)
{
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
// Dirt Line 1
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
)
// Dirt Line 2
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
fun DrawScope.EarthView(earthState: EarthState)
1
{
2
3
4
5
6
7
8
9
10
// Dirt Line 1
11
drawLine(
12
color = Color.DarkGray,
13
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
14
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
15
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
16
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
17
)
18
19
// Dirt Line 2
20
drawLine(
21
color = Color.DarkGray,
22
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
23
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
24
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
25
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
26
)
27
}
28
13
Drawing Game Scene
Earth
fun DrawScope.EarthView(earthState: EarthState)
{
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
// Dirt Line 1
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
)
// Dirt Line 2
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
fun DrawScope.EarthView(earthState: EarthState)
1
{
2
3
4
5
6
7
8
9
10
// Dirt Line 1
11
drawLine(
12
color = Color.DarkGray,
13
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
14
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
15
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
16
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
17
)
18
19
// Dirt Line 2
20
drawLine(
21
color = Color.DarkGray,
22
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
23
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
24
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
25
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
26
)
27
}
28
// Dirt Line 1
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
)
fun DrawScope.EarthView(earthState: EarthState)
1
{
2
// Ground Line
3
drawLine(
4
color = Color.DarkGray,
5
start = Offset(x = 0f, y = EARTH_Y_POSITION),
6
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
7
strokeWidth = EARTH_GROUND_STROKE_WIDTH
8
)
9
10
11
12
13
14
15
16
17
18
19
// Dirt Line 2
20
drawLine(
21
color = Color.DarkGray,
22
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
23
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
24
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
25
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
26
)
27
}
28
13
Drawing Game Scene
Earth
fun DrawScope.EarthView(earthState: EarthState)
{
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
// Dirt Line 1
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
)
// Dirt Line 2
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// Ground Line
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
strokeWidth = EARTH_GROUND_STROKE_WIDTH
)
fun DrawScope.EarthView(earthState: EarthState)
1
{
2
3
4
5
6
7
8
9
10
// Dirt Line 1
11
drawLine(
12
color = Color.DarkGray,
13
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
14
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
15
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
16
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
17
)
18
19
// Dirt Line 2
20
drawLine(
21
color = Color.DarkGray,
22
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
23
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
24
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
25
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
26
)
27
}
28
// Dirt Line 1
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
)
fun DrawScope.EarthView(earthState: EarthState)
1
{
2
// Ground Line
3
drawLine(
4
color = Color.DarkGray,
5
start = Offset(x = 0f, y = EARTH_Y_POSITION),
6
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
7
strokeWidth = EARTH_GROUND_STROKE_WIDTH
8
)
9
10
11
12
13
14
15
16
17
18
19
// Dirt Line 2
20
drawLine(
21
color = Color.DarkGray,
22
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
23
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
24
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
25
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
26
)
27
}
28
// Dirt Line 2
drawLine(
color = Color.DarkGray,
start = Offset(x = 0f, y = EARTH_Y_POSITION + 30),
end = Offset(x = x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 30),
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
pathEffect = DashPathEffect(floatArrayOf(15f, 50f), 40f)
)
fun DrawScope.EarthView(earthState: EarthState)
1
{
2
// Ground Line
3
drawLine(
4
color = Color.DarkGray,
5
start = Offset(x = 0f, y = EARTH_Y_POSITION),
6
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION),
7
strokeWidth = EARTH_GROUND_STROKE_WIDTH
8
)
9
10
// Dirt Line 1
11
drawLine(
12
color = Color.DarkGray,
13
start = Offset(x = 0f, y = EARTH_Y_POSITION + 20),
14
end = Offset(x = deviceWidthInPixels.toFloat(), y = EARTH_Y_POSITION + 20),
15
strokeWidth = EARTH_GROUND_STROKE_WIDTH / 5,
16
pathEffect = DashPathEffect(floatArrayOf(20f, 40f), 0f)
17
)
18
19
20
21
22
23
24
25
26
27
}
28
13
Drawing Game Scene
Vector Icons (SVG)
Icons made by from
Freepik www.flaticon.com
14
Drawing Game Scene
Vector Icons Issues
All icons are of different sizes
Canvas uses Vector icon's coordinates as
pixels
Icons need to be of size width/height at least
for uniformity
I resized all to 200x200 using this website
https://www.iloveimg.com/resize-image/resize-svg
15
Drawing Game Scene
Clouds
Text
16
Drawing Game Scene
Clouds
Text
No method to draw VectorDrawables in Canvas yet!
16
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
5
6
7
8
9
10
11
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
5
6
7
8
9
10
11
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
5
6
7
8
9
10
11
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
androidPath.transform(scaleMatrix)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
5
6
7
8
9
10
11
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
androidPath.transform(scaleMatrix)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
return androidPath.asComposePath()
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
5
6
7
8
9
10
11
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
androidPath.transform(scaleMatrix)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
return androidPath.asComposePath()
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
15
16
17
18
19
20
21
}
22
17
Drawing Game Scene
Clouds
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cloud
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Cloud Path
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
fun CloudPathNodes() = cloudPath.toNodes()
1
2
3
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun CloudPath(): Path {
var path = cloudPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
5
6
7
8
9
10
11
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
androidPath.transform(scaleMatrix)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
return androidPath.asComposePath()
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
path = cloud.path,
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
fun DrawScope.CloudsView(cloudState: CloudState)
{
drawPath(
path = cloud.path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
15
16
17
18
19
20
21
}
22
path = cloud.path,
// Cloud Path
1
private var CLOUD_PATH_STR = "M169.895,88.699C167.27,71.887 152.695,58.984 135.156,58
2
private var cloudPath = PathParser().parsePathString(CLOUD_PATH_STR)
3
fun CloudPathNodes() = cloudPath.toNodes()
4
fun CloudPath(): Path {
5
var path = cloudPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cloud
14
fun DrawScope.CloudsView(cloudState: CloudState)
15
{
16
drawPath(
17
18
color = Color(0xFFC5C5C5),
19
style = Stroke(2f)
20
)
21
}
22
17
Drawing Game Scene
Cactus
// Cactus Path
private var CACTUS_PATH_STR = "M57.449,111.191L85.246,111.191L85.246,200.145L118.605,2
private var cactusPath = PathParser().parsePathString(CACTUS_PATH_STR)
fun CactusPathNodes() = cactusPath.toNodes()
fun CactusPath(): Path {
var path = cactusPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cactus
fun DrawScope.CactusView(cactusState: CactusState)
{
drawPath(
path = cactus.path,
color = Color(0xFF000000),
style = Fill
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
18
Drawing Game Scene
Cactus
// Cactus Path
private var CACTUS_PATH_STR = "M57.449,111.191L85.246,111.191L85.246,200.145L118.605,2
private var cactusPath = PathParser().parsePathString(CACTUS_PATH_STR)
fun CactusPathNodes() = cactusPath.toNodes()
fun CactusPath(): Path {
var path = cactusPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Cactus
fun DrawScope.CactusView(cactusState: CactusState)
{
drawPath(
path = cactus.path,
color = Color(0xFF000000),
style = Fill
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun DrawScope.CactusView(cactusState: CactusState)
{
drawPath(
path = cactus.path,
color = Color(0xFF000000),
style = Fill
)
// Cactus Path
1
private var CACTUS_PATH_STR = "M57.449,111.191L85.246,111.191L85.246,200.145L118.605,2
2
private var cactusPath = PathParser().parsePathString(CACTUS_PATH_STR)
3
fun CactusPathNodes() = cactusPath.toNodes()
4
fun CactusPath(): Path {
5
var path = cactusPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Cactus
14
15
16
17
18
19
20
21
}
22
18
Drawing Game Scene
T-Rex
// T-Rex Dino
private var TREX_DINO_PATH_STR = "M93.027,18.996L173.41,18.996L173.41,60.836L93.027,60
private var trexPath = PathParser().parsePathString(TREX_DINO_PATH_STR)
fun DinoPathNodes() = trexPath.toNodes()
fun DinoPath(): Path {
var path = trexPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Dino
fun DrawScope.DinoView(dinoState: DinoState) {
{
drawPath(
path = dinoState.path
color = Color(0xFF000000),
style = Fill
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
19
Drawing Game Scene
T-Rex
// T-Rex Dino
private var TREX_DINO_PATH_STR = "M93.027,18.996L173.41,18.996L173.41,60.836L93.027,60
private var trexPath = PathParser().parsePathString(TREX_DINO_PATH_STR)
fun DinoPathNodes() = trexPath.toNodes()
fun DinoPath(): Path {
var path = trexPath.toPath()
var scaleMatrix = Matrix()
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
var androidPath = path.asAndroidPath()
androidPath.transform(scaleMatrix)
return androidPath.asComposePath()
}
// Draw Dino
fun DrawScope.DinoView(dinoState: DinoState) {
{
drawPath(
path = dinoState.path
color = Color(0xFF000000),
style = Fill
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun DrawScope.DinoView(dinoState: DinoState) {
{
drawPath(
path = dinoState.path
color = Color(0xFF000000),
style = Fill
)
// T-Rex Dino
1
private var TREX_DINO_PATH_STR = "M93.027,18.996L173.41,18.996L173.41,60.836L93.027,60
2
private var trexPath = PathParser().parsePathString(TREX_DINO_PATH_STR)
3
fun DinoPathNodes() = trexPath.toNodes()
4
fun DinoPath(): Path {
5
var path = trexPath.toPath()
6
var scaleMatrix = Matrix()
7
scaleMatrix.setScale(BASE_SCALE, BASE_SCALE, 0f, 0f)
8
var androidPath = path.asAndroidPath()
9
androidPath.transform(scaleMatrix)
10
return androidPath.asComposePath()
11
}
12
13
// Draw Dino
14
15
16
17
18
19
20
21
}
22
19
Drawing Game Scene
We need to set positions for each element dynamically
@Composable
fun DinoGameScene()
{
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
20
Game Loop in Compose
I assumed this
Compose automatically updates when state
changes
Why we even need game loop?
Compose State can do our job.
21
Game Loop in Compose
Attempt # 1 - Playing with states
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
22
Game Loop in Compose
Attempt # 1 - Playing with states
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
1
2
3
4
5
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
22
Game Loop in Compose
Attempt # 1 - Playing with states
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
1
2
3
4
5
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Cloud Model
1
data class CloudModel(
2
var xPos: Int = 0,
3
var yPos: Int = 0,
4
var path: Path = CloudPath()
5
)
6
7
8
9
10
11
12
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
22
Game Loop in Compose
Attempt # 1 - Playing with states
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
1
2
3
4
5
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Cloud Model
1
data class CloudModel(
2
var xPos: Int = 0,
3
var yPos: Int = 0,
4
var path: Path = CloudPath()
5
)
6
7
8
9
10
11
12
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Cloud Model
1
data class CloudModel(
2
var xPos: Int = 0,
3
var yPos: Int = 0,
4
var path: Path = CloudPath()
5
)
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
15
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
22
Game Loop in Compose
Attempt # 1 - Playing with states
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
1
2
3
4
5
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Cloud Model
1
data class CloudModel(
2
var xPos: Int = 0,
3
var yPos: Int = 0,
4
var path: Path = CloudPath()
5
)
6
7
8
9
10
11
12
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Cloud Model
1
data class CloudModel(
2
var xPos: Int = 0,
3
var yPos: Int = 0,
4
var path: Path = CloudPath()
5
)
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
15
16
17
// Game Loop
18
while(true) {
19
cloudsState.cloudsList.forEach { cloud ->
20
cloud.x++
21
}
22
}
23
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
// Cloud Model
1
data class CloudModel(
2
var xPos: Int = 0,
3
var yPos: Int = 0,
4
var path: Path = CloudPath()
5
)
6
7
// Cloud State
8
data class CloudState(
9
val cloudsList: ArrayList = arrayListOf(),
10
val maxClouds: Int = 3,
11
val speed: Int = 1
12
)
13
14
// Setting Cloud State
15
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
16
17
18
19
20
21
22
23
22
Game Loop in Compose
Attempt # 1 - Playing with states
// Cloud Model
data class CloudModel(
var xPos: Int = 0,
var yPos: Int = 0,
var path: Path = CloudPath()
)
// Cloud State
data class CloudState(
val cloudsList: ArrayList = arrayListOf(),
val maxClouds: Int = 3,
val speed: Int = 1
)
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
while(true) {
cloudsState.cloudsList.forEach { cloud ->
cloud.x++
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Failed. No Cloud
Anim
ation
23
Game Loop in Compose
Attempt # 2 - FrameCallback
// Cloud State
data class CloudState( /* ... */ ) {
fun moveForward()
{
cactusList.forEach { cactus ->
cactus.xPos -= cactusSpeed
}
}
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
val gameLoopCallback = object : Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
cloudsState.value = cloudsState.value.moveForward()
Choreographer.getInstance().postFrameCallback(this)
}
}
Choreographer.getInstance().postFrameCallback(gameLoopCallback)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
24
Game Loop in Compose
Attempt # 2 - FrameCallback
// Cloud State
data class CloudState( /* ... */ ) {
fun moveForward()
{
cactusList.forEach { cactus ->
cactus.xPos -= cactusSpeed
}
}
// Setting Cloud State
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED) }
// Game Loop
val gameLoopCallback = object : Choreographer.FrameCallback {
override fun doFrame(frameTimeNanos: Long) {
cloudsState.value = cloudsState.value.moveForward()
Choreographer.getInstance().postFrameCallback(this)
}
}
Choreographer.getInstance().postFrameCallback(gameLoopCallback)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Failed. No Cloud
Anim
ation
24
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun animationTimeMillis(gameloopCallback: () -> Unit): State
{
val millisState = remember { mutableStateOf(0L) }
val lifecycleOwner = LifecycleOwnerAmbient.current
launchInComposition {
val startTime = withFrameMillis { it }
lifecycleOwner.whenStarted {
while(true) {
withFrameMillis { frameTimeMillis: Long ->
millisState.value = frameTimeMillis - startTime
}
gameloopCallback.invoke()
}
}
}
return millisState
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
https://github.com/JorgeCastilloPrz/
25
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun animationTimeMillis(gameloopCallback: () -> Unit): State
{
val millisState = remember { mutableStateOf(0L) }
val lifecycleOwner = LifecycleOwnerAmbient.current
launchInComposition {
val startTime = withFrameMillis { it }
lifecycleOwner.whenStarted {
while(true) {
withFrameMillis { frameTimeMillis: Long ->
millisState.value = frameTimeMillis - startTime
}
gameloopCallback.invoke()
}
}
}
return millisState
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val millisState = remember { mutableStateOf(0L) }
@Composable
1
fun animationTimeMillis(gameloopCallback: () -> Unit): State
2
{
3
4
val lifecycleOwner = LifecycleOwnerAmbient.current
5
launchInComposition {
6
val startTime = withFrameMillis { it }
7
lifecycleOwner.whenStarted {
8
while(true) {
9
withFrameMillis { frameTimeMillis: Long ->
10
millisState.value = frameTimeMillis - startTime
11
}
12
gameloopCallback.invoke()
13
}
14
}
15
}
16
return millisState
17
}
18
https://github.com/JorgeCastilloPrz/
25
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun animationTimeMillis(gameloopCallback: () -> Unit): State
{
val millisState = remember { mutableStateOf(0L) }
val lifecycleOwner = LifecycleOwnerAmbient.current
launchInComposition {
val startTime = withFrameMillis { it }
lifecycleOwner.whenStarted {
while(true) {
withFrameMillis { frameTimeMillis: Long ->
millisState.value = frameTimeMillis - startTime
}
gameloopCallback.invoke()
}
}
}
return millisState
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val millisState = remember { mutableStateOf(0L) }
@Composable
1
fun animationTimeMillis(gameloopCallback: () -> Unit): State
2
{
3
4
val lifecycleOwner = LifecycleOwnerAmbient.current
5
launchInComposition {
6
val startTime = withFrameMillis { it }
7
lifecycleOwner.whenStarted {
8
while(true) {
9
withFrameMillis { frameTimeMillis: Long ->
10
millisState.value = frameTimeMillis - startTime
11
}
12
gameloopCallback.invoke()
13
}
14
}
15
}
16
return millisState
17
}
18
while(true) {
withFrameMillis { frameTimeMillis: Long ->
millisState.value = frameTimeMillis - startTime
}
gameloopCallback.invoke()
}
@Composable
1
fun animationTimeMillis(gameloopCallback: () -> Unit): State
2
{
3
val millisState = remember { mutableStateOf(0L) }
4
val lifecycleOwner = LifecycleOwnerAmbient.current
5
launchInComposition {
6
val startTime = withFrameMillis { it }
7
lifecycleOwner.whenStarted {
8
9
10
11
12
13
14
}
15
}
16
return millisState
17
}
18
https://github.com/JorgeCastilloPrz/
25
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun animationTimeMillis(gameloopCallback: () -> Unit): State
{
val millisState = remember { mutableStateOf(0L) }
val lifecycleOwner = LifecycleOwnerAmbient.current
launchInComposition {
val startTime = withFrameMillis { it }
lifecycleOwner.whenStarted {
while(true) {
withFrameMillis { frameTimeMillis: Long ->
millisState.value = frameTimeMillis - startTime
}
gameloopCallback.invoke()
}
}
}
return millisState
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val millisState = remember { mutableStateOf(0L) }
@Composable
1
fun animationTimeMillis(gameloopCallback: () -> Unit): State
2
{
3
4
val lifecycleOwner = LifecycleOwnerAmbient.current
5
launchInComposition {
6
val startTime = withFrameMillis { it }
7
lifecycleOwner.whenStarted {
8
while(true) {
9
withFrameMillis { frameTimeMillis: Long ->
10
millisState.value = frameTimeMillis - startTime
11
}
12
gameloopCallback.invoke()
13
}
14
}
15
}
16
return millisState
17
}
18
while(true) {
withFrameMillis { frameTimeMillis: Long ->
millisState.value = frameTimeMillis - startTime
}
gameloopCallback.invoke()
}
@Composable
1
fun animationTimeMillis(gameloopCallback: () -> Unit): State
2
{
3
val millisState = remember { mutableStateOf(0L) }
4
val lifecycleOwner = LifecycleOwnerAmbient.current
5
launchInComposition {
6
val startTime = withFrameMillis { it }
7
lifecycleOwner.whenStarted {
8
9
10
11
12
13
14
}
15
}
16
return millisState
17
}
18
return millisState
@Composable
1
fun animationTimeMillis(gameloopCallback: () -> Unit): State
2
{
3
val millisState = remember { mutableStateOf(0L) }
4
val lifecycleOwner = LifecycleOwnerAmbient.current
5
launchInComposition {
6
val startTime = withFrameMillis { it }
7
lifecycleOwner.whenStarted {
8
while(true) {
9
withFrameMillis { frameTimeMillis: Long ->
10
millisState.value = frameTimeMillis - startTime
11
}
12
gameloopCallback.invoke()
13
}
14
}
15
}
16
17
}
18
https://github.com/JorgeCastilloPrz/
25
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun DinoGameScene()
{
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
var millis = timeState.millis
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
26
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun DinoGameScene()
{
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
var millis = timeState.millis
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
@Composable
1
fun DinoGameScene()
2
{
3
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
4
5
6
7
8
9
var millis = timeState.millis
10
11
Canvas(modifier = Modifier.weight(1f)) {
12
EarthView(earthState)
13
CloudsView(cloudsState)
14
DinoView(dinoState)
15
CactusView(cactusState)
16
}
17
}
18
26
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun DinoGameScene()
{
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
var millis = timeState.millis
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
@Composable
1
fun DinoGameScene()
2
{
3
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
4
5
6
7
8
9
var millis = timeState.millis
10
11
Canvas(modifier = Modifier.weight(1f)) {
12
EarthView(earthState)
13
CloudsView(cloudsState)
14
DinoView(dinoState)
15
CactusView(cactusState)
16
}
17
}
18
var millis = timeState.millis
@Composable
1
fun DinoGameScene()
2
{
3
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
4
5
val timeState = animationTimeMillis {
6
cloudsState.moveForward()
7
}
8
9
10
11
Canvas(modifier = Modifier.weight(1f)) {
12
EarthView(earthState)
13
CloudsView(cloudsState)
14
DinoView(dinoState)
15
CactusView(cactusState)
16
}
17
}
18
26
Game Loop in Compose
Attempt # 3 - Compose Couroutines
@Composable
fun DinoGameScene()
{
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
var millis = timeState.millis
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
val timeState = animationTimeMillis {
cloudsState.moveForward()
}
@Composable
1
fun DinoGameScene()
2
{
3
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
4
5
6
7
8
9
var millis = timeState.millis
10
11
Canvas(modifier = Modifier.weight(1f)) {
12
EarthView(earthState)
13
CloudsView(cloudsState)
14
DinoView(dinoState)
15
CactusView(cactusState)
16
}
17
}
18
var millis = timeState.millis
@Composable
1
fun DinoGameScene()
2
{
3
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
4
5
val timeState = animationTimeMillis {
6
cloudsState.moveForward()
7
}
8
9
10
11
Canvas(modifier = Modifier.weight(1f)) {
12
EarthView(earthState)
13
CloudsView(cloudsState)
14
DinoView(dinoState)
15
CactusView(cactusState)
16
}
17
}
18
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
@Composable
1
fun DinoGameScene()
2
{
3
var cloudsState = remember { CloudState(maxClouds = MAX_CLOUDS, speed = CLOUDS_SPEED)
4
5
val timeState = animationTimeMillis {
6
cloudsState.moveForward()
7
}
8
9
var millis = timeState.millis
10
11
12
13
14
15
16
17
}
18
26
Game Loop in Compose
Wait... One more thing!
fun DrawScope.CloudsView(cloudState: CloudState)
{
cloudState.cloudsList.forEach {cloud ->
withTransform({
translate(
left = cloud.xPos.toFloat(),
top = cloud.yPos.toFloat()
)
})
{
drawPath(
path = cloudState.cloudsList.first().path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
27
Game Loop in Compose
Wait... One more thing!
fun DrawScope.CloudsView(cloudState: CloudState)
{
cloudState.cloudsList.forEach {cloud ->
withTransform({
translate(
left = cloud.xPos.toFloat(),
top = cloud.yPos.toFloat()
)
})
{
drawPath(
path = cloudState.cloudsList.first().path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
withTransform({
fun DrawScope.CloudsView(cloudState: CloudState)
1
{
2
cloudState.cloudsList.forEach {cloud ->
3
4
translate(
5
left = cloud.xPos.toFloat(),
6
top = cloud.yPos.toFloat()
7
)
8
})
9
{
10
drawPath(
11
path = cloudState.cloudsList.first().path,
12
color = Color(0xFFC5C5C5),
13
style = Stroke(2f)
14
)
15
}
16
}
17
}
18
27
Game Loop in Compose
Wait... One more thing!
fun DrawScope.CloudsView(cloudState: CloudState)
{
cloudState.cloudsList.forEach {cloud ->
withTransform({
translate(
left = cloud.xPos.toFloat(),
top = cloud.yPos.toFloat()
)
})
{
drawPath(
path = cloudState.cloudsList.first().path,
color = Color(0xFFC5C5C5),
style = Stroke(2f)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
withTransform({
fun DrawScope.CloudsView(cloudState: CloudState)
1
{
2
cloudState.cloudsList.forEach {cloud ->
3
4
translate(
5
left = cloud.xPos.toFloat(),
6
top = cloud.yPos.toFloat()
7
)
8
})
9
{
10
drawPath(
11
path = cloudState.cloudsList.first().path,
12
color = Color(0xFFC5C5C5),
13
style = Stroke(2f)
14
)
15
}
16
}
17
}
18
translate(
left = cloud.xPos.toFloat(),
top = cloud.yPos.toFloat()
)
fun DrawScope.CloudsView(cloudState: CloudState)
1
{
2
cloudState.cloudsList.forEach {cloud ->
3
withTransform({
4
5
6
7
8
})
9
{
10
drawPath(
11
path = cloudState.cloudsList.first().path,
12
color = Color(0xFFC5C5C5),
13
style = Stroke(2f)
14
)
15
}
16
}
17
}
18
27
Scrolling Earth
Two blocks chasing each other
28
Scrolling Earth
Two blocks chasing each other
data class EarthState( /* ... */ ) {
fun moveForward()
{
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
for (i in 0 until maxBlocks)
{
var block = blocksList[i]
block.xPos -= speed
// If first block reached end,
// move it after second
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
block.xPos = endPos
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
29
Scrolling Earth
Two blocks chasing each other
data class EarthState( /* ... */ ) {
fun moveForward()
{
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
for (i in 0 until maxBlocks)
{
var block = blocksList[i]
block.xPos -= speed
// If first block reached end,
// move it after second
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
block.xPos = endPos
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
data class EarthState( /* ... */ ) {
1
fun moveForward()
2
{
3
4
5
6
for (i in 0 until maxBlocks)
7
{
8
var block = blocksList[i]
9
block.xPos -= speed
10
11
// If first block reached end,
12
// move it after second
13
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
14
block.xPos = endPos
15
}
16
}
17
}
18
}
19
29
Scrolling Earth
Two blocks chasing each other
data class EarthState( /* ... */ ) {
fun moveForward()
{
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
for (i in 0 until maxBlocks)
{
var block = blocksList[i]
block.xPos -= speed
// If first block reached end,
// move it after second
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
block.xPos = endPos
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
data class EarthState( /* ... */ ) {
1
fun moveForward()
2
{
3
4
5
6
for (i in 0 until maxBlocks)
7
{
8
var block = blocksList[i]
9
block.xPos -= speed
10
11
// If first block reached end,
12
// move it after second
13
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
14
block.xPos = endPos
15
}
16
}
17
}
18
}
19
block.xPos -= speed
data class EarthState( /* ... */ ) {
1
fun moveForward()
2
{
3
var endPos = blocksList[maxBlocks-1].xPos
4
+ blocksList[maxBlocks-1].size
5
6
for (i in 0 until maxBlocks)
7
{
8
var block = blocksList[i]
9
10
11
// If first block reached end,
12
// move it after second
13
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
14
block.xPos = endPos
15
}
16
}
17
}
18
}
19
29
Scrolling Earth
Two blocks chasing each other
data class EarthState( /* ... */ ) {
fun moveForward()
{
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
for (i in 0 until maxBlocks)
{
var block = blocksList[i]
block.xPos -= speed
// If first block reached end,
// move it after second
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
block.xPos = endPos
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var endPos = blocksList[maxBlocks-1].xPos
+ blocksList[maxBlocks-1].size
data class EarthState( /* ... */ ) {
1
fun moveForward()
2
{
3
4
5
6
for (i in 0 until maxBlocks)
7
{
8
var block = blocksList[i]
9
block.xPos -= speed
10
11
// If first block reached end,
12
// move it after second
13
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
14
block.xPos = endPos
15
}
16
}
17
}
18
}
19
block.xPos -= speed
data class EarthState( /* ... */ ) {
1
fun moveForward()
2
{
3
var endPos = blocksList[maxBlocks-1].xPos
4
+ blocksList[maxBlocks-1].size
5
6
for (i in 0 until maxBlocks)
7
{
8
var block = blocksList[i]
9
10
11
// If first block reached end,
12
// move it after second
13
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
14
block.xPos = endPos
15
}
16
}
17
}
18
}
19
// If first block reached end,
// move it after second
if ((block.xPos + block.size) < -EARTH_OFFSET ) {
block.xPos = endPos
}
data class EarthState( /* ... */ ) {
1
fun moveForward()
2
{
3
var endPos = blocksList[maxBlocks-1].xPos
4
+ blocksList[maxBlocks-1].size
5
6
for (i in 0 until maxBlocks)
7
{
8
var block = blocksList[i]
9
block.xPos -= speed
10
11
12
13
14
15
16
}
17
}
18
}
19
29
Clouds & Cactus Generation
Getting spawned one by one
data class CloudState( /* ... */ ) {
fun moveForward()
{
for (i in 0 until maxClouds)
{
var cloud = cloudsList[i]
cloud.xPos -= speed
// If cloud is out of screen,
// Reposition it at start
if (cloud.xPos < -100) {
cloud.xPos = rand(deviceWidthInPixels,
deviceWidthInPixels * rand(1,2))
cloud.yPos = rand(0, 100)
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
30
Clouds & Cactus Generation
Getting spawned one by one
data class CloudState( /* ... */ ) {
fun moveForward()
{
for (i in 0 until maxClouds)
{
var cloud = cloudsList[i]
cloud.xPos -= speed
// If cloud is out of screen,
// Reposition it at start
if (cloud.xPos < -100) {
cloud.xPos = rand(deviceWidthInPixels,
deviceWidthInPixels * rand(1,2))
cloud.yPos = rand(0, 100)
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cloud.xPos -= speed
data class CloudState( /* ... */ ) {
1
fun moveForward()
2
{
3
for (i in 0 until maxClouds)
4
{
5
var cloud = cloudsList[i]
6
7
8
// If cloud is out of screen,
9
// Reposition it at start
10
if (cloud.xPos < -100) {
11
cloud.xPos = rand(deviceWidthInPixels,
12
deviceWidthInPixels * rand(1,2))
13
cloud.yPos = rand(0, 100)
14
}
15
}
16
}
17
}
18
30
Clouds & Cactus Generation
Getting spawned one by one
data class CloudState( /* ... */ ) {
fun moveForward()
{
for (i in 0 until maxClouds)
{
var cloud = cloudsList[i]
cloud.xPos -= speed
// If cloud is out of screen,
// Reposition it at start
if (cloud.xPos < -100) {
cloud.xPos = rand(deviceWidthInPixels,
deviceWidthInPixels * rand(1,2))
cloud.yPos = rand(0, 100)
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
cloud.xPos -= speed
data class CloudState( /* ... */ ) {
1
fun moveForward()
2
{
3
for (i in 0 until maxClouds)
4
{
5
var cloud = cloudsList[i]
6
7
8
// If cloud is out of screen,
9
// Reposition it at start
10
if (cloud.xPos < -100) {
11
cloud.xPos = rand(deviceWidthInPixels,
12
deviceWidthInPixels * rand(1,2))
13
cloud.yPos = rand(0, 100)
14
}
15
}
16
}
17
}
18
// If cloud is out of screen,
// Reposition it at start
if (cloud.xPos < -100) {
cloud.xPos = rand(deviceWidthInPixels,
deviceWidthInPixels * rand(1,2))
cloud.yPos = rand(0, 100)
}
data class CloudState( /* ... */ ) {
1
fun moveForward()
2
{
3
for (i in 0 until maxClouds)
4
{
5
var cloud = cloudsList[i]
6
cloud.xPos -= speed
7
8
9
10
11
12
13
14
15
}
16
}
17
}
18
30
Dino Jump
Detecting Tap first
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
if (!gameState.isGameOver)
dinoState.jump()
else
{
cactusState.initCactus()
dinoState.init()
gameState.replay()
}
},
indication = null)
) {
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
31
Dino Jump
Detecting Tap first
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
if (!gameState.isGameOver)
dinoState.jump()
else
{
cactusState.initCactus()
dinoState.init()
gameState.replay()
}
},
indication = null)
) {
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = {
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
indication = null)
12
) {
13
14
15
16
17
18
19
}
20
31
Dino Jump
Detecting Tap first
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
if (!gameState.isGameOver)
dinoState.jump()
else
{
cactusState.initCactus()
dinoState.init()
gameState.replay()
}
},
indication = null)
) {
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = {
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
indication = null)
12
) {
13
14
15
16
17
18
19
}
20
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
indication = null)
1
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
12
) {
13
Canvas(modifier = Modifier.weight(1f)) {
14
EarthView(earthState)
15
CloudsView(cloudsState)
16
DinoView(dinoState)
17
CactusView(cactusState)
18
}
19
}
20
31
Dino Jump
Detecting Tap first
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
if (!gameState.isGameOver)
dinoState.jump()
else
{
cactusState.initCactus()
dinoState.init()
gameState.replay()
}
},
indication = null)
) {
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = {
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
indication = null)
12
) {
13
14
15
16
17
18
19
}
20
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
indication = null)
1
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
12
) {
13
Canvas(modifier = Modifier.weight(1f)) {
14
EarthView(earthState)
15
CloudsView(cloudsState)
16
DinoView(dinoState)
17
CactusView(cactusState)
18
}
19
}
20
if (!gameState.isGameOver)
dinoState.jump()
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = {
2
3
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
indication = null)
12
) {
13
Canvas(modifier = Modifier.weight(1f)) {
14
EarthView(earthState)
15
CloudsView(cloudsState)
16
DinoView(dinoState)
17
CactusView(cactusState)
18
}
19
}
20
31
Dino Jump
Detecting Tap first
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
if (!gameState.isGameOver)
dinoState.jump()
else
{
cactusState.initCactus()
dinoState.init()
gameState.replay()
}
},
indication = null)
) {
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = {
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
indication = null)
12
) {
13
14
15
16
17
18
19
}
20
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
indication = null)
1
2
if (!gameState.isGameOver)
3
dinoState.jump()
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
12
) {
13
Canvas(modifier = Modifier.weight(1f)) {
14
EarthView(earthState)
15
CloudsView(cloudsState)
16
DinoView(dinoState)
17
CactusView(cactusState)
18
}
19
}
20
if (!gameState.isGameOver)
dinoState.jump()
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = {
2
3
4
else
5
{
6
cactusState.initCactus()
7
dinoState.init()
8
gameState.replay()
9
}
10
},
11
indication = null)
12
) {
13
Canvas(modifier = Modifier.weight(1f)) {
14
EarthView(earthState)
15
CloudsView(cloudsState)
16
DinoView(dinoState)
17
CactusView(cactusState)
18
}
19
}
20
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = {
if (!gameState.isGameOver)
dinoState.jump()
else
{
cactusState.initCactus()
dinoState.init()
gameState.replay()
}
},
indication = null)
) {
Canvas(modifier = Modifier.weight(1f)) {
EarthView(earthState)
CloudsView(cloudsState)
DinoView(dinoState)
CactusView(cactusState)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
31
Dino Jump
Making Dino Jump
data class DinoState( /* ... */ ) {
fun move() {
yPos += velocityY
velocityY += gravity
if (yPos > EARTH_Y_POSITION) {
yPos = EARTH_Y_POSITION
gravity = 0f
velocityY = 0f
isJumping = false
}
}
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
32
Dino Jump
Making Dino Jump
data class DinoState( /* ... */ ) {
fun move() {
yPos += velocityY
velocityY += gravity
if (yPos > EARTH_Y_POSITION) {
yPos = EARTH_Y_POSITION
gravity = 0f
velocityY = 0f
isJumping = false
}
}
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
data class DinoState( /* ... */ ) {
1
fun move() {
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
}
12
13
14
15
16
17
18
19
}
20
}
21
}
22
32
Dino Jump
Making Dino Jump
data class DinoState( /* ... */ ) {
fun move() {
yPos += velocityY
velocityY += gravity
if (yPos > EARTH_Y_POSITION) {
yPos = EARTH_Y_POSITION
gravity = 0f
velocityY = 0f
isJumping = false
}
}
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
data class DinoState( /* ... */ ) {
1
fun move() {
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
}
12
13
14
15
16
17
18
19
}
20
}
21
}
22
data class DinoState( /* ... */ ) {
fun move() {
}
1
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
12
13
fun jump() {
14
// Adding negative force
15
if (yPos == EARTH_Y_POSITION) {
16
isJumping = true
17
velocityY = -40f
18
gravity = 3f
19
}
20
}
21
}
22
32
Dino Jump
Making Dino Jump
data class DinoState( /* ... */ ) {
fun move() {
yPos += velocityY
velocityY += gravity
if (yPos > EARTH_Y_POSITION) {
yPos = EARTH_Y_POSITION
gravity = 0f
velocityY = 0f
isJumping = false
}
}
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
data class DinoState( /* ... */ ) {
1
fun move() {
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
}
12
13
14
15
16
17
18
19
}
20
}
21
}
22
data class DinoState( /* ... */ ) {
fun move() {
}
1
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
12
13
fun jump() {
14
// Adding negative force
15
if (yPos == EARTH_Y_POSITION) {
16
isJumping = true
17
velocityY = -40f
18
gravity = 3f
19
}
20
}
21
}
22
yPos += velocityY
velocityY += gravity
data class DinoState( /* ... */ ) {
1
fun move() {
2
3
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
}
12
13
fun jump() {
14
// Adding negative force
15
if (yPos == EARTH_Y_POSITION) {
16
isJumping = true
17
velocityY = -40f
18
gravity = 3f
19
}
20
}
21
}
22
32
Dino Jump
Making Dino Jump
data class DinoState( /* ... */ ) {
fun move() {
yPos += velocityY
velocityY += gravity
if (yPos > EARTH_Y_POSITION) {
yPos = EARTH_Y_POSITION
gravity = 0f
velocityY = 0f
isJumping = false
}
}
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
data class DinoState( /* ... */ ) {
1
fun move() {
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
}
12
13
14
15
16
17
18
19
}
20
}
21
}
22
data class DinoState( /* ... */ ) {
fun move() {
}
1
2
yPos += velocityY
3
velocityY += gravity
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
12
13
fun jump() {
14
// Adding negative force
15
if (yPos == EARTH_Y_POSITION) {
16
isJumping = true
17
velocityY = -40f
18
gravity = 3f
19
}
20
}
21
}
22
yPos += velocityY
velocityY += gravity
data class DinoState( /* ... */ ) {
1
fun move() {
2
3
4
5
if (yPos > EARTH_Y_POSITION) {
6
yPos = EARTH_Y_POSITION
7
gravity = 0f
8
velocityY = 0f
9
isJumping = false
10
}
11
}
12
13
fun jump() {
14
// Adding negative force
15
if (yPos == EARTH_Y_POSITION) {
16
isJumping = true
17
velocityY = -40f
18
gravity = 3f
19
}
20
}
21
}
22
data class DinoState( /* ... */ ) {
fun move() {
yPos += velocityY
velocityY += gravity
if (yPos > EARTH_Y_POSITION) {
yPos = EARTH_Y_POSITION
gravity = 0f
velocityY = 0f
isJumping = false
}
}
fun jump() {
// Adding negative force
if (yPos == EARTH_Y_POSITION) {
isJumping = true
velocityY = -40f
gravity = 3f
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
32
Dino Running Steps
Keyframes in Jetpack Compose
data class DinoState(
// ....
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
) {
// Current Vector Path of keyframe
val path: Path
get() = if (keyframe == 0) pathList[0] else pathList[1]
fun changeKeyframe()
{
keyframe++
if (keyframe == 1)
keyframe = 0
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
33
Dino Running Steps
Keyframes in Jetpack Compose
data class DinoState(
// ....
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
) {
// Current Vector Path of keyframe
val path: Path
get() = if (keyframe == 0) pathList[0] else pathList[1]
fun changeKeyframe()
{
keyframe++
if (keyframe == 1)
keyframe = 0
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
data class DinoState(
1
// ....
2
3
4
) {
5
// Current Vector Path of keyframe
6
val path: Path
7
get() = if (keyframe == 0) pathList[0] else pathList[1]
8
9
fun changeKeyframe()
10
{
11
keyframe++
12
if (keyframe == 1)
13
keyframe = 0
14
}
15
}
16
33
Dino Running Steps
Keyframes in Jetpack Compose
data class DinoState(
// ....
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
) {
// Current Vector Path of keyframe
val path: Path
get() = if (keyframe == 0) pathList[0] else pathList[1]
fun changeKeyframe()
{
keyframe++
if (keyframe == 1)
keyframe = 0
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
data class DinoState(
1
// ....
2
3
4
) {
5
// Current Vector Path of keyframe
6
val path: Path
7
get() = if (keyframe == 0) pathList[0] else pathList[1]
8
9
fun changeKeyframe()
10
{
11
keyframe++
12
if (keyframe == 1)
13
keyframe = 0
14
}
15
}
16
val path: Path
get() = if (keyframe == 0) pathList[0] else pathList[1]
data class DinoState(
1
// ....
2
var keyframe: Int = 0,
3
private var pathList: ArrayList = arrayListOf(),
4
) {
5
// Current Vector Path of keyframe
6
7
8
9
fun changeKeyframe()
10
{
11
keyframe++
12
if (keyframe == 1)
13
keyframe = 0
14
}
15
}
16
33
Dino Running Steps
Keyframes in Jetpack Compose
data class DinoState(
// ....
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
) {
// Current Vector Path of keyframe
val path: Path
get() = if (keyframe == 0) pathList[0] else pathList[1]
fun changeKeyframe()
{
keyframe++
if (keyframe == 1)
keyframe = 0
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var keyframe: Int = 0,
private var pathList: ArrayList = arrayListOf(),
data class DinoState(
1
// ....
2
3
4
) {
5
// Current Vector Path of keyframe
6
val path: Path
7
get() = if (keyframe == 0) pathList[0] else pathList[1]
8
9
fun changeKeyframe()
10
{
11
keyframe++
12
if (keyframe == 1)
13
keyframe = 0
14
}
15
}
16
val path: Path
get() = if (keyframe == 0) pathList[0] else pathList[1]
data class DinoState(
1
// ....
2
var keyframe: Int = 0,
3
private var pathList: ArrayList = arrayListOf(),
4
) {
5
// Current Vector Path of keyframe
6
7
8
9
fun changeKeyframe()
10
{
11
keyframe++
12
if (keyframe == 1)
13
keyframe = 0
14
}
15
}
16
fun changeKeyframe()
{
keyframe++
if (keyframe == 1)
keyframe = 0
}
data class DinoState(
1
// ....
2
var keyframe: Int = 0,
3
private var pathList: ArrayList = arrayListOf(),
4
) {
5
// Current Vector Path of keyframe
6
val path: Path
7
get() = if (keyframe == 0) pathList[0] else pathList[1]
8
9
10
11
12
13
14
15
}
16
33
Collision Detection
Debugging with Bounding Box
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
if (showBounds.value)
{
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
}
}
fun DrawScope.CactusView(cactusState: CactusState) {
// ....
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
}
fun DrawScope.DinoView(dinoState: DinoState) {
// ....
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
34
Collision Detection
Debugging with Bounding Box
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
if (showBounds.value)
{
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
}
}
fun DrawScope.CactusView(cactusState: CactusState) {
// ....
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
}
fun DrawScope.DinoView(dinoState: DinoState) {
// ....
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
34
Collision Detection
Debugging with Bounding Box
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
if (showBounds.value)
{
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
}
}
fun DrawScope.CactusView(cactusState: CactusState) {
// ....
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
}
fun DrawScope.DinoView(dinoState: DinoState) {
// ....
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
34
Collision Detection
Debugging with Bounding Box
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
if (showBounds.value)
{
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
}
}
fun DrawScope.CactusView(cactusState: CactusState) {
// ....
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
}
fun DrawScope.DinoView(dinoState: DinoState) {
// ....
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
5
6
7
8
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
34
Collision Detection
Debugging with Bounding Box
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
if (showBounds.value)
{
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
}
}
fun DrawScope.CactusView(cactusState: CactusState) {
// ....
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
}
fun DrawScope.DinoView(dinoState: DinoState) {
// ....
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
rect.deflate(DOUBT_FACTOR).size,
style = Stroke(width = 3f,
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
)
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
5
6
7
8
9
}
10
}
11
12
fun DrawScope.CactusView(cactusState: CactusState) {
13
// ....
14
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
15
}
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
fun DrawScope.CactusView(cactusState: CactusState) {
// ....
drawBoundingBox(color = Color.Red, rect = cactus.path.getBounds())
}
fun DrawScope.drawBoundingBox(color: Color, rect: Rect) {
1
if (showBounds.value)
2
{
3
drawRect(color, rect.topLeft, rect.size, style = Stroke(3f))
4
drawRect(color, rect.deflate(DOUBT_FACTOR).topLeft,
5
rect.deflate(DOUBT_FACTOR).size,
6
style = Stroke(width = 3f,
7
pathEffect = DashPathEffect(floatArrayOf(2f, 4f), 0f))
8
)
9
}
10
}
11
12
13
14
15
16
17
fun DrawScope.DinoView(dinoState: DinoState) {
18
// ....
19
drawBoundingBox(color = Color.Green, rect = dino.path.getBounds())
20
}
21
34
Collision Detection
Calculating Overlap
val state = animationTimeMillis {
if (!gameState.isGameOver)
{
// Game Loop
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
// Collision Check
cactusState.cactusList.forEach {
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
it.getBounds().deflate(DOUBT_FACTOR))) {
gameState.isGameOver = true
[email protected]
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
35
Collision Detection
Calculating Overlap
val state = animationTimeMillis {
if (!gameState.isGameOver)
{
// Game Loop
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
// Collision Check
cactusState.cactusList.forEach {
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
it.getBounds().deflate(DOUBT_FACTOR))) {
gameState.isGameOver = true
[email protected]
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
35
Collision Detection
Calculating Overlap
val state = animationTimeMillis {
if (!gameState.isGameOver)
{
// Game Loop
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
// Collision Check
cactusState.cactusList.forEach {
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
it.getBounds().deflate(DOUBT_FACTOR))) {
gameState.isGameOver = true
[email protected]
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
// Game Loop
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
35
Collision Detection
Calculating Overlap
val state = animationTimeMillis {
if (!gameState.isGameOver)
{
// Game Loop
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
// Collision Check
cactusState.cactusList.forEach {
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
it.getBounds().deflate(DOUBT_FACTOR))) {
gameState.isGameOver = true
[email protected]
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
// Game Loop
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
5
6
7
8
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
35
Collision Detection
Calculating Overlap
val state = animationTimeMillis {
if (!gameState.isGameOver)
{
// Game Loop
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
// Collision Check
cactusState.cactusList.forEach {
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
it.getBounds().deflate(DOUBT_FACTOR))) {
gameState.isGameOver = true
[email protected]
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
// Game Loop
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
gameState.increaseScore()
cloudsState.moveForward()
earthState.moveForward()
cactusState.moveForward()
dinoState.move()
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
5
6
7
8
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
13
it.getBounds().deflate(DOUBT_FACTOR))) {
14
gameState.isGameOver = true
15
[email protected]
16
}
17
}
18
}
19
}
20
if (dinoState.getBounds().deflate(DOUBT_FACTOR).overlaps(
it.getBounds().deflate(DOUBT_FACTOR))) {
gameState.isGameOver = true
[email protected]
val state = animationTimeMillis {
1
if (!gameState.isGameOver)
2
{
3
// Game Loop
4
gameState.increaseScore()
5
cloudsState.moveForward()
6
earthState.moveForward()
7
cactusState.moveForward()
8
dinoState.move()
9
10
// Collision Check
11
cactusState.cactusList.forEach {
12
13
14
15
16
}
17
}
18
}
19
}
20
35
Scoring
Updating Scores
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
}
@Composable
fun HighScoreTextViews(gameState: GameState)
{
Spacer(modifier = Modifier.padding(top = 50.dp))
Row(
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
horizontalArrangement = Arrangement.End
) {
Text(text = "HI")
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.highScore}".padStart(5, '0'))
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.currentScore}".padStart(5, '0'))
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
36
Scoring
Updating Scores
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
}
@Composable
fun HighScoreTextViews(gameState: GameState)
{
Spacer(modifier = Modifier.padding(top = 50.dp))
Row(
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
horizontalArrangement = Arrangement.End
) {
Text(text = "HI")
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.highScore}".padStart(5, '0'))
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.currentScore}".padStart(5, '0'))
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
HighScoreTextViews(gameState)
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
}
9
10
@Composable
11
fun HighScoreTextViews(gameState: GameState)
12
{
13
Spacer(modifier = Modifier.padding(top = 50.dp))
14
Row(
15
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
16
horizontalArrangement = Arrangement.End
17
) {
18
Text(text = "HI")
19
Spacer(modifier = Modifier.padding(start = 10.dp))
20
Text(text = "${gameState.highScore}".padStart(5, '0'))
21
Spacer(modifier = Modifier.padding(start = 10.dp))
22
Text(text = "${gameState.currentScore}".padStart(5, '0'))
23
}
24
}
25
36
Scoring
Updating Scores
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
}
@Composable
fun HighScoreTextViews(gameState: GameState)
{
Spacer(modifier = Modifier.padding(top = 50.dp))
Row(
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
horizontalArrangement = Arrangement.End
) {
Text(text = "HI")
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.highScore}".padStart(5, '0'))
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.currentScore}".padStart(5, '0'))
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
HighScoreTextViews(gameState)
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
}
9
10
@Composable
11
fun HighScoreTextViews(gameState: GameState)
12
{
13
Spacer(modifier = Modifier.padding(top = 50.dp))
14
Row(
15
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
16
horizontalArrangement = Arrangement.End
17
) {
18
Text(text = "HI")
19
Spacer(modifier = Modifier.padding(start = 10.dp))
20
Text(text = "${gameState.highScore}".padStart(5, '0'))
21
Spacer(modifier = Modifier.padding(start = 10.dp))
22
Text(text = "${gameState.currentScore}".padStart(5, '0'))
23
}
24
}
25
fun HighScoreTextViews(gameState: GameState)
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
}
9
10
@Composable
11
12
{
13
Spacer(modifier = Modifier.padding(top = 50.dp))
14
Row(
15
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
16
horizontalArrangement = Arrangement.End
17
) {
18
Text(text = "HI")
19
Spacer(modifier = Modifier.padding(start = 10.dp))
20
Text(text = "${gameState.highScore}".padStart(5, '0'))
21
Spacer(modifier = Modifier.padding(start = 10.dp))
22
Text(text = "${gameState.currentScore}".padStart(5, '0'))
23
}
24
}
25
36
Scoring
Updating Scores
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
}
@Composable
fun HighScoreTextViews(gameState: GameState)
{
Spacer(modifier = Modifier.padding(top = 50.dp))
Row(
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
horizontalArrangement = Arrangement.End
) {
Text(text = "HI")
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.highScore}".padStart(5, '0'))
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.currentScore}".padStart(5, '0'))
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
HighScoreTextViews(gameState)
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
}
9
10
@Composable
11
fun HighScoreTextViews(gameState: GameState)
12
{
13
Spacer(modifier = Modifier.padding(top = 50.dp))
14
Row(
15
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
16
horizontalArrangement = Arrangement.End
17
) {
18
Text(text = "HI")
19
Spacer(modifier = Modifier.padding(start = 10.dp))
20
Text(text = "${gameState.highScore}".padStart(5, '0'))
21
Spacer(modifier = Modifier.padding(start = 10.dp))
22
Text(text = "${gameState.currentScore}".padStart(5, '0'))
23
}
24
}
25
fun HighScoreTextViews(gameState: GameState)
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
}
9
10
@Composable
11
12
{
13
Spacer(modifier = Modifier.padding(top = 50.dp))
14
Row(
15
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
16
horizontalArrangement = Arrangement.End
17
) {
18
Text(text = "HI")
19
Spacer(modifier = Modifier.padding(start = 10.dp))
20
Text(text = "${gameState.highScore}".padStart(5, '0'))
21
Spacer(modifier = Modifier.padding(start = 10.dp))
22
Text(text = "${gameState.currentScore}".padStart(5, '0'))
23
}
24
}
25
Spacer(modifier = Modifier.padding(top = 50.dp))
Row(
modifier = Modifier.fillMaxWidth().padding(end = 20.dp),
horizontalArrangement = Arrangement.End
) {
Text(text = "HI")
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.highScore}".padStart(5, '0'))
Spacer(modifier = Modifier.padding(start = 10.dp))
Text(text = "${gameState.currentScore}".padStart(5, '0'))
}
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
}
9
10
@Composable
11
fun HighScoreTextViews(gameState: GameState)
12
{
13
14
15
16
17
18
19
20
21
22
23
24
}
25
36
Game Over
Finally...
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
}
@Composable
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
{
Column(modifier = modifier) {
Text(
text = if (isGameOver) "GAME OVER" else "",
// ... More attributes
)
if (isGameOver) {
Image(
asset = vectorResource(id = R.drawable.ic_replay),
modifier = Modifier.preferredSize(40.dp)
.align(alignment = Alignment.CenterHorizontally)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
37
Game Over
Finally...
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
}
@Composable
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
{
Column(modifier = modifier) {
Text(
text = if (isGameOver) "GAME OVER" else "",
// ... More attributes
)
if (isGameOver) {
Image(
asset = vectorResource(id = R.drawable.ic_replay),
modifier = Modifier.preferredSize(40.dp)
.align(alignment = Alignment.CenterHorizontally)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
9
10
}
11
12
@Composable
13
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
14
{
15
Column(modifier = modifier) {
16
Text(
17
text = if (isGameOver) "GAME OVER" else "",
18
// ... More attributes
19
)
20
if (isGameOver) {
21
Image(
22
asset = vectorResource(id = R.drawable.ic_replay),
23
modifier = Modifier.preferredSize(40.dp)
24
.align(alignment = Alignment.CenterHorizontally)
25
)
26
}
27
}
28
}
29
37
Game Over
Finally...
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
}
@Composable
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
{
Column(modifier = modifier) {
Text(
text = if (isGameOver) "GAME OVER" else "",
// ... More attributes
)
if (isGameOver) {
Image(
asset = vectorResource(id = R.drawable.ic_replay),
modifier = Modifier.preferredSize(40.dp)
.align(alignment = Alignment.CenterHorizontally)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
9
10
}
11
12
@Composable
13
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
14
{
15
Column(modifier = modifier) {
16
Text(
17
text = if (isGameOver) "GAME OVER" else "",
18
// ... More attributes
19
)
20
if (isGameOver) {
21
Image(
22
asset = vectorResource(id = R.drawable.ic_replay),
23
modifier = Modifier.preferredSize(40.dp)
24
.align(alignment = Alignment.CenterHorizontally)
25
)
26
}
27
}
28
}
29
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
GameOverTextView(gameState.isGameOver,
9
modifier = Modifier.align(Alignment.Center))
10
}
11
12
@Composable
13
14
{
15
Column(modifier = modifier) {
16
Text(
17
text = if (isGameOver) "GAME OVER" else "",
18
// ... More attributes
19
)
20
if (isGameOver) {
21
Image(
22
asset = vectorResource(id = R.drawable.ic_replay),
23
modifier = Modifier.preferredSize(40.dp)
24
.align(alignment = Alignment.CenterHorizontally)
25
)
26
}
27
}
28
}
29
37
Game Over
Finally...
Column(modifier = Modifier.fillMaxWidth().clickable(
onClick = { /* ... */ },
indication = null)
) {
HighScoreTextViews(gameState)
Canvas(modifier = Modifier.weight(1f)) {
// Game drawing
}
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
}
@Composable
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
{
Column(modifier = modifier) {
Text(
text = if (isGameOver) "GAME OVER" else "",
// ... More attributes
)
if (isGameOver) {
Image(
asset = vectorResource(id = R.drawable.ic_replay),
modifier = Modifier.preferredSize(40.dp)
.align(alignment = Alignment.CenterHorizontally)
)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
GameOverTextView(gameState.isGameOver,
modifier = Modifier.align(Alignment.Center))
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
9
10
}
11
12
@Composable
13
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
14
{
15
Column(modifier = modifier) {
16
Text(
17
text = if (isGameOver) "GAME OVER" else "",
18
// ... More attributes
19
)
20
if (isGameOver) {
21
Image(
22
asset = vectorResource(id = R.drawable.ic_replay),
23
modifier = Modifier.preferredSize(40.dp)
24
.align(alignment = Alignment.CenterHorizontally)
25
)
26
}
27
}
28
}
29
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
GameOverTextView(gameState.isGameOver,
9
modifier = Modifier.align(Alignment.Center))
10
}
11
12
@Composable
13
14
{
15
Column(modifier = modifier) {
16
Text(
17
text = if (isGameOver) "GAME OVER" else "",
18
// ... More attributes
19
)
20
if (isGameOver) {
21
Image(
22
asset = vectorResource(id = R.drawable.ic_replay),
23
modifier = Modifier.preferredSize(40.dp)
24
.align(alignment = Alignment.CenterHorizontally)
25
)
26
}
27
}
28
}
29
text = if (isGameOver) "GAME OVER" else "",
if (isGameOver) {
Column(modifier = Modifier.fillMaxWidth().clickable(
1
onClick = { /* ... */ },
2
indication = null)
3
) {
4
HighScoreTextViews(gameState)
5
Canvas(modifier = Modifier.weight(1f)) {
6
// Game drawing
7
}
8
GameOverTextView(gameState.isGameOver,
9
modifier = Modifier.align(Alignment.Center))
10
}
11
12
@Composable
13
fun GameOverTextView(isGameOver: Boolean = true, modifier: Modifier = Mod
14
{
15
Column(modifier = modifier) {
16
Text(
17
18
// ... More attributes
19
)
20
21
Image(
22
asset = vectorResource(id = R.drawable.ic_replay),
23
modifier = Modifier.preferredSize(40.dp)
24
.align(alignment = Alignment.CenterHorizontally)
25
)
26
}
27
}
28
}
29
37
Summary
It was super fun to make a game in Jetpack Compose
Canvas
Game Loop
Vector Paths
State Handling
Bounding Box
38
Thank You for Listening!
Code is available at github.com/wajahatkarim3/DinoCompose
WajahatKarim
wajahatkarim.com/subscribe
wajahatkarim.com
39