/* * Copyright (C) 2016 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.android.apps.santatracker.village; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; public class SnowFlake { private static Paint mPaint; private static float MAX_SIZE; private static final int VERTICAL_MULTIPLIER = 3; // Fall this much faster down than across private final float mAngleDelta = (float) (Math.random() / 100); // [0, 0.01) private float mX, mY, mRadius, mFlakeVelocity, mAngle; public SnowFlake(Resources resources, int height, int width) { // MAX_SIZE is the fraction of the shorter edge of the screen to use for a single flake if (MAX_SIZE == 0) { MAX_SIZE = Float.valueOf(resources.getString(R.string.maxSize)); } if (mPaint == null) { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.WHITE); // Intentionally no alpha as it didn't test well. mPaint.setStyle(Paint.Style.FILL_AND_STROKE); } setScreenDimensions(height, width); } public void setScreenDimensions(int height, int width) { // Choose the smaller of height/width for radius calculations int shortEdge = Math.min(width, height); mRadius = shortEdge * (float) Math.random() * MAX_SIZE; // Individual flake velocity is related to, but not tied to actual flake radius. mFlakeVelocity = shortEdge * (float) Math.random() * MAX_SIZE / VERTICAL_MULTIPLIER; mAngle = newAngle(); mX = newX(width); // Randomly position along x-axis mY = newY(height, mRadius, false); } // Initial falling angle [0, 2π) private static float newAngle() { return (float) (Math.random() * 2 * Math.PI); } // Randomly position along x-axis private static float newX(int width) { return width * (float) Math.random(); } // Place Y position. Deduct diameter to have it off screen. private static float newY(int height, float radius, boolean atTop) { return atTop ? -radius * 2 : height * (float) Math.random() - radius * 2; } public void onDraw(Canvas canvas, int height, int width) { mX += mFlakeVelocity * Math.cos(mAngle); // Make the snow vertically fall at VERTICAL_MULTIPLIER times the increment mY += mFlakeVelocity * VERTICAL_MULTIPLIER * Math.abs(Math.sin(mAngle)); mAngle += mAngleDelta; // If the flake went off screen, bring it back at the top. if (mY > height + mRadius * 2 || mX < -mRadius * 2 || mX > width + mRadius * 2) { mAngle = newAngle(); mX = newX(width); mY = newY(height, mRadius, true); // Move to the top of the screen, just out of view } canvas.drawCircle(mX, mY, mRadius, mPaint); } }