Living with the LLand.

Bug: 15984887
Change-Id: I2a42a064587db3478d865348f860bda07217f7dd
This commit is contained in:
Dan Sandler
2014-09-14 16:28:58 -04:00
parent dc524b714e
commit 4455da985d
16 changed files with 1176 additions and 0 deletions

View File

@@ -283,6 +283,21 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".egg.LLandActivity"
android:theme="@android:style/Theme.Material.Light.NoActionBar.TranslucentDecor"
android:exported="true"
android:label="@string/lland"
android:hardwareAccelerated="true"
android:launchMode="singleInstance"
android:screenOrientation="locked"
android:process=":sweetsweetdesserts"
android:excludeFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="com.android.internal.category.PLATLOGO" />
</intent-filter>
</activity>

View File

@@ -0,0 +1,37 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:name="torso"
android:pathData="M12,36c0,1.1 0.9,2 2,2l2,0l0,7c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3l0,-7l4,0l0,7c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3l0,-7l2,0c1.1,0 2,-0.9 2,-2L36,16L12,16L12,36z"
android:fillColor="#FFFFFF"/>
<path
android:name="leftArm"
android:pathData="M7,16c-1.7,0 -3,1.3 -3,3l0,14c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3L10,19C10,17.3 8.7,16 7,16z"
android:fillColor="#FFFFFF"/>
<path
android:name="rightArm"
android:pathData="M41,16c-1.7,0 -3,1.3 -3,3l0,14c0,1.7 1.3,3 3,3c1.7,0 3,-1.3 3,-3L44,19C44,17.3 42.7,16 41,16z"
android:fillColor="#FFFFFF"/>
<path
android:name="illFormTheHead"
android:pathData="M31.1,4.3l2.6,-2.6c0.4,-0.4 0.4,-1 0,-1.4c-0.4,-0.4 -1,-0.4 -1.4,0l-3,3C27.7,2.5 25.9,2 24,2c-1.9,0 -3.7,0.5 -5.3,1.3l-3,-3c-0.4,-0.4 -1,-0.4 -1.4,0c-0.4,0.4 -0.4,1 0,1.4l2.6,2.6C13.9,6.5 12,10 12,14l24,0C36,10 34.1,6.5 31.1,4.3zM20.31,9c0,0.72 -0.59,1.31 -1.31,1.31c-0.72,0 -1.31,-0.59 -1.31,-1.31c0,-0.72 0.59,-1.31 1.31,-1.31C19.72,7.69 20.31,8.28 20.31,9zM30.31,9c0,0.72 -0.59,1.31 -1.31,1.31c-0.73,0 -1.31,-0.59 -1.31,-1.31c0,-0.72 0.59,-1.31 1.31,-1.31C29.72,7.69 30.31,8.28 30.31,9z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -0,0 +1,24 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:pathData="M38.700001,20.100000C37.299999,13.200000 31.299999,8.000000 24.000000,8.000000c-5.800000,0.000000 -10.800000,3.300000 -13.300000,8.100000C4.700000,16.700001 0.000000,21.799999 0.000000,28.000000c0.000000,6.600000 5.400000,12.000000 12.000000,12.000000l26.000000,0.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000C48.000000,24.700001 43.900002,20.400000 38.700001,20.100000z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -0,0 +1,24 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.0dp"
android:height="24.0dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M19.400000,10.000000c-0.700000,-3.400000 -3.700000,-6.000000 -7.400000,-6.000000c-1.500000,0.000000 -2.900000,0.400000 -4.000000,1.200000l1.500000,1.500000C10.200000,6.200000 11.100000,6.000000 12.000000,6.000000c3.000000,0.000000 5.500000,2.500000 5.500000,5.500000L17.500000,12.000000L19.000000,12.000000c1.700000,0.000000 3.000000,1.300000 3.000000,3.000000c0.000000,1.100000 -0.600000,2.100000 -1.600000,2.600000l1.500000,1.500000c1.300000,-0.900000 2.100000,-2.400000 2.100000,-4.100000C24.000000,12.400000 21.900000,10.200000 19.400000,10.000000zM3.000000,5.300000L5.800000,8.000000C2.600000,8.200000 0.000000,10.800000 0.000000,14.000000c0.000000,3.300000 2.700000,6.000000 6.000000,6.000000l11.700000,0.000000l2.000000,2.000000l1.300000,-1.300000L4.300000,4.000000L3.000000,5.300000zM7.700000,10.000000l8.000000,8.000000L6.000000,18.000000c-2.200000,0.000000 -4.000000,-1.800000 -4.000000,-4.000000c0.000000,-2.200000 1.800000,-4.000000 4.000000,-4.000000L7.700000,10.000000z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -0,0 +1,24 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:pathData="M18.000000,4.000000c-2.100000,0.000000 -4.100000,0.300000 -6.000000,0.900000C20.100000,7.500000 26.000000,15.000000 26.000000,24.000000s-5.900000,16.500000 -14.000000,19.100000c1.900000,0.600000 3.900000,0.900000 6.000000,0.900000c11.000000,0.000000 20.000000,-9.000000 20.000000,-20.000000S29.000000,4.000000 18.000000,4.000000z"
android:fillColor="#FFF2F2FF"/>
</vector>

View File

@@ -0,0 +1,51 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="100dp"
android:height="400dp"
android:viewportWidth="100"
android:viewportHeight="400">
<!-- future site of real artwork -->
<path android:fillColor="#FFFFFF00"
android:pathData="M 0,0 L 100,0 L 100,400 L 0,400 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,0 L 100,25 L 100,50 L 0,25 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,50 L 100,75 L 100,100 L 0,75 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,100 L 100,125 L 100,150 L 0,125 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,150 L 100,175 L 100,200 L 0,175 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,200 L 100,225 L 100,250 L 0,225 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,250 L 100,275 L 100,300 L 0,275 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,300 L 100,325 L 100,350 L 0,325 z" />
<path
android:fillColor="#FF000000"
android:pathData="M 0,350 L 100,375 L 100,400 L 0,375 z" />
</vector>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners
android:radius="8dp" />
<solid
android:color="#ffffffff" />
</shape>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners
android:radius="8dp" />
<solid
android:color="#ffff0000" />
</shape>

View File

@@ -0,0 +1,24 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:pathData="M30.250000,17.750000L24.000000,4.000000l-6.250000,13.750000L4.000000,24.000000l13.750000,6.250000L24.000000,44.000000l6.250000,-13.750000L44.000000,24.000000L30.250000,17.750000z"
android:fillColor="#FFFFFF"/>
</vector>

View File

@@ -0,0 +1,29 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<group>
<path
android:pathData="M 24,8 A 16,16 0 1,0 24.0001,8 z"
android:fillColor="#FFFFFFCC" />
<path
android:pathData="M40.0,30.6l6.6,-6.6L40.0,17.4L40.0,8.0l-9.4,0.0L24.0,1.4L17.4,8.0L8.0,8.0l0.0,9.4L1.4,24.0L8.0,30.6L8.0,40.0l9.4,0.0l6.6,6.6l6.6,-6.6L40.0,40.0L40.0,30.6zM24.0,36.0c-6.6,0.0 -12.0,-5.4 -12.0,-12.0s5.4,-12.0 12.0,-12.0c6.6,0.0 12.0,5.4 12.0,12.0S30.6,36.0 24.0,36.0z"
android:fillColor="#FFFFFF40"/>
</group>
</vector>

View File

@@ -0,0 +1,24 @@
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48.0dp"
android:height="48.0dp"
android:viewportWidth="48.0"
android:viewportHeight="48.0">
<path
android:pathData="M40.000000,17.400000L40.000000,8.000000l-9.400000,0.000000L24.000000,1.400000L17.400000,8.000000L8.000000,8.000000l0.000000,9.400000L1.400000,24.000000L8.000000,30.600000L8.000000,40.000000l9.400000,0.000000l6.600000,6.600000l6.600000,-6.600000L40.000000,40.000000l0.000000,-9.400000l6.600000,-6.600000L40.000000,17.400000zM24.000000,36.000000c-6.600000,0.000000 -12.000000,-5.400000 -12.000000,-12.000000s5.400000,-12.000000 12.000000,-12.000000c6.600000,0.000000 12.000000,5.400000 12.000000,12.000000S30.600000,36.000000 24.000000,36.000000zM24.000000,16.000000c-4.400000,0.000000 -8.000000,3.600000 -8.000000,8.000000c0.000000,4.400000 3.600000,8.000000 8.000000,8.000000s8.000000,-3.600000 8.000000,-8.000000C32.000000,19.600000 28.400000,16.000000 24.000000,16.000000z"
android:fillColor="#FF000000"/>
</vector>

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.android.systemui.egg.LLand
android:id="@+id/world"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.android.systemui.egg.LLand>
<TextView
android:id="@+id/score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="32sp"
android:textColor="#FFAAAAAA"
android:layout_marginTop="32dp"
android:layout_marginLeft="16dp"
android:layout_gravity="top|left"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:background="@drawable/scorecard"
/>
<TextView
android:id="@+id/welcome"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30sp"
android:textColor="#FFFFFFFF"
android:layout_gravity="center"
android:layout_marginTop="70dp"
android:visibility="gone"
/>
</FrameLayout>

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
** Copyright 2014, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->
<resources>
<dimen name="obstacle_spacing">380dp</dimen>
<dimen name="translation_per_sec">100dp</dimen>
<dimen name="boost_dv">600dp</dimen>
<dimen name="player_hit_size">40dp</dimen>
<dimen name="player_size">40dp</dimen>
<dimen name="obstacle_width">80dp</dimen>
<dimen name="obstacle_gap">170dp</dimen>
<dimen name="obstacle_height_min">40dp</dimen>
<dimen name="building_width_min">20dp</dimen>
<dimen name="building_width_max">250dp</dimen>
<dimen name="building_height_min">20dp</dimen>
<dimen name="cloud_size_min">10dp</dimen>
<dimen name="cloud_size_max">100dp</dimen>
<dimen name="sun_size">45dp</dimen>
<dimen name="moon_size">30dp</dimen>
<dimen name="star_size_min">3dp</dimen>
<dimen name="star_size_max">5dp</dimen>
<dimen name="G">30dp</dimen>
<dimen name="max_v">1000dp</dimen>
<dimen name="scenery_z">6dp</dimen>
<dimen name="obstacle_z">15dp</dimen>
<dimen name="player_z">15dp</dimen>
<dimen name="player_z_boost">18dp</dimen>
<dimen name="hud_z">35dp</dimen>
</resources>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/**
* Copyright (c) 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Name of the L Land easter egg. DO NOT TRANSLATE -->
<string name="lland">L Land</string>
</resources>

View File

@@ -0,0 +1,748 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.egg;
import android.animation.TimeAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.*;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import com.android.systemui.R;
public class LLand extends FrameLayout {
public static final String TAG = "LLand";
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean DEBUG_DRAW = false && DEBUG;
public static final void L(String s, Object ... objects) {
if (DEBUG) {
Log.d(TAG, String.format(s, objects));
}
}
public static final boolean AUTOSTART = true;
public static final boolean HAVE_STARS = true;
public static final float DEBUG_SPEED_MULTIPLIER = 1f; // 0.1f;
public static final boolean DEBUG_IDDQD = false;
private static class Params {
public float TRANSLATION_PER_SEC;
public int OBSTACLE_SPACING, OBSTACLE_PERIOD;
public int BOOST_DV;
public int PLAYER_HIT_SIZE;
public int PLAYER_SIZE;
public int OBSTACLE_WIDTH;
public int OBSTACLE_GAP;
public int OBSTACLE_MIN;
public int BUILDING_WIDTH_MIN, BUILDING_WIDTH_MAX;
public int BUILDING_HEIGHT_MIN;
public int CLOUD_SIZE_MIN, CLOUD_SIZE_MAX;
public int STAR_SIZE_MIN, STAR_SIZE_MAX;
public int G;
public int MAX_V;
public float SCENERY_Z, OBSTACLE_Z, PLAYER_Z, PLAYER_Z_BOOST, HUD_Z;
public Params(Resources res) {
TRANSLATION_PER_SEC = res.getDimension(R.dimen.translation_per_sec);
OBSTACLE_SPACING = res.getDimensionPixelSize(R.dimen.obstacle_spacing);
OBSTACLE_PERIOD = (int) (OBSTACLE_SPACING / TRANSLATION_PER_SEC);
BOOST_DV = res.getDimensionPixelSize(R.dimen.boost_dv);
PLAYER_HIT_SIZE = res.getDimensionPixelSize(R.dimen.player_hit_size);
PLAYER_SIZE = res.getDimensionPixelSize(R.dimen.player_size);
OBSTACLE_WIDTH = res.getDimensionPixelSize(R.dimen.obstacle_width);
OBSTACLE_GAP = res.getDimensionPixelSize(R.dimen.obstacle_gap);
OBSTACLE_MIN = res.getDimensionPixelSize(R.dimen.obstacle_height_min);
BUILDING_HEIGHT_MIN = res.getDimensionPixelSize(R.dimen.building_height_min);
BUILDING_WIDTH_MIN = res.getDimensionPixelSize(R.dimen.building_width_min);
BUILDING_WIDTH_MAX = res.getDimensionPixelSize(R.dimen.building_width_max);
CLOUD_SIZE_MIN = res.getDimensionPixelSize(R.dimen.cloud_size_min);
CLOUD_SIZE_MAX = res.getDimensionPixelSize(R.dimen.cloud_size_max);
STAR_SIZE_MIN = res.getDimensionPixelSize(R.dimen.star_size_min);
STAR_SIZE_MAX = res.getDimensionPixelSize(R.dimen.star_size_max);
G = res.getDimensionPixelSize(R.dimen.G);
MAX_V = res.getDimensionPixelSize(R.dimen.max_v);
SCENERY_Z = res.getDimensionPixelSize(R.dimen.scenery_z);
OBSTACLE_Z = res.getDimensionPixelSize(R.dimen.obstacle_z);
PLAYER_Z = res.getDimensionPixelSize(R.dimen.player_z);
PLAYER_Z_BOOST = res.getDimensionPixelSize(R.dimen.player_z_boost);
HUD_Z = res.getDimensionPixelSize(R.dimen.hud_z);
}
}
private TimeAnimator mAnim;
private TextView mScoreField;
private View mSplash;
private Player mDroid;
private ArrayList<Obstacle> mObstaclesInPlay = new ArrayList<Obstacle>();
private float t, dt;
private int mScore;
private float mLastPipeTime; // in sec
private int mWidth, mHeight;
private boolean mAnimating, mPlaying;
private boolean mFrozen; // after death, a short backoff
private int mTimeOfDay;
private static final int DAY = 0, NIGHT = 1, TWILIGHT = 2, SUNSET = 3;
private static final int[][] SKIES = {
{ 0xFFc0c0FF, 0xFFa0a0FF }, // DAY
{ 0xFF000010, 0xFF000000 }, // NIGHT
{ 0xFF000040, 0xFF000010 }, // TWILIGHT
{ 0xFF805010, 0xFF202080 }, // SUNSET
};
private static Params PARAMS;
public LLand(Context context) {
this(context, null);
}
public LLand(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public LLand(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setFocusable(true);
PARAMS = new Params(getResources());
mTimeOfDay = irand(0, SKIES.length);
}
@Override
public boolean willNotDraw() {
return !DEBUG;
}
public int getGameWidth() { return mWidth; }
public int getGameHeight() { return mHeight; }
public float getGameTime() { return t; }
public float getLastTimeStep() { return dt; }
public void setScoreField(TextView tv) {
mScoreField = tv;
if (tv != null) {
tv.setTranslationZ(PARAMS.HUD_Z);
if (!(mAnimating && mPlaying)) {
tv.setTranslationY(-500);
}
}
}
public void setSplash(View v) {
mSplash = v;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
stop();
reset();
if (AUTOSTART) {
start(false);
}
}
final float hsv[] = {0, 0, 0};
private void reset() {
L("reset");
final Drawable sky = new GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,
SKIES[mTimeOfDay]
);
sky.setDither(true);
setBackground(sky);
setScaleX(frand() > 0.5f ? 1 : -1);
setScore(0);
int i = getChildCount();
while (i-->0) {
final View v = getChildAt(i);
if (v instanceof GameView) {
removeViewAt(i);
}
}
mObstaclesInPlay.clear();
mWidth = getWidth();
mHeight = getHeight();
boolean showingSun = (mTimeOfDay == DAY || mTimeOfDay == SUNSET) && frand() > 0.25;
if (showingSun) {
final Star sun = new Star(getContext());
sun.setBackgroundResource(R.drawable.sun);
final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
sun.setTranslationX(frand(w, mWidth-w));
if (mTimeOfDay == DAY) {
sun.setTranslationY(frand(w, (mHeight * 0.66f)));
sun.getBackground().setTint(0);
} else {
sun.setTranslationY(frand(mHeight * 0.66f, mHeight - w));
sun.getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
sun.getBackground().setTint(0xC0FF8000);
}
addView(sun, new LayoutParams(w, w));
}
if (!showingSun) {
final boolean dark = mTimeOfDay == NIGHT || mTimeOfDay == TWILIGHT;
final float ff = frand();
if ((dark && ff < 0.75f) || ff < 0.5f) {
final Star moon = new Star(getContext());
moon.setBackgroundResource(R.drawable.moon);
moon.getBackground().setAlpha(dark ? 255 : 128);
moon.setScaleX(frand() > 0.5 ? -1 : 1);
moon.setRotation(moon.getScaleX() * frand(5, 30));
final int w = getResources().getDimensionPixelSize(R.dimen.sun_size);
moon.setTranslationX(frand(w, mWidth - w));
moon.setTranslationY(frand(w, mHeight - w));
addView(moon, new LayoutParams(w, w));
}
}
final int mh = mHeight / 6;
final boolean cloudless = frand() < 0.25;
final int N = 20;
for (i=0; i<N; i++) {
final float r1 = frand();
final Scenery s;
if (HAVE_STARS && r1 < 0.3 && mTimeOfDay != DAY) {
s = new Star(getContext());
} else if (r1 < 0.6 && !cloudless) {
s = new Cloud(getContext());
} else {
s = new Building(getContext());
s.z = (float)i/N;
s.setTranslationZ(PARAMS.SCENERY_Z * (1+s.z));
s.v = 0.85f * s.z; // buildings move proportional to their distance
hsv[0] = 175;
hsv[1] = 0.25f;
hsv[2] = 1 * s.z;
s.setBackgroundColor(Color.HSVToColor(hsv));
s.h = irand(PARAMS.BUILDING_HEIGHT_MIN, mh);
}
final LayoutParams lp = new LayoutParams(s.w, s.h);
if (s instanceof Building) {
lp.gravity = Gravity.BOTTOM;
} else {
lp.gravity = Gravity.TOP;
final float r = frand();
if (s instanceof Star) {
lp.topMargin = (int) (r * r * mHeight);
} else {
lp.topMargin = (int) (1 - r*r * mHeight/2) + mHeight/2;
}
}
addView(s, lp);
s.setTranslationX(frand(-lp.width, mWidth + lp.width));
}
mDroid = new Player(getContext());
mDroid.setX(mWidth / 2);
mDroid.setY(mHeight / 2);
addView(mDroid, new LayoutParams(PARAMS.PLAYER_SIZE, PARAMS.PLAYER_SIZE));
if (mAnim != null) {
Log.wtf(TAG, "reseting while animating??!?");
}
mAnim = new TimeAnimator();
mAnim.setTimeListener(new TimeAnimator.TimeListener() {
@Override
public void onTimeUpdate(TimeAnimator timeAnimator, long t, long dt) {
step(t, dt);
}
});
}
private void setScore(int score) {
mScore = score;
if (mScoreField != null) mScoreField.setText(String.valueOf(score));
}
private void addScore(int incr) {
setScore(mScore + incr);
}
private void start(boolean startPlaying) {
L("start(startPlaying=%s)", startPlaying?"true":"false");
if (startPlaying) {
mPlaying = true;
t = 0;
mLastPipeTime = getGameTime() - PARAMS.OBSTACLE_PERIOD; // queue up a obstacle
if (mSplash != null && mSplash.getAlpha() > 0f) {
mSplash.setTranslationZ(PARAMS.HUD_Z);
mSplash.animate().alpha(0).translationZ(0).setDuration(400);
mScoreField.animate().translationY(0)
.setInterpolator(new DecelerateInterpolator())
.setDuration(1500);
}
mScoreField.setTextColor(0xFFAAAAAA);
mScoreField.setBackgroundResource(R.drawable.scorecard);
mDroid.setVisibility(View.VISIBLE);
mDroid.setX(mWidth / 2);
mDroid.setY(mHeight / 2);
} else {
mDroid.setVisibility(View.GONE);
}
if (!mAnimating) {
mAnim.start();
mAnimating = true;
}
}
private void stop() {
if (mAnimating) {
mAnim.cancel();
mAnim = null;
mAnimating = false;
mScoreField.setTextColor(0xFFFFFFFF);
mScoreField.setBackgroundResource(R.drawable.scorecard_gameover);
mTimeOfDay = irand(0, SKIES.length); // for next reset
mFrozen = true;
postDelayed(new Runnable() {
@Override
public void run() {
mFrozen = false;
}
}, 250);
}
}
public static final float lerp(float x, float a, float b) {
return (b - a) * x + a;
}
public static final float rlerp(float v, float a, float b) {
return (v - a) / (b - a);
}
public static final float clamp(float f) {
return f < 0f ? 0f : f > 1f ? 1f : f;
}
public static final float frand() {
return (float) Math.random();
}
public static final float frand(float a, float b) {
return lerp(frand(), a, b);
}
public static final int irand(int a, int b) {
return (int) lerp(frand(), (float) a, (float) b);
}
private void step(long t_ms, long dt_ms) {
t = t_ms / 1000f; // seconds
dt = dt_ms / 1000f;
if (DEBUG) {
t *= DEBUG_SPEED_MULTIPLIER;
dt *= DEBUG_SPEED_MULTIPLIER;
}
// 1. Move all objects and update bounds
final int N = getChildCount();
int i = 0;
for (; i<N; i++) {
final View v = getChildAt(i);
if (v instanceof GameView) {
((GameView) v).step(t_ms, dt_ms, t, dt);
}
}
// 2. Check for altitude
if (mPlaying && mDroid.below(mHeight)) {
if (DEBUG_IDDQD) {
poke();
} else {
L("player hit the floor");
stop();
}
}
// 3. Check for obstacles
boolean passedBarrier = false;
for (int j = mObstaclesInPlay.size(); j-->0;) {
final Obstacle ob = mObstaclesInPlay.get(j);
if (mPlaying && ob.intersects(mDroid) && !DEBUG_IDDQD) {
L("player hit an obstacle");
stop();
} else if (ob.cleared(mDroid)) {
passedBarrier = true;
mObstaclesInPlay.remove(j);
}
}
if (mPlaying && passedBarrier) {
addScore(1);
}
// 4. Handle edge of screen
// Walk backwards to make sure removal is safe
while (i-->0) {
final View v = getChildAt(i);
if (v instanceof Obstacle) {
if (v.getTranslationX() + v.getWidth() < 0) {
removeViewAt(i);
}
} else if (v instanceof Scenery) {
final Scenery s = (Scenery) v;
if (v.getTranslationX() + s.w < 0) {
v.setTranslationX(getWidth());
}
}
}
// 3. Time for more obstacles!
if (mPlaying && (t - mLastPipeTime) > PARAMS.OBSTACLE_PERIOD) {
mLastPipeTime = t;
final int obstacley = (int) (Math.random()
* (mHeight - 2*PARAMS.OBSTACLE_MIN - PARAMS.OBSTACLE_GAP)) + PARAMS.OBSTACLE_MIN;
final Obstacle p1 = new Obstacle(getContext(), obstacley);
addView(p1, new LayoutParams(
PARAMS.OBSTACLE_WIDTH,
mHeight,
Gravity.TOP|Gravity.LEFT));
p1.setTranslationX(mWidth);
p1.setTranslationY(-mHeight);
p1.setTranslationZ(0);
p1.animate()
.translationY(-mHeight+p1.h)
.translationZ(PARAMS.OBSTACLE_Z)
.setStartDelay(irand(0,250))
.setDuration(250);
mObstaclesInPlay.add(p1);
final Obstacle p2 = new Obstacle(getContext(),
mHeight - obstacley - PARAMS.OBSTACLE_GAP);
addView(p2, new LayoutParams(
PARAMS.OBSTACLE_WIDTH,
mHeight,
Gravity.TOP|Gravity.LEFT));
p2.setTranslationX(mWidth);
p2.setTranslationY(mHeight);
p2.setTranslationZ(0);
p2.animate()
.translationY(mHeight-p2.h)
.translationZ(PARAMS.OBSTACLE_Z)
.setStartDelay(irand(0,100))
.setDuration(400);
mObstaclesInPlay.add(p2);
}
if (DEBUG) {
final Rect r = new Rect();
mDroid.getHitRect(r);
r.inset(-4, -4);
invalidate(r);
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (DEBUG) L("touch: %s", ev);
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
poke();
return true;
}
return false;
}
@Override
public boolean onTrackballEvent(MotionEvent ev) {
if (DEBUG) L("trackball: %s", ev);
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
poke();
return true;
}
return false;
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent ev) {
if (DEBUG) L("keyDown: %d", keyCode);
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_DPAD_UP:
case KeyEvent.KEYCODE_SPACE:
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_BUTTON_A:
poke();
return true;
}
return false;
}
@Override
public boolean onGenericMotionEvent (MotionEvent ev) {
if (DEBUG) L("generic: %s", ev);
return false;
}
private void poke() {
L("poke");
if (mFrozen) return;
if (!mAnimating) {
reset();
start(true);
} else if (!mPlaying) {
start(true);
}
mDroid.boost();
if (DEBUG) {
mDroid.dv *= DEBUG_SPEED_MULTIPLIER;
mDroid.animate().setDuration((long) (200/DEBUG_SPEED_MULTIPLIER));
}
}
@Override
public void onDraw(Canvas c) {
super.onDraw(c);
if (!DEBUG_DRAW) return;
final Paint pt = new Paint();
pt.setColor(0xFFFFFFFF);
final int L = mDroid.corners.length;
final int N = L/2;
for (int i=0; i<N; i++) {
final int x = (int) mDroid.corners[i*2];
final int y = (int) mDroid.corners[i*2+1];
c.drawCircle(x, y, 4, pt);
c.drawLine(x, y,
mDroid.corners[(i*2+2)%L],
mDroid.corners[(i*2+3)%L],
pt);
}
final int M = getChildCount();
pt.setColor(0x6000FF00);
for (int i=0; i<M; i++) {
final View v = getChildAt(i);
if (v == mDroid) continue;
if (!(v instanceof GameView)) continue;
final Rect r = new Rect();
v.getHitRect(r);
c.drawRect(r, pt);
}
pt.setColor(Color.BLACK);
final StringBuilder sb = new StringBuilder("obstacles: ");
for (Obstacle ob : mObstaclesInPlay) {
sb.append(ob.hitRect.toShortString());
sb.append(" ");
}
pt.setTextSize(20f);
c.drawText(sb.toString(), 20, 100, pt);
}
static final Rect sTmpRect = new Rect();
private interface GameView {
public void step(long t_ms, long dt_ms, float t, float dt);
}
private class Player extends ImageView implements GameView {
public float dv;
private final float[] sHull = new float[] {
0.3f, 0f, // left antenna
0.7f, 0f, // right antenna
0.92f, 0.33f, // off the right shoulder of Orion
0.92f, 0.75f, // right hand (our right, not his right)
0.6f, 1f, // right foot
0.4f, 1f, // left foot BLUE!
0.08f, 0.75f, // sinistram
0.08f, 0.33f, // cold shoulder
};
public final float[] corners = new float[sHull.length];
public Player(Context context) {
super(context);
setBackgroundResource(R.drawable.android);
getBackground().setTintMode(PorterDuff.Mode.SRC_ATOP);
getBackground().setTint(0xFF00FF00);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
final int w = view.getWidth();
final int h = view.getHeight();
final int ix = (int) (w * 0.3f);
final int iy = (int) (h * 0.2f);
outline.setRect(ix, iy, w - ix, h - iy);
}
});
}
public void prepareCheckIntersections() {
final int inset = (PARAMS.PLAYER_SIZE - PARAMS.PLAYER_HIT_SIZE)/2;
final int scale = PARAMS.PLAYER_HIT_SIZE;
final int N = sHull.length/2;
for (int i=0; i<N; i++) {
corners[i*2] = scale * sHull[i*2] + inset;
corners[i*2+1] = scale * sHull[i*2+1] + inset;
}
final Matrix m = getMatrix();
m.mapPoints(corners);
}
public boolean below(int h) {
final int N = corners.length/2;
for (int i=0; i<N; i++) {
final int y = (int) corners[i*2+1];
if (y >= h) return true;
}
return false;
}
public void step(long t_ms, long dt_ms, float t, float dt) {
if (getVisibility() != View.VISIBLE) return; // not playing yet
dv += PARAMS.G;
if (dv < -PARAMS.MAX_V) dv = -PARAMS.MAX_V;
else if (dv > PARAMS.MAX_V) dv = PARAMS.MAX_V;
final float y = getTranslationY() + dv * dt;
setTranslationY(y < 0 ? 0 : y);
setRotation(
90 + lerp(clamp(rlerp(dv, PARAMS.MAX_V, -1 * PARAMS.MAX_V)), 90, -90));
prepareCheckIntersections();
}
public void boost() {
dv = -PARAMS.BOOST_DV;
setTranslationZ(PARAMS.PLAYER_Z_BOOST);
setScaleX(1.25f);
setScaleY(1.25f);
animate()
.scaleX(1f)
.scaleY(1f)
.translationZ(PARAMS.PLAYER_Z)
.setDuration(200);
}
}
private class Obstacle extends View implements GameView {
public float h;
public final Rect hitRect = new Rect();
public Obstacle(Context context, float h) {
super(context);
setBackgroundResource(R.drawable.placeholder);
this.h = h;
}
public boolean intersects(Player p) {
final int N = p.corners.length/2;
for (int i=0; i<N; i++) {
final int x = (int) p.corners[i*2];
final int y = (int) p.corners[i*2+1];
if (hitRect.contains(x, y)) return true;
}
return false;
}
public boolean cleared(Player p) {
final int N = p.corners.length/2;
for (int i=0; i<N; i++) {
final int x = (int) p.corners[i*2];
if (hitRect.right >= x) return false;
}
return true;
}
@Override
public void step(long t_ms, long dt_ms, float t, float dt) {
setTranslationX(getTranslationX()-PARAMS.TRANSLATION_PER_SEC*dt);
getHitRect(hitRect);
}
}
private class Scenery extends FrameLayout implements GameView {
public float z;
public float v;
public int h, w;
public Scenery(Context context) {
super(context);
}
@Override
public void step(long t_ms, long dt_ms, float t, float dt) {
setTranslationX(getTranslationX() - PARAMS.TRANSLATION_PER_SEC * dt * v);
}
}
private class Building extends Scenery {
public Building(Context context) {
super(context);
w = irand(PARAMS.BUILDING_WIDTH_MIN, PARAMS.BUILDING_WIDTH_MAX);
h = 0; // will be setup later, along with z
setTranslationZ(PARAMS.SCENERY_Z);
}
}
private class Cloud extends Scenery {
public Cloud(Context context) {
super(context);
setBackgroundResource(frand() < 0.01f ? R.drawable.cloud_off : R.drawable.cloud);
getBackground().setAlpha(0x40);
w = h = irand(PARAMS.CLOUD_SIZE_MIN, PARAMS.CLOUD_SIZE_MAX);
z = 0;
v = frand(0.15f,0.5f);
}
}
private class Star extends Scenery {
public Star(Context context) {
super(context);
setBackgroundResource(R.drawable.star);
w = h = irand(PARAMS.STAR_SIZE_MIN, PARAMS.STAR_SIZE_MAX);
v = z = 0;
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.egg;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import com.android.systemui.R;
public class LLandActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.lland);
LLand world = (LLand) findViewById(R.id.world);
world.setScoreField((TextView) findViewById(R.id.score));
world.setSplash(findViewById(R.id.welcome));
Log.v(LLand.TAG, "focus: " + world.requestFocus());
}
}