PK creative Spring Festival, I am participating in the “Spring Festival creative submission contest”, please see: Spring Festival creative submission Contest

preface

When I was a child, I began to look forward to the winter vacation and the Spring Festival. Because the New Year has put endless firecrackers and eat endless candy, I still remember that time my pocket is always full of all kinds of candy. Today with candy as the theme, the realization of candy rain come this interactive game.

Results show

Start boot page Candy Collection page Collection End Page

Implementation details

The concrete implementation is actually very simple, mainly divided into three parts:

  1. Start boot page: Provides a start button to tell the user how to start and a 3 second countdown animation to get the user ready.
  2. Candy collection page: Automatically generates candy and drops it from the top, and the user clicks on the candy to complete the collection (candy disappears & total number of candy collections plus one).
  3. End of collection page: tells the user how many candies they have collected and provides a button entry to play again.

Boot animation

A static page with text to remind the user how to start the game would be a bit boring, so I added some custom View animations to simulate clicking actions to remind the user.

Three animations are combined together and executed at the same time to achieve the effect, respectively:

  1. Move your finger to click the animation.
  2. Click on the water ripple animation.
  3. Post click candy+ 1The animation.

Here we use the candy +1 animation after clicking.

Let’s create a res/anim/ candy_add_im.xml file as follows:


      
<set xmlns:android="http://schemas.android.com/apk/res/android">

    <alpha
        android:duration="3000"
        android:fromAlpha="0.0"
        android:repeatCount="1"
        android:repeatMode="restart"
        android:toAlpha="1.0" />

    <translate
        android:duration="3000"
        android:fromYDelta="0%"
        android:interpolator="@android:anim/accelerate_interpolator"
        android:repeatCount="1"
        android:repeatMode="restart"
        android:toYDelta="-10%p" />

    <scale
        android:duration="3000"
        android:fromXScale="0"
        android:fromYScale="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:repeatCount="1"
        android:repeatMode="restart"
        android:toXScale="1"
        android:toYScale="1" />

</set>
Copy the code

Then execute the animation in the specified View as follows:

binding.candyAddOneTv.apply {
    val animation = AnimationUtils.loadAnimation(context, R.anim.candy_add_anim)
    startAnimation(animation)
}
Copy the code

Candy making

As you can see from the effect display, the candy has a variety of styles and its position coordinates are random.

I dynamically generated a fixed size TextView from the code and set the coordinates to LayoutParams.setMargins and setBackground(drawable) to set the candy background. So I got some SVG images of candy as a background) and added them to view.root.

The specific code is as follows:

// Randomly generate X coordinates
val leftMargin = (0..(getScreenWidth() - 140)).random()
TextView(this).apply {
    layoutParams = FrameLayout.LayoutParams(140.140).apply {
        setMargins(leftMargin, -140.0.0)
    }
    background = ContextCompat.getDrawable(this@MainActivity, generateRandomCandy())
    binding.root.addView(this)}Copy the code

The coroutine delay(250) is used to generate 4 candies per second.

fun generatePointViewOnTime(a) {
    viewModelScope.launch {
        for (i in 1.60.) {
            Log.e(TAG, "generatePointViewOnTime: i = $i")
            pointViewLiveData.value = i
            if (i % 4= =0) {
                countDownTimeLiveData.postValue(i / 4)
            }
            delay(250)}}}Copy the code

Candy drops

After the introduction of candy generation, then is the realization of candy falling effect.

Here we also use the View animation to make the candy slide from the top to the bottom of the screen with the translationY(getScreenHeight().tofloat () + 200) and set the acceleration interpolator to make the candy drop faster and faster.

The entire translation time is set to 3s, and the specific code is as follows:

private fun startMoving(view: View) {
    view.apply {
        animate().apply {
            interpolator = AccelerateInterpolator()
            duration = 3000
            translationY(getScreenHeight().toFloat() + 200)
            start()
        }
    }
}
Copy the code

Candy collection

Click on the candy, the candy disappears, the total number of candy collected +1. So we just need to set the click listener for it, and when the user clicks, set visibility and catchNumber++ to the TextView.

TextView(this).apply {··· ·· setOnClickListener {this.visibility = View.GONE
        Log.e(TAG, "onCreate: tag = ${it.tag}, id = ${it.id}")
        catchNumber++
        binding.catchNumberTv.text = getString(R.string.catch_number, catchNumber)
        doVibratorEffect()
    }
}
Copy the code

Click on the feedback

For better user experience, set vibration feedback effect for click.

private fun doVibratorEffect(a) {
    val vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val vibratorManager =
            getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
        vibratorManager.defaultVibrator
    } else {
        getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        vibrator.vibrate(VibrationEffect.createOneShot(30, VibrationEffect.DEFAULT_AMPLITUDE))
    } else {
        vibrator.vibrate(30)}}Copy the code

End of pop-ups

When the candy collection is finished, an end popup window will pop up to tell the user the candy collection situation. Here, attribute animation is adopted to make the popup effect more vivid.

private fun showAnimation(view: View) {
    view.scaleX = 0F
    view.scaleY = 0F

    //zoom in; Zoom out C. Return to normal
    val zoomInHolderX = PropertyValuesHolder.ofFloat("scaleX".1.05 F)
    val zoomInHolderY = PropertyValuesHolder.ofFloat("scaleY".1.05 F)
    val zoomOutHolderX = PropertyValuesHolder.ofFloat("scaleX".0.8 F)
    val zoomOutHolderY = PropertyValuesHolder.ofFloat("scaleY".0.8 F)
    val normalHolderX = PropertyValuesHolder.ofFloat("scaleX".1F)
    val normalHolderY = PropertyValuesHolder.ofFloat("scaleY".1F)
    val zoomIn = ObjectAnimator.ofPropertyValuesHolder(
        view,
        zoomInHolderX,
        zoomInHolderY
    )

    val zoomOut = ObjectAnimator.ofPropertyValuesHolder(
        view,
        zoomOutHolderX,
        zoomOutHolderY
    )
    zoomOut.duration = 400

    val normal = ObjectAnimator.ofPropertyValuesHolder(
        view,
        normalHolderX,
        normalHolderY
    )
    normal.duration = 500

    val animatorSet = AnimatorSet()
    animatorSet.playSequentially(zoomIn, zoomOut, normal)
    animatorSet.start()
}
Copy the code

conclusion

If you are interested in learning more about the code, please refer to Github Candy-Catch. You are welcome to give me a star.

I believe many people have such feelings, with the increase of age, more and more feel that the flavor of the New Year is getting weaker and weaker, followed by the expectation of the New Year is also decreasing year by year. Here, I wish you all retained childlike innocence, return is still young!

Finally, I wish you all a happy New Year!

In fact, the biggest purpose of sharing articles is to wait for someone to point out my mistakes. If you find any mistakes, please point them out without reservation and consult with an open mind.

In addition, if you think this article is good and helpful, please give me a like as encouragement, thank you ~ Peace~!