Skip to content

Commit fff0599

Browse files
author
Paul Ruiz
committed
Added Android TV Asteroids-esque game
1 parent 6d1b0d3 commit fff0599

33 files changed

+2481
-0
lines changed

AndroidTVAsteroidBelt/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.gradle
2+
/local.properties
3+
/.idea/workspace.xml
4+
.DS_Store
5+
/build

AndroidTVAsteroidBelt/app/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
apply plugin: 'com.android.application'
2+
3+
4+
android {
5+
compileSdkVersion 'android-L'
6+
buildToolsVersion "20.0.0"
7+
8+
defaultConfig {
9+
applicationId "com.ptrprograms.asteroidbelttv"
10+
minSdkVersion 'L'
11+
targetSdkVersion 'L'
12+
versionCode 1
13+
versionName "1.0"
14+
}
15+
buildTypes {
16+
release {
17+
runProguard false
18+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19+
}
20+
}
21+
}
22+
23+
dependencies {
24+
compile fileTree(dir: 'libs', include: ['*.jar'])
25+
compile 'com.android.support:leanback-v17:+'
26+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Add project specific ProGuard rules here.
2+
# By default, the flags in this file are appended to flags specified
3+
# in /Users/PaulTR/Documents/sdk/tools/proguard/proguard-android.txt
4+
# You can edit the include path and order by changing the proguardFiles
5+
# directive in build.gradle.
6+
#
7+
# For more details, see
8+
# http://developer.android.com/guide/developing/tools/proguard.html
9+
10+
# Add any project specific keep options here:
11+
12+
# If your project uses WebView with JS, uncomment the following
13+
# and specify the fully qualified class name to the JavaScript interface
14+
# class:
15+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16+
# public *;
17+
#}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
package="com.ptrprograms.asteroidbelttv" >
4+
5+
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
6+
7+
<application
8+
android:allowBackup="true"
9+
android:icon="@drawable/ic_launcher"
10+
android:label="@string/app_name"
11+
android:isGame="true"
12+
android:theme="@style/AppTheme" >
13+
<activity
14+
android:name=".MainActivity"
15+
android:label="@string/app_name"
16+
android:logo="@drawable/asteroids_banner"
17+
android:screenOrientation="landscape" >
18+
<intent-filter>
19+
<action android:name="android.intent.action.MAIN" />
20+
21+
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
22+
</intent-filter>
23+
</activity>
24+
</application>
25+
26+
</manifest>
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
package com.ptrprograms.asteroidbelttv;
2+
3+
import android.content.Context;
4+
import android.hardware.input.InputManager;
5+
import android.opengl.GLES20;
6+
import android.opengl.GLSurfaceView;
7+
import android.hardware.input.InputManager.InputDeviceListener;
8+
import android.opengl.Matrix;
9+
import android.util.Log;
10+
import android.view.KeyEvent;
11+
import android.view.MotionEvent;
12+
13+
import com.ptrprograms.asteroidbelttv.Objects.Asteroid;
14+
import com.ptrprograms.asteroidbelttv.Objects.Ship;
15+
import com.ptrprograms.asteroidbelttv.Particles.BaseParticle;
16+
import com.ptrprograms.asteroidbelttv.Particles.ParticleSystem;
17+
import com.ptrprograms.asteroidbelttv.Utils.Constants;
18+
import com.ptrprograms.asteroidbelttv.Utils.ShapeBuffer;
19+
import com.ptrprograms.asteroidbelttv.Utils.Utils;
20+
21+
import java.util.ArrayList;
22+
import java.util.List;
23+
24+
import javax.microedition.khronos.egl.EGLConfig;
25+
import javax.microedition.khronos.opengles.GL10;
26+
27+
/**
28+
* Created by PaulTR on 7/20/14.
29+
*/
30+
public class GameView extends GLSurfaceView implements GLSurfaceView.Renderer, InputDeviceListener {
31+
32+
private static GameView mInstance;
33+
34+
private ShapeBuffer mShapeBuffer;
35+
36+
private Ship mShip;
37+
38+
private long mLastUpdateTimeMillis;
39+
40+
private int mWindowWidth;
41+
private int mWindowHeight;
42+
private List<Asteroid> mAsteroids;
43+
private static final int MAX_BULLET_PARTICLES = 100;
44+
45+
private static ParticleSystem mShots;
46+
47+
private final float[] mMVPMatrix = new float[16];
48+
49+
public GameView(Context context) {
50+
super( context );
51+
52+
setEGLContextClientVersion( 2 );
53+
this.setRenderer( this );
54+
this.requestFocus();
55+
56+
mInstance = this;
57+
58+
mLastUpdateTimeMillis = System.currentTimeMillis();
59+
60+
mShip = new Ship( this, Utils.Color.WHITE );
61+
62+
InputManager inputManager = (InputManager) context.getSystemService( Context.INPUT_SERVICE );
63+
inputManager.registerInputDeviceListener( this, null );
64+
mAsteroids = new ArrayList<Asteroid>();
65+
66+
mShots = new ParticleSystem(MAX_BULLET_PARTICLES, true);
67+
68+
initLevel();
69+
70+
}
71+
72+
public static GameView getInstance() {
73+
return mInstance;
74+
}
75+
76+
private void initLevel() {
77+
for( int i = 0; i < 1; i++ ) {
78+
mAsteroids.add(new Asteroid(Utils.Color.RED, Constants.ASTEROID_SIZE_LARGE));
79+
mAsteroids.add( new Asteroid(Utils.Color.RED, Constants.ASTEROID_SIZE_MEDIUM) );
80+
mAsteroids.add( new Asteroid(Utils.Color.RED, Constants.ASTEROID_SIZE_SMALL) );
81+
}
82+
}
83+
84+
private void update( float delta ) {
85+
mShip.update( delta );
86+
BaseParticle bullet = null;
87+
for( Asteroid asteroid : mAsteroids ) {
88+
asteroid.update( delta );
89+
bullet = mShots.checkForCollision( asteroid.mPositionX, asteroid.mPositionY, Constants.ASTEROID_SIZE_LARGE );
90+
if( bullet != null ) {
91+
Log.e("ASTEROIDS", "bullet hit something" );
92+
bullet = null;
93+
}
94+
}
95+
mShots.update( delta );
96+
}
97+
98+
@Override
99+
public void onInputDeviceAdded(int deviceId) {
100+
101+
}
102+
103+
@Override
104+
public void onInputDeviceRemoved(int deviceId) {
105+
106+
}
107+
108+
@Override
109+
public void onInputDeviceChanged(int deviceId) {
110+
111+
}
112+
113+
@Override
114+
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
115+
// The ShapeBuffer creates OpenGl resources, so don't create it until after the
116+
// primary rendering surface has been created.
117+
mShapeBuffer = new ShapeBuffer();
118+
mShapeBuffer.loadResources();
119+
}
120+
121+
/**
122+
* Here we do our drawing
123+
*/
124+
@Override
125+
public void onDrawFrame(GL10 unused) {
126+
// Clear the screen to black.
127+
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
128+
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
129+
130+
// Don't try to draw if the shape buffer failed to initialize.
131+
if (!mShapeBuffer.isInitialized()) {
132+
return;
133+
}
134+
135+
long currentTimeMillis = System.currentTimeMillis();
136+
137+
// Compute frame delta. frameDelta = # of "ideal" frames that have occurred since the
138+
// last update. "ideal" assumes a constant frame-rate (60 FPS or 16.7 milliseconds per
139+
// frame). Since the delta doesn't depend on the "real" frame-rate, the animations always
140+
// run at the same wall clock speed, regardless of what the real refresh rate is.
141+
//
142+
// frameDelta was used instead of a time delta in order to make the values passed
143+
// to update easier to understand when debugging the code. For example, a frameDelta
144+
// of "1.5" means that one and a half hypothetical frames have passed since the last
145+
// update. In wall time this would be 25 milliseconds or 0.025 seconds.
146+
float frameDelta = Utils.millisToFrameDelta(currentTimeMillis - mLastUpdateTimeMillis);
147+
148+
update(frameDelta);
149+
draw();
150+
mLastUpdateTimeMillis = currentTimeMillis;
151+
}
152+
153+
/**
154+
* If the surface changes, reset the view size.
155+
*/
156+
@Override
157+
public void onSurfaceChanged(GL10 unused, int width, int height) {
158+
// Make sure the window dimensions are never 0.
159+
mWindowWidth = Math.max(width, 1);
160+
mWindowHeight = Math.max(height, 1);
161+
}
162+
163+
public void draw() {
164+
// Each world element adds triangles to the shape buffer. No OpenGl calls are made
165+
// until after the whole scene has been added to the shape buffer.
166+
mShapeBuffer.clear();
167+
if (mShip.isActive()) {
168+
mShip.draw(mShapeBuffer);
169+
}
170+
for( Asteroid asteroid : mAsteroids ) {
171+
asteroid.draw( mShapeBuffer );
172+
}
173+
mShots.draw( mShapeBuffer );
174+
// Prepare for rendering to the screen.
175+
updateViewportAndProjection();
176+
177+
// Send the triangles to OpenGl.
178+
mShapeBuffer.draw( mMVPMatrix );
179+
}
180+
181+
private void updateViewportAndProjection() {
182+
// Assume a square viewport if the width and height haven't been initialized.
183+
float viewportAspectRatio = 1.0f;
184+
if ((mWindowWidth > 0) && (mWindowHeight > 0)) {
185+
viewportAspectRatio = (float) mWindowWidth / (float) mWindowHeight;
186+
}
187+
float viewportWidth = (float) mWindowWidth;
188+
float viewportHeight = (float) mWindowHeight;
189+
float viewportOffsetX = 0.0f;
190+
float viewportOffsetY = 0.0f;
191+
192+
if ( Constants.WORLD_ASPECT_RATIO > viewportAspectRatio ) {
193+
// Our window is taller than the ideal aspect ratio needed to accommodate the world
194+
// without stretching.
195+
// Reduce the viewport height to match the aspect ratio of the world. The world
196+
// will fill the whole width of the screen, but have some empty space on the top and
197+
// bottom of the screen.
198+
viewportHeight = viewportWidth / Constants.WORLD_ASPECT_RATIO;
199+
// Center the viewport on the screen.
200+
viewportOffsetY = ((float) mWindowHeight - viewportHeight) / 2.0f;
201+
} else if (viewportAspectRatio > Constants.WORLD_ASPECT_RATIO) {
202+
// Our window is wider than the ideal aspect ratio needed to accommodate the world
203+
// without stretching.
204+
// Reduce the viewport width to match the aspect ratio of the world. The world
205+
// will fill the whole height of the screen, but have some empty space on the
206+
// left and right of the screen.
207+
viewportWidth = viewportHeight * Constants.WORLD_ASPECT_RATIO;
208+
// Center the viewport on the screen.
209+
viewportOffsetX = ((float) mWindowWidth - viewportWidth) / 2.0f;
210+
}
211+
212+
Matrix.orthoM( mMVPMatrix, 0,
213+
Constants.WORLD_LEFT_COORDINATE,
214+
Constants.WORLD_RIGHT_COORDINATE,
215+
Constants.WORLD_BOTTOM_COORDINATE,
216+
Constants.WORLD_TOP_COORDINATE,
217+
Constants.WORLD_NEAR_PLANE,
218+
Constants.WORLD_FAR_PLANE );
219+
GLES20.glViewport((int) viewportOffsetX, (int) viewportOffsetY,
220+
(int) viewportWidth, (int) viewportHeight);
221+
}
222+
223+
public boolean handleMotionEvent(MotionEvent motionEvent) {
224+
if ( mShip != null ) {
225+
mShip.getController().setDeviceId( motionEvent.getDeviceId() );
226+
mShip.getController().handleMotionEvent(motionEvent);
227+
return true;
228+
}
229+
return false;
230+
}
231+
232+
public boolean handleKeyEvent(KeyEvent keyEvent) {
233+
if ( mShip != null) {
234+
mShip.getController().setDeviceId( keyEvent.getDeviceId() );
235+
mShip.getController().handleKeyEvent(keyEvent);
236+
return true;
237+
}
238+
return false;
239+
}
240+
241+
public static ParticleSystem getShots() {
242+
return mShots;
243+
}
244+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.ptrprograms.asteroidbelttv;
2+
3+
import android.app.Activity;
4+
import android.os.Bundle;
5+
import android.view.KeyEvent;
6+
import android.view.MotionEvent;
7+
8+
public class MainActivity extends Activity {
9+
10+
private GameView mGame;
11+
12+
@Override
13+
protected void onCreate(Bundle savedInstanceState) {
14+
super.onCreate(savedInstanceState);
15+
mGame = new GameView( this );
16+
setContentView( mGame );
17+
}
18+
19+
@Override
20+
protected void onResume() {
21+
super.onResume();
22+
mGame.onResume();
23+
}
24+
25+
@Override
26+
protected void onPause() {
27+
super.onPause();
28+
mGame.onPause();
29+
}
30+
31+
@Override
32+
public boolean dispatchGenericMotionEvent(MotionEvent event) {
33+
return mGame.handleMotionEvent(event);
34+
}
35+
36+
@Override
37+
public boolean dispatchKeyEvent(KeyEvent event) {
38+
return mGame.handleKeyEvent(event);
39+
}
40+
}

0 commit comments

Comments
 (0)