This is the sixth day of my participation in Gwen Challenge

Welcome to follow my public account “ananzhuo”, learn more knowledge

Read a good book. – I said

The previous articles covered Canvas, Paint, and Path, which are commonly used in custom controls. In this article we go one step further on the basis of the previous several, drawing an underwater world effect.

Github address of the project

Github.com/ananananzhu…

Drawing process

Draw the background

SetShader: Draw the entire Canvas using the canvas. drawRect method. Paint sets a Shader as follows:

paintBack.shader = LinearGradient(
            measuredWidth / 3f,
            0f,
            measuredWidth * 2 / 3f,
            measuredHeight.toFloat(),
            Color.WHITE,
            Color.parseColor("#000055"),
            Shader.TileMode.CLAMP
        )
Copy the code
canvas.drawRect(background, paintBack)
Copy the code

It looks something like this

Draw a whale

Cough, whale this thing I found a picture in Baidu

After that, the most beautiful blue whale was pulled out with PS, and the tail of the blue whale was processed with PS liquefaction tool. The purpose is to make the tail of the blue whale swing constantly during the movement so as to achieve the effect of swimming

Code:
 private val bitmaps = listOf<Bitmap>(
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish1),
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish2),
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish3),
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish4),
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish3),
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish2),
        BitmapFactory.decodeResource(context.resources, R.drawable.bluefish1),
    )
Copy the code
 canvas.run {
            drawBitmap(bitmaps[bitmapIndex % bitmaps.size], 100f, 100f, paint)
            bitmapIndex++
            drawFishWithPath()
        }
Copy the code
Effect:

It’s not enough for the killer whale to swing its tail. We should also make it swim, and it’s best to follow our designated path

The core code that defines the path
fishPath.moveTo(100f, 100f) for (i in 0.. 20) { fishPath.apply { cubicTo(randowX(), randowY(), randowX(), randowY(), randowX(), randowY()) } } fishPath.close()Copy the code
Draw the path effect

There is a problem here, because there are a lot of sharp angles when the path turns, which can not be expected, and the baby killer whale will not swim in this way, right? This will be optimized later, the most important thing is to achieve the effect

Let the fish move along the path

This is where the PathMeasure tool comes in

dstPath.reset() var stop = start+100f pathMeasure.getSegment(start, stop, dstPath, true) val matrix = Matrix() pathMeasure.getMatrix(stop, matrix, (PathMeasure.POSITION_MATRIX_FLAG.or(PathMeasure.TANGENT_MATRIX_FLAG))) val bitmap = bitmaps[bitmapIndex % bitmaps.size]  matrix.preTranslate(-bitmap.width / 2f, -bitmap.height / 2f) canvas.drawBitmap(bitmap, matrix, paint)Copy the code

The code can intercept the path through the pathMeasure. GetSegment method to draw a whale picture at a certain position of the path. Because we can get the tangent value of a certain point of the path, our whale can always swim along the tangent line

Swimming effect:

Unfortunately, I forgot to record the screen in the middle and had to put up the final image

Draw the sun and bubbles

Now that we have the final effect, let’s go ahead and put in the sun and bubble code

Draw the sun

The main point of painting the sun is to paint the surrounding sunlight. When we draw sunlight, we divide the sun into 20 equal radians, and then triangle outward between the two equal points to achieve our sunshine effect.

Path.moveto (radius + sunX, sunY) val degree = 3.14f * 2 / leafNum for (I in 1.. LeafNum) {val x1 = radius * cos(I * degree) + sunX val y1 = radius * sin(I * degree) + sunY val halfDegree = (i-0.5) * degree val shineRadius = radius + Random.nextInt(50) val controllX = shineRadius * cos(halfDegree).toFloat() + sunX val controllY = shineRadius * sin(halfDegree).toFloat() + sunY path.lineTo(controllX, controllY) path.lineTo(x1, y1) } path.close()Copy the code
Draw air bubbles

We use RadiaGradient image gradient way to achieve bubble effect, to pay attention to the point is the image gradient color middle point do not choose in the center of the circle, otherwise it will be very ugly

paint.shader=RadialGradient(cycleX+40,cycleY-40,radius+300, Color.WHITE,Color.GREEN,Shader.TileMode.CLAMP)
        canvas.drawCircle(cycleX, cycleY, radius, paint)
Copy the code