[Kotlin/Compose] 슬라이드를 이용한 공 던지기 모션 만들기

요약

지난 번에 공부했던, anchoredDraggable을 이용하여 슬라이드를 통한 공을 던지는 모션을 제작해보고자 합니다.

 

공의 시작 위치는 기기의 하단 가운데 이며 위로 스크롤 하게 되면, 상단 중앙 포수가 있는 위치까지 날아가게 됩니다.

 

사용자가 던지게 되면, graphicsLayer를 통해 rotationZ값을 drag된 위치에 따라 계산하여, 회전하는 듯한 모션을 주어 공을 던지는 느낌을 주었습니다.

 

또한 공이 포수 위치까지 도달하게 되면, coroutine을 이용하여 0.5초 딜레이를 주어 다시 원래 초기 위치로 돌아가도록 설정하였습니다.

완성

슈웃

전체 코드

class MainActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        setContent {  
            ShootingballTheme {  
                // A surface container using the 'background' color from the theme  
                Surface(  
                    modifier = Modifier.fillMaxSize(),  
                    color = MaterialTheme.colorScheme.background  
                ) {  
                    Ground()  
                }  
            }        }    }  
}  

@OptIn(ExperimentalFoundationApi::class)  
@Composable  
private fun Ground(modifier: Modifier = Modifier){  
    var componentSize by remember {  
        mutableStateOf(IntSize.Zero)  
    }  
    val density = LocalDensity.current  

    var state = remember {  
        AnchoredDraggableState(  
            initialValue = Position.Start,  
            positionalThreshold = {totalDistance : Float -> totalDistance},  
            velocityThreshold = {Float.MIN_VALUE},  
            animationSpec = tween()  

        )  
    }  


    LaunchedEffect(componentSize){  
        if(componentSize.width > 0) {  
            val endPosition = with(density){(componentSize.height - 40.dp.toPx()) - 60.dp.toPx()}  
            state.updateAnchors(  
                DraggableAnchors {  
                    Position.Start at -0f  
                    Position.End at -endPosition  
                }  
            )  
            if(state.offset.isNaN()) {  
            }  
        }  
    }  

    LaunchedEffect(state.currentValue){  
        if(state.currentValue == Position.End){  
            delay(1000)  
            state.snapTo(Position.Start)  
        }  
    }  

    Box(  
        modifier = modifier  
            .fillMaxSize()  
            .background(color = Color.LightGray)  
            .onGloballyPositioned {  
                componentSize = it.size  
            }  
    ){  
        Image(  
            painter = painterResource(id = R.drawable.posu),  
            contentDescription = "",  
            modifier = Modifier  
                .size(120.dp)  
                .align(Alignment.TopCenter)  
        )  

        Text(  
            text = if(state.currentValue == Position.Start) "던지세요" else "스트라이크",  
            style = MaterialTheme.typography.bodyLarge,  
            modifier = Modifier.align(Alignment.Center)  
        )  

        val safeOffset = if(state.offset.isNaN()) 0f else state.offset  
        Box(  
            modifier = Modifier  
                .align(Alignment.BottomCenter)  
                .offset {  
                    IntOffset(0, (safeOffset.roundToInt()))  
                }  
                .scale((componentSize.height - state.offset) / componentSize.height)  
        ){  
            Image(  
                painter = painterResource(id = R.drawable.baseball),  
                contentDescription = "",  
                modifier = Modifier  
                    .size(40.dp)  
                    .clip(CircleShape)  
                    .anchoredDraggable(  
                        state = state,  
                        orientation = Orientation.Vertical  
                    )  
                    .graphicsLayer {  
                        rotationZ = state.offset % 360  
                    }  
            )  
        }  

    }}  

enum class Position{  
    Start, End  
}

깃허브

https://github.com/Myeongcheol-shin/shooting-ball

 

GitHub - Myeongcheol-shin/shooting-ball: shooting ball animation with jetpack compose

shooting ball animation with jetpack compose. Contribute to Myeongcheol-shin/shooting-ball development by creating an account on GitHub.

github.com