/* * Copyright (C) 2017 The Android Open Source Project * * 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.android.egg.octo; import android.animation.TimeAnimator; import android.content.Context; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.DashPathEffect; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.animation.DynamicAnimation; import android.support.animation.SpringForce; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.animation.SpringAnimation; import android.support.animation.FloatValueHolder; public class OctopusDrawable extends Drawable { private static float BASE_SCALE = 100f; public static boolean PATH_DEBUG = false; private static int BODY_COLOR = 0xFF101010; private static int ARM_COLOR = 0xFF101010; private static int ARM_COLOR_BACK = 0xFF000000; private static int EYE_COLOR = 0xFF808080; private static int[] BACK_ARMS = {1, 3, 4, 6}; private static int[] FRONT_ARMS = {0, 2, 5, 7}; private Paint mPaint = new Paint(); private Arm[] mArms = new Arm[8]; final PointF point = new PointF(); private int mSizePx = 100; final Matrix M = new Matrix(); final Matrix M_inv = new Matrix(); private TimeAnimator mDriftAnimation; private boolean mBlinking; private float[] ptmp = new float[2]; private float[] scaledBounds = new float[2]; public static float randfrange(float a, float b) { return (float) (Math.random()*(b-a) + a); } public static float clamp(float v, float a, float b) { return vb?b:v; } public OctopusDrawable(Context context) { float dp = context.getResources().getDisplayMetrics().density; setSizePx((int) (100*dp)); mPaint.setAntiAlias(true); for (int i=0; i nextjump) { vy = JUMP_VY; nextjump = t + (long) randfrange(5000, 10000); } if (unblink > 0 && t > unblink) { setBlinking(false); unblink = 0; } else if (Math.random() < 0.001f) { setBlinking(true); unblink = t + 200; } ax = (float) (MAX_VX * Math.sin(t_sec*.25f)); vx = clamp(vx + dt_sec * ax, -MAX_VX, MAX_VX); vy = clamp(vy + dt_sec * ay, -100*MAX_VY, MAX_VY); // oob check if (point.y - BASE_SCALE/2 > scaledBounds[1]) { vy = JUMP_VY; } else if (point.y + BASE_SCALE < 0) { vy = MAX_VY; } point.x = clamp(point.x + dt_sec * vx, 0, scaledBounds[0]); point.y = point.y + dt_sec * vy; repositionArms(); } }); } mDriftAnimation.start(); } public void stopDrift() { mDriftAnimation.cancel(); } @Override public void onBoundsChange(Rect bounds) { final float w = bounds.width(); final float h = bounds.height(); lockArms(true); moveTo(w/2, h/2); lockArms(false); scaledBounds[0] = w; scaledBounds[1] = h; M_inv.mapPoints(scaledBounds); } // real pixel coordinates public void moveTo(float x, float y) { point.x = x; point.y = y; mapPointF(M_inv, point); repositionArms(); } public boolean hitTest(float x, float y) { ptmp[0] = x; ptmp[1] = y; M_inv.mapPoints(ptmp); return Math.hypot(ptmp[0] - point.x, ptmp[1] - point.y) < BASE_SCALE/2; } private void lockArms(boolean l) { for (Arm arm : mArms) { arm.setLocked(l); } } private void repositionArms() { for (int i=0; i