14455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler/*
28df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler * Copyright (C) 2015 The Android Open Source Project
34455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler *
44455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * Licensed under the Apache License, Version 2.0 (the "License");
54455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * you may not use this file except in compliance with the License.
64455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * You may obtain a copy of the License at
74455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler *
84455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler *      http://www.apache.org/licenses/LICENSE-2.0
94455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler *
104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * Unless required by applicable law or agreed to in writing, software
114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * distributed under the License is distributed on an "AS IS" BASIS,
124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * See the License for the specific language governing permissions and
144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler * limitations under the License.
154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler */
164455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerpackage com.android.systemui.egg;
184455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport android.animation.LayoutTransition;
204455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.animation.TimeAnimator;
214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.content.Context;
224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.content.res.Resources;
232200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Canvas;
242200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Color;
252200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Matrix;
262200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Outline;
272200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Paint;
282200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Path;
292200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.PorterDuff;
308df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport android.graphics.PorterDuffColorFilter;
312200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.graphics.Rect;
324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.graphics.drawable.Drawable;
334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.graphics.drawable.GradientDrawable;
34195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandlerimport android.media.AudioAttributes;
35195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandlerimport android.media.AudioManager;
36195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandlerimport android.os.Vibrator;
374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.util.AttributeSet;
384455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.util.Log;
392200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.view.Gravity;
408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport android.view.InputDevice;
412200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.view.KeyEvent;
428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport android.view.LayoutInflater;
432200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.view.MotionEvent;
442200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.view.View;
458df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport android.view.ViewGroup;
462200f86f800876d005f911e6864708fa9772d03aDan Sandlerimport android.view.ViewOutlineProvider;
474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.widget.FrameLayout;
484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.widget.ImageView;
494455da985d4bc8b3dce8ae35deaef41049d121daDan Sandlerimport android.widget.TextView;
504455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport com.android.internal.logging.MetricsLogger;
528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerimport com.android.systemui.R;
538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
54c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport java.util.ArrayList;
55c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson
568df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler// It's like LLand, but "M"ultiplayer.
578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandlerpublic class MLand extends FrameLayout {
588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final String TAG = "MLand";
594455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
604455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
612200f86f800876d005f911e6864708fa9772d03aDan Sandler    public static final boolean DEBUG_DRAW = false; // DEBUG
624455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final boolean SHOW_TOUCHES = true;
648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
65195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    public static void L(String s, Object ... objects) {
664455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (DEBUG) {
678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            Log.d(TAG, objects.length == 0 ? s : String.format(s, objects));
684455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
694455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
704455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final float PI_2 = (float) (Math.PI/2);
728df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
734455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final boolean AUTOSTART = true;
744455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final boolean HAVE_STARS = true;
754455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final float DEBUG_SPEED_MULTIPLIER = 0.5f; // only if DEBUG
77195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    public static final boolean DEBUG_IDDQD = Log.isLoggable(TAG + ".iddqd", Log.DEBUG);
784455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final int DEFAULT_PLAYERS = 1;
808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final int MIN_PLAYERS = 1;
818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static final int MAX_PLAYERS = 6;
828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    static final float CONTROLLER_VIBRATION_MULTIPLIER = 2f;
842200f86f800876d005f911e6864708fa9772d03aDan Sandler
854455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private static class Params {
864455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public float TRANSLATION_PER_SEC;
874455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int OBSTACLE_SPACING, OBSTACLE_PERIOD;
884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int BOOST_DV;
894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int PLAYER_HIT_SIZE;
904455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int PLAYER_SIZE;
912200f86f800876d005f911e6864708fa9772d03aDan Sandler        public int OBSTACLE_WIDTH, OBSTACLE_STEM_WIDTH;
924455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int OBSTACLE_GAP;
934455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int OBSTACLE_MIN;
944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int BUILDING_WIDTH_MIN, BUILDING_WIDTH_MAX;
954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int BUILDING_HEIGHT_MIN;
964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int CLOUD_SIZE_MIN, CLOUD_SIZE_MAX;
974455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int STAR_SIZE_MIN, STAR_SIZE_MAX;
984455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int G;
994455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int MAX_V;
1004455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            public float SCENERY_Z, OBSTACLE_Z, PLAYER_Z, PLAYER_Z_BOOST, HUD_Z;
1014455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Params(Resources res) {
1024455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            TRANSLATION_PER_SEC = res.getDimension(R.dimen.translation_per_sec);
1034455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            OBSTACLE_SPACING = res.getDimensionPixelSize(R.dimen.obstacle_spacing);
1044455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            OBSTACLE_PERIOD = (int) (OBSTACLE_SPACING / TRANSLATION_PER_SEC);
1054455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            BOOST_DV = res.getDimensionPixelSize(R.dimen.boost_dv);
1064455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            PLAYER_HIT_SIZE = res.getDimensionPixelSize(R.dimen.player_hit_size);
1074455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            PLAYER_SIZE = res.getDimensionPixelSize(R.dimen.player_size);
1084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            OBSTACLE_WIDTH = res.getDimensionPixelSize(R.dimen.obstacle_width);
1092200f86f800876d005f911e6864708fa9772d03aDan Sandler            OBSTACLE_STEM_WIDTH = res.getDimensionPixelSize(R.dimen.obstacle_stem_width);
1104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            OBSTACLE_GAP = res.getDimensionPixelSize(R.dimen.obstacle_gap);
1114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            OBSTACLE_MIN = res.getDimensionPixelSize(R.dimen.obstacle_height_min);
1124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            BUILDING_HEIGHT_MIN = res.getDimensionPixelSize(R.dimen.building_height_min);
1134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            BUILDING_WIDTH_MIN = res.getDimensionPixelSize(R.dimen.building_width_min);
1144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            BUILDING_WIDTH_MAX = res.getDimensionPixelSize(R.dimen.building_width_max);
1154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            CLOUD_SIZE_MIN = res.getDimensionPixelSize(R.dimen.cloud_size_min);
1164455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            CLOUD_SIZE_MAX = res.getDimensionPixelSize(R.dimen.cloud_size_max);
1174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            STAR_SIZE_MIN = res.getDimensionPixelSize(R.dimen.star_size_min);
1184455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            STAR_SIZE_MAX = res.getDimensionPixelSize(R.dimen.star_size_max);
1194455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1204455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            G = res.getDimensionPixelSize(R.dimen.G);
1214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            MAX_V = res.getDimensionPixelSize(R.dimen.max_v);
1224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            SCENERY_Z = res.getDimensionPixelSize(R.dimen.scenery_z);
1244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            OBSTACLE_Z = res.getDimensionPixelSize(R.dimen.obstacle_z);
1254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            PLAYER_Z = res.getDimensionPixelSize(R.dimen.player_z);
1264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            PLAYER_Z_BOOST = res.getDimensionPixelSize(R.dimen.player_z_boost);
1274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            HUD_Z = res.getDimensionPixelSize(R.dimen.hud_z);
128195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler
129195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            // Sanity checking
130195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            if (OBSTACLE_MIN <= OBSTACLE_WIDTH / 2) {
1318df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                L("error: obstacles might be too short, adjusting");
132195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler                OBSTACLE_MIN = OBSTACLE_WIDTH / 2 + 1;
133195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            }
1344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
1354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
1364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private TimeAnimator mAnim;
138195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    private Vibrator mVibrator;
139195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    private AudioManager mAudioManager;
140195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    private final AudioAttributes mAudioAttrs = new AudioAttributes.Builder()
141195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            .setUsage(AudioAttributes.USAGE_GAME).build();
1424455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1434455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private View mSplash;
1448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private ViewGroup mScoreFields;
1454455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private ArrayList<Player> mPlayers = new ArrayList<Player>();
1474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private ArrayList<Obstacle> mObstaclesInPlay = new ArrayList<Obstacle>();
1484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1494455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private float t, dt;
1504455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1514455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private float mLastPipeTime; // in sec
1528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private int mCurrentPipeId; // basically, equivalent to the current score
1534455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private int mWidth, mHeight;
1544455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private boolean mAnimating, mPlaying;
1554455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private boolean mFrozen; // after death, a short backoff
1568df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private int mCountdown = 0;
1572200f86f800876d005f911e6864708fa9772d03aDan Sandler    private boolean mFlipped;
1584455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private int mTaps;
1608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
1614455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private int mTimeOfDay;
1624455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private static final int DAY = 0, NIGHT = 1, TWILIGHT = 2, SUNSET = 3;
1634455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private static final int[][] SKIES = {
1644455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            { 0xFFc0c0FF, 0xFFa0a0FF }, // DAY
1654455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            { 0xFF000010, 0xFF000000 }, // NIGHT
1664455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            { 0xFF000040, 0xFF000010 }, // TWILIGHT
1672200f86f800876d005f911e6864708fa9772d03aDan Sandler            { 0xFFa08020, 0xFF204080 }, // SUNSET
1684455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    };
1694455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private int mScene;
1718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private static final int SCENE_CITY = 0, SCENE_TX = 1, SCENE_ZRH = 2;
1728df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private static final int SCENE_COUNT = 3;
1738df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
1744455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private static Params PARAMS;
1754455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private static float dp = 1f;
1778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
1788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private Paint mTouchPaint, mPlayerTracePaint;
1798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
1808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private ArrayList<Integer> mGameControllers = new ArrayList<>();
1818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
1828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public MLand(Context context) {
1834455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        this(context, null);
1844455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
1854455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1868df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public MLand(Context context, AttributeSet attrs) {
1874455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        this(context, attrs, 0);
1884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
1894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
1908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public MLand(Context context, AttributeSet attrs, int defStyle) {
1914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        super(context, attrs, defStyle);
1928df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
193195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
194195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
1954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        setFocusable(true);
1964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        PARAMS = new Params(getResources());
1978df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mTimeOfDay = irand(0, SKIES.length - 1);
1988df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mScene = irand(0, SCENE_COUNT);
1998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2008df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mTouchPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
2018df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mTouchPaint.setColor(0x80FFFFFF);
2028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mTouchPaint.setStyle(Paint.Style.FILL);
2038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2048df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mPlayerTracePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
2058df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mPlayerTracePaint.setColor(0x80FFFFFF);
2068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mPlayerTracePaint.setStyle(Paint.Style.STROKE);
2078df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mPlayerTracePaint.setStrokeWidth(2 * dp);
208f5ba6bdafa33720fa6ee692954ac9ab364fdedf5Dan Sandler
209f5ba6bdafa33720fa6ee692954ac9ab364fdedf5Dan Sandler        // we assume everything will be laid out left|top
210f5ba6bdafa33720fa6ee692954ac9ab364fdedf5Dan Sandler        setLayoutDirection(LAYOUT_DIRECTION_LTR);
2118df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        setupPlayers(DEFAULT_PLAYERS);
2138df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        MetricsLogger.count(getContext(), "egg_mland_create", 1);
2158df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
2168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2178df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    @Override
2188df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void onAttachedToWindow() {
2198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        super.onAttachedToWindow();
2208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        dp = getResources().getDisplayMetrics().density;
2218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2228df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        reset();
2238df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (AUTOSTART) {
2248df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            start(false);
2258df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
2264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
2274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
2284455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
2294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public boolean willNotDraw() {
2304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return !DEBUG;
2314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
2324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
2334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public int getGameWidth() { return mWidth; }
2344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public int getGameHeight() { return mHeight; }
2354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public float getGameTime() { return t; }
2364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public float getLastTimeStep() { return dt; }
2374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
2388df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void setScoreFieldHolder(ViewGroup vg) {
2398df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mScoreFields = vg;
2408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (vg != null) {
2418df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final LayoutTransition lt = new LayoutTransition();
2428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            lt.setDuration(250);
2438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScoreFields.setLayoutTransition(lt);
2448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
2458df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (Player p : mPlayers) {
2468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScoreFields.addView(p.mScoreField,
2478df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    new MarginLayoutParams(
2488df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            MarginLayoutParams.WRAP_CONTENT,
2498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            MarginLayoutParams.MATCH_PARENT));
2504455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
2514455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
2524455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
2534455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public void setSplash(View v) {
2544455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        mSplash = v;
2554455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
2564455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
2578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static boolean isGamePad(InputDevice dev) {
2588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        int sources = dev.getSources();
2598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        // Verify that the device has gamepad buttons, control sticks, or both.
2618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
2628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK));
2638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
2648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public ArrayList getGameControllers() {
2668df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mGameControllers.clear();
2678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        int[] deviceIds = InputDevice.getDeviceIds();
2688df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (int deviceId : deviceIds) {
2698df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            InputDevice dev = InputDevice.getDevice(deviceId);
2708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (isGamePad(dev)) {
2718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (!mGameControllers.contains(deviceId)) {
2728df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mGameControllers.add(deviceId);
2738df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
2748df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
2758df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
2768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return mGameControllers;
2778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
2788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public int getControllerPlayer(int id) {
2808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final int player = mGameControllers.indexOf(id);
2818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (player < 0 || player >= mPlayers.size()) return 0;
2828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return player;
2838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
2848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2854455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
2864455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
2878df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        dp = getResources().getDisplayMetrics().density;
2888df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        stop();
2908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        reset();
2924455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (AUTOSTART) {
2934455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            start(false);
2944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
2954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
2964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
2978df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    final static float hsv[] = {0, 0, 0};
2988df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
2998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private static float luma(int bgcolor) {
3008df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return    0.2126f * (float) (bgcolor & 0xFF0000) / 0xFF0000
3018df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                + 0.7152f * (float) (bgcolor & 0xFF00) / 0xFF00
3028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                + 0.0722f * (float) (bgcolor & 0xFF) / 0xFF;
3038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3048df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3058df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public Player getPlayer(int i) {
3068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return i < mPlayers.size() ? mPlayers.get(i) : null;
3078df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3088df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3098df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private int addPlayerInternal(Player p) {
3108df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mPlayers.add(p);
3118df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        realignPlayers();
3128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        TextView scoreField = (TextView)
3138df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            LayoutInflater.from(getContext()).inflate(R.layout.mland_scorefield, null);
3148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mScoreFields != null) {
3158df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScoreFields.addView(scoreField,
3168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                new MarginLayoutParams(
3178df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        MarginLayoutParams.WRAP_CONTENT,
3188df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        MarginLayoutParams.MATCH_PARENT));
3198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
3208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        p.setScoreField(scoreField);
3218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return mPlayers.size()-1;
3228df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3238df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3248df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void removePlayerInternal(Player p) {
3258df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mPlayers.remove(p)) {
3268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            removeView(p);
3278df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScoreFields.removeView(p.mScoreField);
3288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            realignPlayers();
3298df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
3308df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3318df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3328df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void realignPlayers() {
3338df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final int N = mPlayers.size();
3348df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        float x = (mWidth - (N-1) * PARAMS.PLAYER_SIZE) / 2;
3358df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (int i=0; i<N; i++) {
3368df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final Player p = mPlayers.get(i);
3378df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.setX(x);
3388df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            x += PARAMS.PLAYER_SIZE;
3398df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
3408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3418df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void clearPlayers() {
3438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        while (mPlayers.size() > 0) {
3448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            removePlayerInternal(mPlayers.get(0));
3458df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
3468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3478df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3488df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void setupPlayers(int num) {
3498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        clearPlayers();
3508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (int i=0; i<num; i++) {
3518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            addPlayerInternal(Player.create(this));
3528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
3538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3548df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3558df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void addPlayer() {
3568df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (getNumPlayers() == MAX_PLAYERS) return;
3578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        addPlayerInternal(Player.create(this));
3588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public int getNumPlayers() {
3618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return mPlayers.size();
3628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
3648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void removePlayer() {
3658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (getNumPlayers() == MIN_PLAYERS) return;
3668df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        removePlayerInternal(mPlayers.get(mPlayers.size() - 1));
3678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
3684455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
3698df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void thump(int playerIndex, long ms) {
370195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        if (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
371195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            // No interruptions. Not even game haptics.
372195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            return;
373195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        }
3748df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (playerIndex < mGameControllers.size()) {
3758df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            int controllerId = mGameControllers.get(playerIndex);
3768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            InputDevice dev = InputDevice.getDevice(controllerId);
3778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (dev != null && dev.getVibrator().hasVibrator()) {
3788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                dev.getVibrator().vibrate(
3798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        (long) (ms * CONTROLLER_VIBRATION_MULTIPLIER),
3808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        mAudioAttrs);
3818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                return;
3828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
3838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
3848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mVibrator.vibrate(ms, mAudioAttrs);
385195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    }
386195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler
387195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    public void reset() {
3884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        L("reset");
3894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final Drawable sky = new GradientDrawable(
3904455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                GradientDrawable.Orientation.BOTTOM_TOP,
3914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                SKIES[mTimeOfDay]
3924455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        );
3934455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        sky.setDither(true);
3944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        setBackground(sky);
3954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
3962200f86f800876d005f911e6864708fa9772d03aDan Sandler        mFlipped = frand() > 0.5f;
3972200f86f800876d005f911e6864708fa9772d03aDan Sandler        setScaleX(mFlipped ? -1 : 1);
3984455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
3994455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        int i = getChildCount();
4004455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        while (i-->0) {
4014455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final View v = getChildAt(i);
4024455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (v instanceof GameView) {
4034455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                removeViewAt(i);
4044455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
4054455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
4064455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4074455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        mObstaclesInPlay.clear();
4088df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mCurrentPipeId = 0;
4094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        mWidth = getWidth();
4114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        mHeight = getHeight();
4124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        boolean showingSun = (mTimeOfDay == DAY || mTimeOfDay == SUNSET) && frand() > 0.25;
4144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (showingSun) {
4154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final Star sun = new Star(getContext());
4164455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            sun.setBackgroundResource(R.drawable.sun);
4174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
4184455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            sun.setTranslationX(frand(w, mWidth-w));
4194455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (mTimeOfDay == DAY) {
4204455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                sun.setTranslationY(frand(w, (mHeight * 0.66f)));
4214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                sun.getBackground().setTint(0);
4224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            } else {
4234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                sun.setTranslationY(frand(mHeight * 0.66f, mHeight - w));
4244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                sun.getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
4254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                sun.getBackground().setTint(0xC0FF8000);
4264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
4284455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            addView(sun, new LayoutParams(w, w));
4294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
4304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (!showingSun) {
4314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final boolean dark = mTimeOfDay == NIGHT || mTimeOfDay == TWILIGHT;
4324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final float ff = frand();
4334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if ((dark && ff < 0.75f) || ff < 0.5f) {
4344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final Star moon = new Star(getContext());
4354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                moon.setBackgroundResource(R.drawable.moon);
4364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                moon.getBackground().setAlpha(dark ? 255 : 128);
4374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                moon.setScaleX(frand() > 0.5 ? -1 : 1);
4384455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                moon.setRotation(moon.getScaleX() * frand(5, 30));
4394455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
4404455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                moon.setTranslationX(frand(w, mWidth - w));
4414455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                moon.setTranslationY(frand(w, mHeight - w));
4424455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                addView(moon, new LayoutParams(w, w));
4434455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
4444455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
4454455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4464455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final int mh = mHeight / 6;
4474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final boolean cloudless = frand() < 0.25;
4484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final int N = 20;
4494455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        for (i=0; i<N; i++) {
4504455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final float r1 = frand();
4514455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final Scenery s;
4524455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (HAVE_STARS && r1 < 0.3 && mTimeOfDay != DAY) {
4534455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                s = new Star(getContext());
4544455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            } else if (r1 < 0.6 && !cloudless) {
4554455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                s = new Cloud(getContext());
4564455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            } else {
4578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                switch (mScene) {
4588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    case SCENE_ZRH:
4598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        s = new Mountain(getContext());
4608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        break;
4618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    case SCENE_TX:
4628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        s = new Cactus(getContext());
4638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        break;
4648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    case SCENE_CITY:
4658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    default:
4668df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        s = new Building(getContext());
4678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        break;
4688df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
4698df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                s.z = (float) i / N;
4708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                // no more shadows for these things
4718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //s.setTranslationZ(PARAMS.SCENERY_Z * (1+s.z));
4724455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                s.v = 0.85f * s.z; // buildings move proportional to their distance
4738df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (mScene == SCENE_CITY) {
4748df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    s.setBackgroundColor(Color.GRAY);
4758df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    s.h = irand(PARAMS.BUILDING_HEIGHT_MIN, mh);
4768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
4778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final int c = (int)(255f*s.z);
4788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final Drawable bg = s.getBackground();
4798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (bg != null) bg.setColorFilter(Color.rgb(c,c,c), PorterDuff.Mode.MULTIPLY);
4804455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
4814455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final LayoutParams lp = new LayoutParams(s.w, s.h);
4824455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (s instanceof Building) {
4834455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                lp.gravity = Gravity.BOTTOM;
4844455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            } else {
4854455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                lp.gravity = Gravity.TOP;
4864455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final float r = frand();
4874455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                if (s instanceof Star) {
4884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    lp.topMargin = (int) (r * r * mHeight);
4894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                } else {
4904455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    lp.topMargin = (int) (1 - r*r * mHeight/2) + mHeight/2;
4914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                }
4924455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
4934455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4948df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
4954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            addView(s, lp);
4964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            s.setTranslationX(frand(-lp.width, mWidth + lp.width));
4974455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
4984455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
4998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (Player p : mPlayers) {
5008df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            addView(p); // put it back!
5018df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.reset();
5028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
5038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5048df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        realignPlayers();
5052200f86f800876d005f911e6864708fa9772d03aDan Sandler
5068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mAnim != null) {
5078df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mAnim.cancel();
5088df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
5094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        mAnim = new TimeAnimator();
5104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        mAnim.setTimeListener(new TimeAnimator.TimeListener() {
5114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            @Override
5124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
5134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                step(t, dt);
5144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
5154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        });
5164455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
5174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
518195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    public void start(boolean startPlaying) {
5198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        L("start(startPlaying=%s)", startPlaying ? "true" : "false");
5208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (startPlaying && mCountdown <= 0) {
5218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            showSplash();
5224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
5238df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.findViewById(R.id.play_button).setEnabled(false);
5244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
5258df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final View playImage = mSplash.findViewById(R.id.play_button_image);
5268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final TextView playText = (TextView) mSplash.findViewById(R.id.play_button_text);
5274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
5288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            playImage.animate().alpha(0f);
5298df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            playText.animate().alpha(1f);
5304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
5318df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mCountdown = 3;
5328df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            post(new Runnable() {
5338df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                @Override
5348df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                public void run() {
5358df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    if (mCountdown == 0) {
5368df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        startPlaying();
5378df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    } else {
5388df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        postDelayed(this, 500);
5398df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    }
5408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    playText.setText(String.valueOf(mCountdown));
5418df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mCountdown--;
5428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
5438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            });
5448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
5458df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (Player p : mPlayers) {
5478df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.setVisibility(View.INVISIBLE);
5484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
5498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5504455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (!mAnimating) {
5514455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mAnim.start();
5524455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mAnimating = true;
5534455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
5544455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
5554455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
5568df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void hideSplash() {
5578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mSplash != null && mSplash.getVisibility() == View.VISIBLE) {
5588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.setClickable(false);
5598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.animate().alpha(0).translationZ(0).setDuration(300).withEndAction(
5608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    new Runnable() {
5618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        @Override
5628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        public void run() {
5638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            mSplash.setVisibility(View.GONE);
5648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        }
5658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    }
5668df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            );
5678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
5688df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
5698df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void showSplash() {
5718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mSplash != null && mSplash.getVisibility() != View.VISIBLE) {
5728df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.setClickable(true);
5738df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.setAlpha(0f);
5748df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.setVisibility(View.VISIBLE);
5758df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.animate().alpha(1f).setDuration(1000);
5768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.findViewById(R.id.play_button_image).setAlpha(1f);
5778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.findViewById(R.id.play_button_text).setAlpha(0f);
5788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.findViewById(R.id.play_button).setEnabled(true);
5798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mSplash.findViewById(R.id.play_button).requestFocus();
5808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
5818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
5828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public void startPlaying() {
5848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mPlaying = true;
5858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5868df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        t = 0;
5878df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        // there's a sucker born every OBSTACLE_PERIOD
5888df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mLastPipeTime = getGameTime() - PARAMS.OBSTACLE_PERIOD;
5898df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        hideSplash();
5918df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5928df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        realignPlayers();
5938df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        mTaps = 0;
5948df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
5958df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final int N = mPlayers.size();
5968df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        MetricsLogger.histogram(getContext(), "egg_mland_players", N);
5978df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (int i=0; i<N; i++) {
5988df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final Player p = mPlayers.get(i);
5998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.setVisibility(View.VISIBLE);
6008df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.reset();
6018df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.start();
6028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.boost(-1, -1); // start you off flying!
6038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.unboost(); // not forever, though
6048df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
6058df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
6068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
607195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler    public void stop() {
6084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (mAnimating) {
6094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mAnim.cancel();
6104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mAnim = null;
6114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mAnimating = false;
6128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mPlaying = false;
6138df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mTimeOfDay = irand(0, SKIES.length - 1); // for next reset
6148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScene = irand(0, SCENE_COUNT);
6154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mFrozen = true;
6168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            for (Player p : mPlayers) {
6178df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                p.die();
6188df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
6194455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            postDelayed(new Runnable() {
6204455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    @Override
6214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    public void run() {
6224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                        mFrozen = false;
6234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    }
6244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                }, 250);
6254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
6264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6284455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final float lerp(float x, float a, float b) {
6294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return (b - a) * x + a;
6304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final float rlerp(float v, float a, float b) {
6334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return (v - a) / (b - a);
6344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final float clamp(float f) {
6374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return f < 0f ? 0f : f > 1f ? 1f : f;
6384455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6394455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6404455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final float frand() {
6414455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return (float) Math.random();
6424455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6434455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6444455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final float frand(float a, float b) {
6454455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return lerp(frand(), a, b);
6464455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public static final int irand(int a, int b) {
6498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return Math.round(frand((float) a, (float) b));
6508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
6518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
6528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    public static int pick(int[] l) {
6538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        return l[irand(0, l.length-1)];
6544455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
6554455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6564455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private void step(long t_ms, long dt_ms) {
6574455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        t = t_ms / 1000f; // seconds
6584455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        dt = dt_ms / 1000f;
6594455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6604455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (DEBUG) {
6614455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            t *= DEBUG_SPEED_MULTIPLIER;
6624455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            dt *= DEBUG_SPEED_MULTIPLIER;
6634455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
6644455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6654455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        // 1. Move all objects and update bounds
6664455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final int N = getChildCount();
6674455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        int i = 0;
6684455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        for (; i<N; i++) {
6694455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final View v = getChildAt(i);
6704455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (v instanceof GameView) {
6714455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                ((GameView) v).step(t_ms, dt_ms, t, dt);
6724455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
6734455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
6744455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
6758df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mPlaying) {
6768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            int livingPlayers = 0;
6778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            for (i = 0; i < mPlayers.size(); i++) {
6788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final Player p = getPlayer(i);
6798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
6808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (p.mAlive) {
6818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    // 2. Check for altitude
6828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    if (p.below(mHeight)) {
6838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        if (DEBUG_IDDQD) {
6848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            poke(i);
6858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            unpoke(i);
6868df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        } else {
6878df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            L("player %d hit the floor", i);
6888df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            thump(i, 80);
6898df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            p.die();
6908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        }
6918df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    }
6928df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
6938df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    // 3. Check for obstacles
6948df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    int maxPassedStem = 0;
6958df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    for (int j = mObstaclesInPlay.size(); j-- > 0; ) {
6968df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        final Obstacle ob = mObstaclesInPlay.get(j);
6978df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        if (ob.intersects(p) && !DEBUG_IDDQD) {
6988df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            L("player hit an obstacle");
6998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            thump(i, 80);
7008df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            p.die();
7018df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        } else if (ob.cleared(p)) {
7028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            if (ob instanceof Stem) {
7038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                                maxPassedStem = Math.max(maxPassedStem, ((Stem)ob).id);
7048df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                            }
7058df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        }
7068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    }
7078df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
7088df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    if (maxPassedStem > p.mScore) {
7098df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        p.addScore(1);
7108df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    }
7118df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
7128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
7138df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (p.mAlive) livingPlayers++;
7144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
7154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
7168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (livingPlayers == 0) {
7174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                stop();
7184455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
7198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                MetricsLogger.count(getContext(), "egg_mland_taps", mTaps);
7208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mTaps = 0;
7218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final int playerCount = mPlayers.size();
7228df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                for (int pi=0; pi<playerCount; pi++) {
7238df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    final Player p = mPlayers.get(pi);
7248df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    MetricsLogger.histogram(getContext(), "egg_mland_score", p.getScore());
7258df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
7268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
7274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
7284455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
7294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        // 4. Handle edge of screen
7304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        // Walk backwards to make sure removal is safe
7314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        while (i-->0) {
7324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final View v = getChildAt(i);
7334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (v instanceof Obstacle) {
7344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                if (v.getTranslationX() + v.getWidth() < 0) {
7354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    removeViewAt(i);
7368df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mObstaclesInPlay.remove(v);
7374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                }
7384455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            } else if (v instanceof Scenery) {
7394455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final Scenery s = (Scenery) v;
7404455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                if (v.getTranslationX() + s.w < 0) {
7414455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    v.setTranslationX(getWidth());
7424455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                }
7434455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
7444455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
7454455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
7464455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        // 3. Time for more obstacles!
7474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (mPlaying && (t - mLastPipeTime) > PARAMS.OBSTACLE_PERIOD) {
7484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mLastPipeTime = t;
7498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mCurrentPipeId ++;
750195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler            final int obstacley =
751195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler                    (int)(frand() * (mHeight - 2*PARAMS.OBSTACLE_MIN - PARAMS.OBSTACLE_GAP)) +
752195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler                    PARAMS.OBSTACLE_MIN;
7534455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
7542200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int inset = (PARAMS.OBSTACLE_WIDTH - PARAMS.OBSTACLE_STEM_WIDTH) / 2;
7552200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int yinset = PARAMS.OBSTACLE_WIDTH/2;
7562200f86f800876d005f911e6864708fa9772d03aDan Sandler
7572200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int d1 = irand(0,250);
7582200f86f800876d005f911e6864708fa9772d03aDan Sandler            final Obstacle s1 = new Stem(getContext(), obstacley - yinset, false);
7592200f86f800876d005f911e6864708fa9772d03aDan Sandler            addView(s1, new LayoutParams(
7602200f86f800876d005f911e6864708fa9772d03aDan Sandler                    PARAMS.OBSTACLE_STEM_WIDTH,
7612200f86f800876d005f911e6864708fa9772d03aDan Sandler                    (int) s1.h,
7622200f86f800876d005f911e6864708fa9772d03aDan Sandler                    Gravity.TOP|Gravity.LEFT));
7632200f86f800876d005f911e6864708fa9772d03aDan Sandler            s1.setTranslationX(mWidth+inset);
7642200f86f800876d005f911e6864708fa9772d03aDan Sandler            s1.setTranslationY(-s1.h-yinset);
7652200f86f800876d005f911e6864708fa9772d03aDan Sandler            s1.setTranslationZ(PARAMS.OBSTACLE_Z*0.75f);
7662200f86f800876d005f911e6864708fa9772d03aDan Sandler            s1.animate()
7672200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .translationY(0)
7682200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setStartDelay(d1)
7692200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setDuration(250);
7702200f86f800876d005f911e6864708fa9772d03aDan Sandler            mObstaclesInPlay.add(s1);
7712200f86f800876d005f911e6864708fa9772d03aDan Sandler
7722200f86f800876d005f911e6864708fa9772d03aDan Sandler            final Obstacle p1 = new Pop(getContext(), PARAMS.OBSTACLE_WIDTH);
7734455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            addView(p1, new LayoutParams(
7744455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    PARAMS.OBSTACLE_WIDTH,
7752200f86f800876d005f911e6864708fa9772d03aDan Sandler                    PARAMS.OBSTACLE_WIDTH,
7764455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    Gravity.TOP|Gravity.LEFT));
7774455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            p1.setTranslationX(mWidth);
7782200f86f800876d005f911e6864708fa9772d03aDan Sandler            p1.setTranslationY(-PARAMS.OBSTACLE_WIDTH);
7792200f86f800876d005f911e6864708fa9772d03aDan Sandler            p1.setTranslationZ(PARAMS.OBSTACLE_Z);
7802200f86f800876d005f911e6864708fa9772d03aDan Sandler            p1.setScaleX(0.25f);
7818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p1.setScaleY(-0.25f);
7824455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            p1.animate()
7832200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .translationY(s1.h-inset)
7842200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleX(1f)
7858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    .scaleY(-1f)
7862200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setStartDelay(d1)
7874455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    .setDuration(250);
7884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mObstaclesInPlay.add(p1);
7894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
7902200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int d2 = irand(0,250);
7912200f86f800876d005f911e6864708fa9772d03aDan Sandler            final Obstacle s2 = new Stem(getContext(),
7922200f86f800876d005f911e6864708fa9772d03aDan Sandler                    mHeight - obstacley - PARAMS.OBSTACLE_GAP - yinset,
7932200f86f800876d005f911e6864708fa9772d03aDan Sandler                    true);
7942200f86f800876d005f911e6864708fa9772d03aDan Sandler            addView(s2, new LayoutParams(
7952200f86f800876d005f911e6864708fa9772d03aDan Sandler                    PARAMS.OBSTACLE_STEM_WIDTH,
7962200f86f800876d005f911e6864708fa9772d03aDan Sandler                    (int) s2.h,
7972200f86f800876d005f911e6864708fa9772d03aDan Sandler                    Gravity.TOP|Gravity.LEFT));
7982200f86f800876d005f911e6864708fa9772d03aDan Sandler            s2.setTranslationX(mWidth+inset);
7992200f86f800876d005f911e6864708fa9772d03aDan Sandler            s2.setTranslationY(mHeight+yinset);
8002200f86f800876d005f911e6864708fa9772d03aDan Sandler            s2.setTranslationZ(PARAMS.OBSTACLE_Z*0.75f);
8012200f86f800876d005f911e6864708fa9772d03aDan Sandler            s2.animate()
8022200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .translationY(mHeight-s2.h)
8032200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setStartDelay(d2)
8042200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setDuration(400);
8052200f86f800876d005f911e6864708fa9772d03aDan Sandler            mObstaclesInPlay.add(s2);
8062200f86f800876d005f911e6864708fa9772d03aDan Sandler
8072200f86f800876d005f911e6864708fa9772d03aDan Sandler            final Obstacle p2 = new Pop(getContext(), PARAMS.OBSTACLE_WIDTH);
8084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            addView(p2, new LayoutParams(
8094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    PARAMS.OBSTACLE_WIDTH,
8102200f86f800876d005f911e6864708fa9772d03aDan Sandler                    PARAMS.OBSTACLE_WIDTH,
8114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    Gravity.TOP|Gravity.LEFT));
8124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            p2.setTranslationX(mWidth);
8134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            p2.setTranslationY(mHeight);
8142200f86f800876d005f911e6864708fa9772d03aDan Sandler            p2.setTranslationZ(PARAMS.OBSTACLE_Z);
8152200f86f800876d005f911e6864708fa9772d03aDan Sandler            p2.setScaleX(0.25f);
8162200f86f800876d005f911e6864708fa9772d03aDan Sandler            p2.setScaleY(0.25f);
8174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            p2.animate()
8182200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .translationY(mHeight-s2.h-yinset)
8192200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleX(1f)
8202200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleY(1f)
8212200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setStartDelay(d2)
8224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    .setDuration(400);
8234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            mObstaclesInPlay.add(p2);
8244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
8254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
8268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (SHOW_TOUCHES || DEBUG_DRAW) invalidate();
8274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
8288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
8294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
8304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public boolean onTouchEvent(MotionEvent ev) {
831195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        L("touch: %s", ev);
8328df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final int actionIndex = ev.getActionIndex();
8338df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final float x = ev.getX(actionIndex);
8348df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final float y = ev.getY(actionIndex);
8358df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        int playerIndex = (int) (getNumPlayers() * (x / getWidth()));
8368df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mFlipped) playerIndex = getNumPlayers() - 1 - playerIndex;
8378df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        switch (ev.getActionMasked()) {
8382200f86f800876d005f911e6864708fa9772d03aDan Sandler            case MotionEvent.ACTION_DOWN:
8398df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            case MotionEvent.ACTION_POINTER_DOWN:
8408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                poke(playerIndex, x, y);
8412200f86f800876d005f911e6864708fa9772d03aDan Sandler                return true;
8422200f86f800876d005f911e6864708fa9772d03aDan Sandler            case MotionEvent.ACTION_UP:
8438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            case MotionEvent.ACTION_POINTER_UP:
8448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                unpoke(playerIndex);
8452200f86f800876d005f911e6864708fa9772d03aDan Sandler                return true;
8464455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
8474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return false;
8484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
8494455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
8504455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
8514455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public boolean onTrackballEvent(MotionEvent ev) {
852195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        L("trackball: %s", ev);
8532200f86f800876d005f911e6864708fa9772d03aDan Sandler        switch (ev.getAction()) {
8542200f86f800876d005f911e6864708fa9772d03aDan Sandler            case MotionEvent.ACTION_DOWN:
8558df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                poke(0);
8562200f86f800876d005f911e6864708fa9772d03aDan Sandler                return true;
8572200f86f800876d005f911e6864708fa9772d03aDan Sandler            case MotionEvent.ACTION_UP:
8588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                unpoke(0);
8592200f86f800876d005f911e6864708fa9772d03aDan Sandler                return true;
8604455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
8614455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return false;
8624455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
8634455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
8644455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
8654455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public boolean onKeyDown(int keyCode, KeyEvent ev) {
866195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        L("keyDown: %d", keyCode);
8674455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        switch (keyCode) {
8684455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            case KeyEvent.KEYCODE_DPAD_CENTER:
8694455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            case KeyEvent.KEYCODE_DPAD_UP:
8704455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            case KeyEvent.KEYCODE_SPACE:
8714455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            case KeyEvent.KEYCODE_ENTER:
8724455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            case KeyEvent.KEYCODE_BUTTON_A:
8738df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                int player = getControllerPlayer(ev.getDeviceId());
8748df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                poke(player);
8754455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                return true;
8764455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
8774455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return false;
8784455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
8794455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
8804455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
8812200f86f800876d005f911e6864708fa9772d03aDan Sandler    public boolean onKeyUp(int keyCode, KeyEvent ev) {
882195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        L("keyDown: %d", keyCode);
8832200f86f800876d005f911e6864708fa9772d03aDan Sandler        switch (keyCode) {
8842200f86f800876d005f911e6864708fa9772d03aDan Sandler            case KeyEvent.KEYCODE_DPAD_CENTER:
8852200f86f800876d005f911e6864708fa9772d03aDan Sandler            case KeyEvent.KEYCODE_DPAD_UP:
8862200f86f800876d005f911e6864708fa9772d03aDan Sandler            case KeyEvent.KEYCODE_SPACE:
8872200f86f800876d005f911e6864708fa9772d03aDan Sandler            case KeyEvent.KEYCODE_ENTER:
8882200f86f800876d005f911e6864708fa9772d03aDan Sandler            case KeyEvent.KEYCODE_BUTTON_A:
8898df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                int player = getControllerPlayer(ev.getDeviceId());
8908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                unpoke(player);
8912200f86f800876d005f911e6864708fa9772d03aDan Sandler                return true;
8922200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
8932200f86f800876d005f911e6864708fa9772d03aDan Sandler        return false;
8942200f86f800876d005f911e6864708fa9772d03aDan Sandler    }
8952200f86f800876d005f911e6864708fa9772d03aDan Sandler
8962200f86f800876d005f911e6864708fa9772d03aDan Sandler    @Override
8974455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public boolean onGenericMotionEvent (MotionEvent ev) {
898195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        L("generic: %s", ev);
8994455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        return false;
9004455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
9014455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
9028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void poke(int playerIndex) {
9038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        poke(playerIndex, -1, -1);
9048df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
9058df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
9068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void poke(int playerIndex, float x, float y) {
9078df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        L("poke(%d)", playerIndex);
9084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (mFrozen) return;
9094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (!mAnimating) {
9104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            reset();
9114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
9128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (!mPlaying) {
9138df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            start(true);
9148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        } else {
9158df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final Player p = getPlayer(playerIndex);
9168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (p == null) return; // no player for this controller
9178df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.boost(x, y);
9188df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mTaps++;
9198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (DEBUG) {
9208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                p.dv *= DEBUG_SPEED_MULTIPLIER;
9218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                p.animate().setDuration((long) (200 / DEBUG_SPEED_MULTIPLIER));
9228df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
9234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
9244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
9254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
9268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private void unpoke(int playerIndex) {
9278df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        L("unboost(%d)", playerIndex);
9288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (mFrozen || !mAnimating || !mPlaying) return;
9298df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        final Player p = getPlayer(playerIndex);
9308df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (p == null) return; // no player for this controller
9318df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        p.unboost();
9322200f86f800876d005f911e6864708fa9772d03aDan Sandler    }
9332200f86f800876d005f911e6864708fa9772d03aDan Sandler
9344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    @Override
9354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    public void onDraw(Canvas c) {
9364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        super.onDraw(c);
9374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
9388df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        if (SHOW_TOUCHES) {
9398df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            for (Player p : mPlayers) {
9408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (p.mTouchX > 0) {
9418df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mTouchPaint.setColor(0x80FFFFFF & p.color);
9428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mPlayerTracePaint.setColor(0x80FFFFFF & p.color);
9438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    float x1 = p.mTouchX;
9448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    float y1 = p.mTouchY;
9458df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    c.drawCircle(x1, y1, 100, mTouchPaint);
9468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    float x2 = p.getX() + p.getPivotX();
9478df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    float y2 = p.getY() + p.getPivotY();
9488df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    float angle = PI_2 - (float) Math.atan2(x2-x1, y2-y1);
9498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    x1 += 100*Math.cos(angle);
9508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    y1 += 100*Math.sin(angle);
9518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    c.drawLine(x1, y1, x2, y2, mPlayerTracePaint);
9528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
9538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
9548df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
9558df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
9564455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        if (!DEBUG_DRAW) return;
9574455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
9584455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final Paint pt = new Paint();
9594455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        pt.setColor(0xFFFFFFFF);
9608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        for (Player p : mPlayers) {
9618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final int L = p.corners.length;
9628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final int N = L / 2;
9638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            for (int i = 0; i < N; i++) {
9648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final int x = (int) p.corners[i * 2];
9658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final int y = (int) p.corners[i * 2 + 1];
9668df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                c.drawCircle(x, y, 4, pt);
9678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                c.drawLine(x, y,
9688df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        p.corners[(i * 2 + 2) % L],
9698df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        p.corners[(i * 2 + 3) % L],
9708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                        pt);
9718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
9724455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
9734455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
9742200f86f800876d005f911e6864708fa9772d03aDan Sandler        pt.setStyle(Paint.Style.STROKE);
9752200f86f800876d005f911e6864708fa9772d03aDan Sandler        pt.setStrokeWidth(getResources().getDisplayMetrics().density);
9762200f86f800876d005f911e6864708fa9772d03aDan Sandler
9774455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final int M = getChildCount();
9782200f86f800876d005f911e6864708fa9772d03aDan Sandler        pt.setColor(0x8000FF00);
9794455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        for (int i=0; i<M; i++) {
9804455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final View v = getChildAt(i);
9818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (v instanceof Player) continue;
9824455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (!(v instanceof GameView)) continue;
9832200f86f800876d005f911e6864708fa9772d03aDan Sandler            if (v instanceof Pop) {
9848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                final Pop pop = (Pop) v;
9858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                c.drawCircle(pop.cx, pop.cy, pop.r, pt);
9862200f86f800876d005f911e6864708fa9772d03aDan Sandler            } else {
9872200f86f800876d005f911e6864708fa9772d03aDan Sandler                final Rect r = new Rect();
9882200f86f800876d005f911e6864708fa9772d03aDan Sandler                v.getHitRect(r);
9892200f86f800876d005f911e6864708fa9772d03aDan Sandler                c.drawRect(r, pt);
9902200f86f800876d005f911e6864708fa9772d03aDan Sandler            }
9914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
9924455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
9934455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        pt.setColor(Color.BLACK);
9944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        final StringBuilder sb = new StringBuilder("obstacles: ");
9954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        for (Obstacle ob : mObstaclesInPlay) {
9964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            sb.append(ob.hitRect.toShortString());
9974455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            sb.append(" ");
9984455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
9994455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        pt.setTextSize(20f);
10004455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        c.drawText(sb.toString(), 20, 100, pt);
10014455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
10024455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
10034455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    static final Rect sTmpRect = new Rect();
10044455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
10054455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private interface GameView {
10064455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public void step(long t_ms, long dt_ms, float t, float dt);
10074455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
10084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
10098df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private static class Player extends ImageView implements GameView {
10104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public float dv;
10118df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public int color;
10128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private MLand mLand;
10132200f86f800876d005f911e6864708fa9772d03aDan Sandler        private boolean mBoosting;
10148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private float mTouchX = -1, mTouchY = -1;
10158df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private boolean mAlive;
10168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private int mScore;
10178df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private TextView mScoreField;
10182200f86f800876d005f911e6864708fa9772d03aDan Sandler
1019195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        private final int[] sColors = new int[] {
10208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //0xFF78C557,
10218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                0xFFDB4437,
10228df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                0xFF3B78E7,
10238df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                0xFFF4B400,
10248df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                0xFF0F9D58,
10258df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                0xFF7B1880,
10268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                0xFF9E9E9E,
1027195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler        };
10288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        static int sNextColor = 0;
1029195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler
10304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        private final float[] sHull = new float[] {
10314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.3f,  0f,    // left antenna
10324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.7f,  0f,    // right antenna
10334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.92f, 0.33f, // off the right shoulder of Orion
10344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.92f, 0.75f, // right hand (our right, not his right)
10354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.6f,  1f,    // right foot
10364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.4f,  1f,    // left foot BLUE!
10374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                0.08f, 0.75f, // sinistram
1038195c438883dfcca799aa456dfe52d24c077e40daDaniel Sandler                0.08f, 0.33f, // cold shoulder
10394455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        };
10404455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public final float[] corners = new float[sHull.length];
10414455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
10428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public static Player create(MLand land) {
10438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            final Player p = new Player(land.getContext());
10448df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.mLand = land;
10458df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.reset();
10468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            p.setVisibility(View.INVISIBLE);
10478df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            land.addView(p, new LayoutParams(PARAMS.PLAYER_SIZE, PARAMS.PLAYER_SIZE));
10488df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            return p;
10498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
10508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
10518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private void setScore(int score) {
10528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScore = score;
10538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (mScoreField != null) {
10548df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mScoreField.setText(DEBUG_IDDQD ? "??" : String.valueOf(score));
10558df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
10568df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
10578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
10588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public int getScore() {
10598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            return mScore;
10608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
10618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
10628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        private void addScore(int incr) {
10638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setScore(mScore + incr);
10648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
10658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
10668df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public void setScoreField(TextView tv) {
10678df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mScoreField = tv;
10688df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (tv != null) {
10698df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                setScore(mScore); // reapply
10708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //mScoreField.setBackgroundResource(R.drawable.scorecard);
10718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mScoreField.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
10728df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mScoreField.setTextColor(luma(color) > 0.7f ? 0xFF000000 : 0xFFFFFFFF);
10738df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
10748df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
10758df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
10768df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public void reset() {
10778df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            //setX(mLand.mWidth / 2);
10788df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setY(mLand.mHeight / 2
10798df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    + (int)(Math.random() * PARAMS.PLAYER_SIZE)
10808df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    - PARAMS.PLAYER_SIZE / 2);
10818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setScore(0);
10828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setScoreField(mScoreField); // refresh color
10838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mBoosting = false;
10848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            dv = 0;
10858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
10868df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
10874455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Player(Context context) {
10884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            super(context);
10894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
10904455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setBackgroundResource(R.drawable.android);
10914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
10928df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            color = sColors[(sNextColor++%sColors.length)];
10938df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            getBackground().setTint(color);
10944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setOutlineProvider(new ViewOutlineProvider() {
10954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                @Override
10964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                public void getOutline(View view, Outline outline) {
10974455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    final int w = view.getWidth();
10984455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    final int h = view.getHeight();
10994455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    final int ix = (int) (w * 0.3f);
11004455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    final int iy = (int) (h * 0.2f);
11014455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    outline.setRect(ix, iy, w - ix, h - iy);
11024455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                }
11034455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            });
11044455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
11054455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11064455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public void prepareCheckIntersections() {
11074455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int inset = (PARAMS.PLAYER_SIZE - PARAMS.PLAYER_HIT_SIZE)/2;
11084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int scale = PARAMS.PLAYER_HIT_SIZE;
11094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int N = sHull.length/2;
11104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            for (int i=0; i<N; i++) {
11114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                corners[i*2]   = scale * sHull[i*2]   + inset;
11124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                corners[i*2+1] = scale * sHull[i*2+1] + inset;
11134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
11144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final Matrix m = getMatrix();
11154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            m.mapPoints(corners);
11164455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
11174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11184455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public boolean below(int h) {
11194455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int N = corners.length/2;
11204455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            for (int i=0; i<N; i++) {
11214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final int y = (int) corners[i*2+1];
11224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                if (y >= h) return true;
11234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
11244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            return false;
11254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
11264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public void step(long t_ms, long dt_ms, float t, float dt) {
11288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (!mAlive) {
11298df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                // float away with the garbage
11308df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                setTranslationX(getTranslationX()-PARAMS.TRANSLATION_PER_SEC*dt);
11318df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                return;
11328df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
11334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11342200f86f800876d005f911e6864708fa9772d03aDan Sandler            if (mBoosting) {
11352200f86f800876d005f911e6864708fa9772d03aDan Sandler                dv = -PARAMS.BOOST_DV;
11362200f86f800876d005f911e6864708fa9772d03aDan Sandler            } else {
11372200f86f800876d005f911e6864708fa9772d03aDan Sandler                dv += PARAMS.G;
11382200f86f800876d005f911e6864708fa9772d03aDan Sandler            }
11394455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            if (dv < -PARAMS.MAX_V) dv = -PARAMS.MAX_V;
11404455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            else if (dv > PARAMS.MAX_V) dv = PARAMS.MAX_V;
11414455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11424455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final float y = getTranslationY() + dv * dt;
11434455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setTranslationY(y < 0 ? 0 : y);
11444455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setRotation(
11454455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                    90 + lerp(clamp(rlerp(dv, PARAMS.MAX_V, -1 * PARAMS.MAX_V)), 90, -90));
11464455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11474455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            prepareCheckIntersections();
11484455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
11494455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public void boost(float x, float y) {
11518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mTouchX = x;
11528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mTouchY = y;
11538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            boost();
11548df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
11558df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
11564455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public void boost() {
11572200f86f800876d005f911e6864708fa9772d03aDan Sandler            mBoosting = true;
11584455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            dv = -PARAMS.BOOST_DV;
11592200f86f800876d005f911e6864708fa9772d03aDan Sandler
11602200f86f800876d005f911e6864708fa9772d03aDan Sandler            animate().cancel();
11612200f86f800876d005f911e6864708fa9772d03aDan Sandler            animate()
11622200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleX(1.25f)
11632200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleY(1.25f)
11642200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .translationZ(PARAMS.PLAYER_Z_BOOST)
11652200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setDuration(100);
11664455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setScaleX(1.25f);
11674455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setScaleY(1.25f);
11682200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
11692200f86f800876d005f911e6864708fa9772d03aDan Sandler
11702200f86f800876d005f911e6864708fa9772d03aDan Sandler        public void unboost() {
11712200f86f800876d005f911e6864708fa9772d03aDan Sandler            mBoosting = false;
11728df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mTouchX = mTouchY = -1;
11732200f86f800876d005f911e6864708fa9772d03aDan Sandler
11742200f86f800876d005f911e6864708fa9772d03aDan Sandler            animate().cancel();
11754455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            animate()
11762200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleX(1f)
11772200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .scaleY(1f)
11782200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .translationZ(PARAMS.PLAYER_Z)
11792200f86f800876d005f911e6864708fa9772d03aDan Sandler                    .setDuration(200);
11804455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
11818df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
11828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public void die() {
11838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mAlive = false;
11848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (mScoreField != null) {
11858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //mScoreField.setTextColor(0xFFFFFFFF);
11868df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //mScoreField.getBackground().setColorFilter(0xFF666666, PorterDuff.Mode.SRC_ATOP);
11878df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //mScoreField.setBackgroundResource(R.drawable.scorecard_gameover);
11888df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
11898df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
11908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
11918df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public void start() {
11928df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mAlive = true;
11938df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
11944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
11954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private class Obstacle extends View implements GameView {
11974455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public float h;
11984455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
11994455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public final Rect hitRect = new Rect();
12004455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
12014455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Obstacle(Context context, float h) {
12024455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            super(context);
12032200f86f800876d005f911e6864708fa9772d03aDan Sandler            setBackgroundColor(0xFFFF0000);
12044455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            this.h = h;
12054455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
12064455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
12074455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public boolean intersects(Player p) {
12084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int N = p.corners.length/2;
12094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            for (int i=0; i<N; i++) {
12104455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final int x = (int) p.corners[i*2];
12114455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final int y = (int) p.corners[i*2+1];
12124455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                if (hitRect.contains(x, y)) return true;
12134455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
12144455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            return false;
12154455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
12164455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
12174455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public boolean cleared(Player p) {
12184455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            final int N = p.corners.length/2;
12194455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            for (int i=0; i<N; i++) {
12204455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                final int x = (int) p.corners[i*2];
12214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler                if (hitRect.right >= x) return false;
12224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            }
12234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            return true;
12244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
12254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
12264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        @Override
12274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public void step(long t_ms, long dt_ms, float t, float dt) {
12284455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setTranslationX(getTranslationX()-PARAMS.TRANSLATION_PER_SEC*dt);
12294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            getHitRect(hitRect);
12304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
12314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
12324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
12338df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    static final int[] ANTENNAE = new int[] {R.drawable.mm_antennae, R.drawable.mm_antennae2};
12348df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    static final int[] EYES = new int[] {R.drawable.mm_eyes, R.drawable.mm_eyes2};
12358df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    static final int[] MOUTHS = new int[] {R.drawable.mm_mouth1, R.drawable.mm_mouth2,
12368df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            R.drawable.mm_mouth3, R.drawable.mm_mouth4};
12372200f86f800876d005f911e6864708fa9772d03aDan Sandler    private class Pop extends Obstacle {
12382200f86f800876d005f911e6864708fa9772d03aDan Sandler        int mRotate;
12392200f86f800876d005f911e6864708fa9772d03aDan Sandler        int cx, cy, r;
12408df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        // The marshmallow illustration and hitbox is 2/3 the size of its container.
12418df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        Drawable antenna, eyes, mouth;
12428df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
12438df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
12442200f86f800876d005f911e6864708fa9772d03aDan Sandler        public Pop(Context context, float h) {
12452200f86f800876d005f911e6864708fa9772d03aDan Sandler            super(context, h);
12468df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setBackgroundResource(R.drawable.mm_head);
12478df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            antenna = context.getDrawable(pick(ANTENNAE));
12488df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (frand() > 0.5f) {
12498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                eyes = context.getDrawable(pick(EYES));
12508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                if (frand() > 0.8f) {
12518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mouth = context.getDrawable(pick(MOUTHS));
12528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
12538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
12542200f86f800876d005f911e6864708fa9772d03aDan Sandler            setOutlineProvider(new ViewOutlineProvider() {
12552200f86f800876d005f911e6864708fa9772d03aDan Sandler                @Override
12562200f86f800876d005f911e6864708fa9772d03aDan Sandler                public void getOutline(View view, Outline outline) {
12578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    final int pad = (int) (getWidth() * 1f/6);
12582200f86f800876d005f911e6864708fa9772d03aDan Sandler                    outline.setOval(pad, pad, getWidth()-pad, getHeight()-pad);
12592200f86f800876d005f911e6864708fa9772d03aDan Sandler                }
12602200f86f800876d005f911e6864708fa9772d03aDan Sandler            });
12612200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
12622200f86f800876d005f911e6864708fa9772d03aDan Sandler
12632200f86f800876d005f911e6864708fa9772d03aDan Sandler        public boolean intersects(Player p) {
12642200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int N = p.corners.length/2;
12652200f86f800876d005f911e6864708fa9772d03aDan Sandler            for (int i=0; i<N; i++) {
12662200f86f800876d005f911e6864708fa9772d03aDan Sandler                final int x = (int) p.corners[i*2];
12672200f86f800876d005f911e6864708fa9772d03aDan Sandler                final int y = (int) p.corners[i*2+1];
12682200f86f800876d005f911e6864708fa9772d03aDan Sandler                if (Math.hypot(x-cx, y-cy) <= r) return true;
12692200f86f800876d005f911e6864708fa9772d03aDan Sandler            }
12702200f86f800876d005f911e6864708fa9772d03aDan Sandler            return false;
12712200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
12722200f86f800876d005f911e6864708fa9772d03aDan Sandler
12732200f86f800876d005f911e6864708fa9772d03aDan Sandler        @Override
12742200f86f800876d005f911e6864708fa9772d03aDan Sandler        public void step(long t_ms, long dt_ms, float t, float dt) {
12752200f86f800876d005f911e6864708fa9772d03aDan Sandler            super.step(t_ms, dt_ms, t, dt);
12762200f86f800876d005f911e6864708fa9772d03aDan Sandler            if (mRotate != 0) {
12772200f86f800876d005f911e6864708fa9772d03aDan Sandler                setRotation(getRotation() + dt * 45 * mRotate);
12782200f86f800876d005f911e6864708fa9772d03aDan Sandler            }
12792200f86f800876d005f911e6864708fa9772d03aDan Sandler
12802200f86f800876d005f911e6864708fa9772d03aDan Sandler            cx = (hitRect.left + hitRect.right)/2;
12812200f86f800876d005f911e6864708fa9772d03aDan Sandler            cy = (hitRect.top + hitRect.bottom)/2;
12828df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            r = getWidth() / 3; // see above re 2/3 container size
12838df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
12848df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
12858df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        @Override
12868df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public void onDraw(Canvas c) {
12878df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            super.onDraw(c);
12888df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (antenna != null) {
12898df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                antenna.setBounds(0, 0, c.getWidth(), c.getHeight());
12908df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                antenna.draw(c);
12918df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
12928df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (eyes != null) {
12938df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                eyes.setBounds(0, 0, c.getWidth(), c.getHeight());
12948df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                eyes.draw(c);
12958df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
12968df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (mouth != null) {
12978df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mouth.setBounds(0, 0, c.getWidth(), c.getHeight());
12988df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mouth.draw(c);
12998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
13002200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
13012200f86f800876d005f911e6864708fa9772d03aDan Sandler    }
13022200f86f800876d005f911e6864708fa9772d03aDan Sandler
13032200f86f800876d005f911e6864708fa9772d03aDan Sandler    private class Stem extends Obstacle {
13042200f86f800876d005f911e6864708fa9772d03aDan Sandler        Paint mPaint = new Paint();
13052200f86f800876d005f911e6864708fa9772d03aDan Sandler        Path mShadow = new Path();
13068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        GradientDrawable mGradient = new GradientDrawable();
13072200f86f800876d005f911e6864708fa9772d03aDan Sandler        boolean mDrawShadow;
13088df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        Path mJandystripe;
13098df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        Paint mPaint2;
13108df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        int id; // use this to track which pipes have been cleared
13112200f86f800876d005f911e6864708fa9772d03aDan Sandler
13122200f86f800876d005f911e6864708fa9772d03aDan Sandler        public Stem(Context context, float h, boolean drawShadow) {
13132200f86f800876d005f911e6864708fa9772d03aDan Sandler            super(context, h);
13148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            id = mCurrentPipeId;
13158df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
13162200f86f800876d005f911e6864708fa9772d03aDan Sandler            mDrawShadow = drawShadow;
13172200f86f800876d005f911e6864708fa9772d03aDan Sandler            setBackground(null);
13188df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mGradient.setOrientation(GradientDrawable.Orientation.LEFT_RIGHT);
13198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mPaint.setColor(0xFF000000);
13208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mPaint.setColorFilter(new PorterDuffColorFilter(0x22000000, PorterDuff.Mode.MULTIPLY));
13218df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
13228df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (frand() < 0.01f) {
13238df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mGradient.setColors(new int[]{0xFFFFFFFF, 0xFFDDDDDD});
13248df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe = new Path();
13258df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mPaint2 = new Paint();
13268df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mPaint2.setColor(0xFFFF0000);
13278df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mPaint2.setColorFilter(new PorterDuffColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY));
13288df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            } else {
13298df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                //mPaint.setColor(0xFFA1887F);
13308df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mGradient.setColors(new int[]{0xFFBCAAA4, 0xFFA1887F});
13318df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
13322200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
13332200f86f800876d005f911e6864708fa9772d03aDan Sandler
13342200f86f800876d005f911e6864708fa9772d03aDan Sandler        @Override
13352200f86f800876d005f911e6864708fa9772d03aDan Sandler        public void onAttachedToWindow() {
13362200f86f800876d005f911e6864708fa9772d03aDan Sandler            super.onAttachedToWindow();
13372200f86f800876d005f911e6864708fa9772d03aDan Sandler            setWillNotDraw(false);
13382200f86f800876d005f911e6864708fa9772d03aDan Sandler            setOutlineProvider(new ViewOutlineProvider() {
13392200f86f800876d005f911e6864708fa9772d03aDan Sandler                @Override
13402200f86f800876d005f911e6864708fa9772d03aDan Sandler                public void getOutline(View view, Outline outline) {
13412200f86f800876d005f911e6864708fa9772d03aDan Sandler                    outline.setRect(0, 0, getWidth(), getHeight());
13422200f86f800876d005f911e6864708fa9772d03aDan Sandler                }
13432200f86f800876d005f911e6864708fa9772d03aDan Sandler            });
13442200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
13452200f86f800876d005f911e6864708fa9772d03aDan Sandler        @Override
13462200f86f800876d005f911e6864708fa9772d03aDan Sandler        public void onDraw(Canvas c) {
13472200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int w = c.getWidth();
13482200f86f800876d005f911e6864708fa9772d03aDan Sandler            final int h = c.getHeight();
13498df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mGradient.setGradientCenter(w * 0.75f, 0);
13508df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mGradient.setBounds(0, 0, w, h);
13518df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mGradient.draw(c);
13528df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
13538df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            if (mJandystripe != null) {
13548df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe.reset();
13558df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe.moveTo(0, w);
13568df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe.lineTo(w, 0);
13578df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe.lineTo(w, 2 * w);
13588df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe.lineTo(0, 3 * w);
13598df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                mJandystripe.close();
13608df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                for (int y=0; y<h; y+=4*w) {
13618df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    c.drawPath(mJandystripe, mPaint2);
13628df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                    mJandystripe.offset(0, 4 * w);
13638df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler                }
13648df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            }
13658df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
13662200f86f800876d005f911e6864708fa9772d03aDan Sandler            if (!mDrawShadow) return;
13672200f86f800876d005f911e6864708fa9772d03aDan Sandler            mShadow.reset();
13688df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mShadow.moveTo(0, 0);
13692200f86f800876d005f911e6864708fa9772d03aDan Sandler            mShadow.lineTo(w, 0);
13708df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mShadow.lineTo(w, PARAMS.OBSTACLE_WIDTH * 0.4f + w*1.5f);
13718df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            mShadow.lineTo(0, PARAMS.OBSTACLE_WIDTH * 0.4f);
13722200f86f800876d005f911e6864708fa9772d03aDan Sandler            mShadow.close();
13732200f86f800876d005f911e6864708fa9772d03aDan Sandler            c.drawPath(mShadow, mPaint);
13742200f86f800876d005f911e6864708fa9772d03aDan Sandler        }
13752200f86f800876d005f911e6864708fa9772d03aDan Sandler    }
13762200f86f800876d005f911e6864708fa9772d03aDan Sandler
13774455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private class Scenery extends FrameLayout implements GameView {
13784455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public float z;
13794455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public float v;
13804455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public int h, w;
13814455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Scenery(Context context) {
13824455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            super(context);
13834455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
13844455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
13854455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        @Override
13864455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public void step(long t_ms, long dt_ms, float t, float dt) {
13874455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setTranslationX(getTranslationX() - PARAMS.TRANSLATION_PER_SEC * dt * v);
13884455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
13894455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
13904455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
13914455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private class Building extends Scenery {
13924455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Building(Context context) {
13934455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            super(context);
13944455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
13954455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            w = irand(PARAMS.BUILDING_WIDTH_MIN, PARAMS.BUILDING_WIDTH_MAX);
13964455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            h = 0; // will be setup later, along with z
13978df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
13988df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
13998df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
14008df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    static final int[] CACTI = { R.drawable.cactus1, R.drawable.cactus2, R.drawable.cactus3 };
14018df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private class Cactus extends Building {
14028df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public Cactus(Context context) {
14038df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            super(context);
14044455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
14058df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setBackgroundResource(pick(CACTI));
14068df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            w = h = irand(PARAMS.BUILDING_WIDTH_MAX / 4, PARAMS.BUILDING_WIDTH_MAX / 2);
14074455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
14084455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
14094455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
14108df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    static final int[] MOUNTAINS = {
14118df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            R.drawable.mountain1, R.drawable.mountain2, R.drawable.mountain3 };
14128df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    private class Mountain extends Building {
14138df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        public Mountain(Context context) {
14148df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            super(context);
14158df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler
14168df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            setBackgroundResource(pick(MOUNTAINS));
14178df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            w = h = irand(PARAMS.BUILDING_WIDTH_MAX / 2, PARAMS.BUILDING_WIDTH_MAX);
14188df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler            z = 0;
14198df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler        }
14208df3cfe6b8e6a871bcc69efdd19a632229b50384Dan Sandler    }
14214455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private class Cloud extends Scenery {
14224455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Cloud(Context context) {
14234455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            super(context);
14244455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setBackgroundResource(frand() < 0.01f ? R.drawable.cloud_off : R.drawable.cloud);
14254455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            getBackground().setAlpha(0x40);
14264455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            w = h = irand(PARAMS.CLOUD_SIZE_MIN, PARAMS.CLOUD_SIZE_MAX);
14274455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            z = 0;
14284455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            v = frand(0.15f,0.5f);
14294455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
14304455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
14314455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler
14324455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    private class Star extends Scenery {
14334455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        public Star(Context context) {
14344455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            super(context);
14354455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            setBackgroundResource(R.drawable.star);
14364455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            w = h = irand(PARAMS.STAR_SIZE_MIN, PARAMS.STAR_SIZE_MAX);
14374455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler            v = z = 0;
14384455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler        }
14394455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler    }
14404455da985d4bc8b3dce8ae35deaef41049d121daDan Sandler}
1441