diff --git a/.gitignore b/.gitignore index a8b0d1d..d3c6c1b 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,45 @@ google-services.json # Android Profiling *.hprof +## Suggested ^^ + +## From TicTacToe project for good measure. vv + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties + +# Log/OS Files +*.log + +# Android Studio generated files and folders +captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json + +# IntelliJ +*.iml +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore + +# Google Services (e.g. APIs or Firebase) +google-services.json + +# Android Profiling +*.hprof +/app/debug/output-metadata.json + +# Ha! +keystore/* +release diff --git a/app/.gitignore b/app/.gitignore new file mode 100755 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100755 index 0000000..13f56a9 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,30 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 24 + buildToolsVersion "24.0.2" + defaultConfig { + applicationId "apps.hyperling.com.platformer" + minSdkVersion 15 + targetSdkVersion 24 + versionCode 10 + versionName "0.9" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:24.2.1' + compile 'com.google.android.gms:play-services-ads:9.8.0' + testCompile 'junit:junit:4.12' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100755 index 0000000..2141ffd --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /home/ling/Android/Sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/com/hyperling/apps/games/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/hyperling/apps/games/ExampleInstrumentedTest.java new file mode 100755 index 0000000..85a88c5 --- /dev/null +++ b/app/src/androidTest/java/com/hyperling/apps/games/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.hyperling.apps.games; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("apps.hyperling.com.platformer", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100755 index 0000000..f8ea237 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/hyperling/apps/games/AdsHelper.java b/app/src/main/java/com/hyperling/apps/games/AdsHelper.java new file mode 100755 index 0000000..ed50f9b --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/AdsHelper.java @@ -0,0 +1,36 @@ +package com.hyperling.apps.games; + +import android.content.Context; +import android.content.SharedPreferences; +import android.view.View; + +import com.google.android.gms.ads.AdRequest; +import com.google.android.gms.ads.AdView; +import com.google.android.gms.ads.MobileAds; + +/** + * Created by ling on 12/26/16. + */ + +public class AdsHelper { + + // To be called in onResume in Activities + public static void toggleAds(SharedPreferences sharedPreferences, String adsKey, Context applicationContext, AdView mAdView){ + // Enable ads? + boolean adsEnabled = sharedPreferences.getBoolean(adsKey, false); + if (adsEnabled) { + mAdView.setVisibility(View.VISIBLE); + MobileAds.initialize(applicationContext, "ca-app-pub-3940256099942544~3347511713"); + AdRequest adRequest = new AdRequest.Builder() + .addTestDevice(AdRequest.DEVICE_ID_EMULATOR) + .addTestDevice("C6A494DC6E7C9AC29102694D48487084") // Nexus 7 + .addTestDevice("6545BCC9B60A394005546783687339B7") // Moto G + .build(); + mAdView.loadAd(adRequest); + } + else{ + mAdView.setVisibility(View.GONE); + } + + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/Animation.java b/app/src/main/java/com/hyperling/apps/games/Animation.java new file mode 100755 index 0000000..70ef76c --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/Animation.java @@ -0,0 +1,54 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; + +/** + * Created by ling on 12/22/16. + */ + +public class Animation { + + private Bitmap[] frames; + private int currentFrame; + private long startTime; + private long delay; + private boolean playedOnce; + + public void setFrames(Bitmap[] f) { + frames = f; + } + + public void setDelay(long d) { + delay = d; + } + + public void setCurrentFrame(int cf) { + currentFrame = cf; + } + + public Bitmap getImage(){ + return frames[currentFrame]; + } + + public int getCurrentFrame(){ + return currentFrame; + } + + public boolean getPlayedOnce(){ + return playedOnce; + } + + public void update(){ + long elapsed = System.currentTimeMillis() - startTime; + if (elapsed > delay){ + currentFrame++; + startTime = System.currentTimeMillis(); + } + + if (currentFrame == frames.length){ + currentFrame = 0; + playedOnce = true; + } + } + +} diff --git a/app/src/main/java/com/hyperling/apps/games/Bird.java b/app/src/main/java/com/hyperling/apps/games/Bird.java new file mode 100755 index 0000000..3d69a31 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/Bird.java @@ -0,0 +1,76 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; + +/** + * Created by ling on 12/23/16. + */ + +public class Bird extends Player { + + private boolean flapping = false; + + private int lives = 0; + + public Bird(Bitmap b, int w, int h, int numFrames){ + super(b, w, h, numFrames); + } + + public boolean isFlapping() { + return flapping; + } + + public void setFlapping(boolean flapping) { + this.flapping = flapping; + } + + public int getLives() { + return lives; + } + + public void addLives(int lives) { + this.lives += lives; + } + + public void subtractLives(int lives) { + this.lives -= lives; + } + + @Override + public void update() { + // Go up! + if (flapping){ + dy += -1; + } + // Otherwise fall + else{ + dy += 2; + } + + // Do not fly up faster than this + if (dy < -5){ + dy = -5; + } + // Do not fall faster than this + if (dy > 7){ + dy = 7; + } + + /***** Map limits *****/ + if (y < GameView.HEIGHT - getHeight() || dy < 0) { + y += dy; + } + // Do not leave bottom of map + else{ + y = GameView.HEIGHT - getHeight(); + dy = 0; + } + + // Do not leave top of map + if (y < 0){ + y = 0; + } + + super.update(); + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/BirdEnemy.java b/app/src/main/java/com/hyperling/apps/games/BirdEnemy.java new file mode 100755 index 0000000..9cef084 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/BirdEnemy.java @@ -0,0 +1,71 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; +import android.graphics.Canvas; + +/** + * Created by ling on 12/26/16. + */ + +public class BirdEnemy extends GameObject { + + protected Bitmap image; + + private Animation animation; + + private int speed, damage; + + public BirdEnemy(Bitmap b, int w, int h, int numFrames, int x, int y, int speed, int damage){ + image = b; + width = w; + height = h; + this.x = x; + this.y = y; + this.speed = speed; + this.damage = damage; + + if (speed > -1){ + speed = -1; + } + if (this.y >= GameView.HEIGHT - this.height){ + this.y = GameView.HEIGHT - this.height; + } + + // Create animation + Bitmap[] image = new Bitmap[numFrames]; + animation = new Animation(); + + for (int i = 0; i < numFrames; i++){ + image[i] = Bitmap.createBitmap(b, width * i, 0, width, height); + } + + animation.setFrames(image); + + //animation.setDelay(100); + int delay = 25 * Math.abs(speed); + if (delay > 125){ + delay = 125; + } + else if (delay < 75){ + delay = 75; + } + animation.setDelay(delay); + animation.setCurrentFrame((int)(Math.random() * numFrames)); + } + + public void update(){ + animation.update(); + + // Move the object + x += speed; + } + + public void draw(Canvas canvas) { + // Draw the object + canvas.drawBitmap(animation.getImage(), getX(), getY(), null); + } + + public int getDamage() { + return damage; + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/BirdGameView.java b/app/src/main/java/com/hyperling/apps/games/BirdGameView.java new file mode 100755 index 0000000..60c2063 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/BirdGameView.java @@ -0,0 +1,290 @@ +package com.hyperling.apps.games; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Rect; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceHolder; + +import java.util.ArrayList; + +/** + * Created by ling on 12/28/16. + */ + +public class BirdGameView extends GameView { + private final String birdScoreKey; + + private final int birdGameSpeed = -8; + private final int birdEnemySpeedVariance = 5; + private final int birdEnemySpeedConstant = 2; + private final int cloudsSpeed = birdGameSpeed/2; + + private Bird bird; + private Bitmap birdBitmap; + + private ArrayList birdEnemies; + private Bitmap birdEnemyBitmap; + + private final int birdWidth = 30; + private final int birdHeight = 20; + private final int birdFrames = 4; + + private ArrayList birdExtraLives; + private Bitmap birdExtraLifeBitmap; + + private final int birdExtraLifeWidth = 20; + private final int birdExtraLifeHeight = 30; + + private final int birdMaxNumEnemyRows = HEIGHT / birdHeight; + private final int birdEnemySpawnRate = 25; + + private Bitmap backgroundBitmap, cloudsBitmap; + + public BirdGameView(Context context){ + super(context); + + // Keys + birdScoreKey = resources.getString(R.string.birdScoreKey); + } + + private void displayScore(Canvas canvas){ + int highScore = sharedPreferences.getInt(birdScoreKey, 0); + textPaint.setColor(Color.parseColor("#330066")); + canvas.drawText("High: " + highScore, 0, textPaint.getTextSize(), textPaint); + canvas.drawText("Current: " + bird.getScore(), 0, textPaint.getTextSize() * 2, textPaint); + + if (bird.getLives() > 0) { + canvas.drawText("Lives: " + bird.getLives(), 0, textPaint.getTextSize() * 3, textPaint); + } + + if (fpsEnabled){ + canvas.drawText("FPS: " + thread.averageFPS, 0, HEIGHT - 1, textPaint); + } + + if (!bird.isPlaying()) { + textPaint.setColor(Color.parseColor("#330066")); + canvas.drawText("You are the Purple Bird", WIDTH / 4, HEIGHT / 4 - textPaint.getTextSize(), textPaint); + + textPaint.setColor(Color.parseColor("#FF9900")); + canvas.drawText("Tap the Screen to Start", WIDTH / 4, HEIGHT / 4, textPaint); + canvas.drawText("Hold the Screen to Fly Higher", WIDTH / 4, HEIGHT / 4 + textPaint.getTextSize(), textPaint); + + textPaint.setColor(Color.parseColor("#FF0000")); + canvas.drawText("Dodge the Enemy Birds", WIDTH / 4, HEIGHT * 3 / 4, textPaint); + + textPaint.setColor(Color.parseColor("#FFFF00")); + textPaint.setFakeBoldText(true); + canvas.drawText("Collect the Bird Coins for Extra Lives", WIDTH / 4, HEIGHT * 3 / 4 + textPaint.getTextSize(), textPaint); + textPaint.setFakeBoldText(false); + } + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + + // Base Object Initializations + if (higherQualityEnabled) { + backgroundBitmap = BitmapFactory.decodeResource(resources, R.drawable.background_forest_without_clouds); + cloudsBitmap = BitmapFactory.decodeResource(resources, R.drawable.clouds); + } + else{ + backgroundBitmap = BitmapFactory.decodeResource(resources, R.drawable.background_forest); + } + birdBitmap = BitmapFactory.decodeResource(resources, R.drawable.bird); + birdEnemyBitmap = BitmapFactory.decodeResource(resources, R.drawable.bird_enemy); + birdExtraLifeBitmap = BitmapFactory.decodeResource(resources, R.drawable.bird_extra_life); + + // Game Object Initializations + background = new GameBackground(backgroundBitmap); + if (higherQualityEnabled) { + clouds = new GameBackground(cloudsBitmap); + } + bird = new Bird(birdBitmap, birdWidth, birdHeight, birdFrames); + birdEnemies = new ArrayList<>(); + birdExtraLives = new ArrayList<>(); + + // Settings + setGameSpeed(birdGameSpeed); + + super.surfaceCreated(holder); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (!bird.isPlaying()) { + bird.setPlaying(true); + + int lifeMiddleOfScreen = HEIGHT/2 - birdExtraLifeHeight/2; + birdExtraLives.add(new ExtraLife(birdExtraLifeBitmap, birdExtraLifeWidth, birdExtraLifeHeight, WIDTH, lifeMiddleOfScreen, 1)); + } + else{ + bird.setFlapping(true); + } + + return true; + } + + if (event.getAction() == MotionEvent.ACTION_UP){ + bird.setFlapping(false); + + return true; + } + + return super.onTouchEvent(event); + } + + public void pauseGame() { + super.pauseGame(birdScoreKey, bird.getScore()); + } + + @Override + public void update() { + super.update(); + + + if (bird.isPlaying()) { + background.update(gameSpeed); + if (higherQualityEnabled) { + clouds.update(cloudsSpeed); + } + + int birdLevel = bird.getScore() / (birdEnemySpawnRate * birdMaxNumEnemyRows); + + // Update extra lives before enemies :) + for (int i = 0; i < birdExtraLives.size(); i++) { + ExtraLife birdExtraLife = birdExtraLives.get(i); + boolean removeLife = false; + + // Check if we've hit any extra lives + if (bird.getRect().intersect(birdExtraLife.getRect())){ + bird.addLives(birdExtraLife.getNumLives()); + removeLife = true; + } + + if (removeLife || birdExtraLife.x + birdExtraLifeWidth < 0){ + birdExtraLives.remove(birdExtraLife); + i--; + } + else{ + birdExtraLife.update(birdGameSpeed); + } + } + + /***** Add new lives *****/ + // Only < so that lives don't appear until more than 1 bird can be on a row + if (birdExtraLives.size() < birdLevel){ + int birdExtraLifeX = WIDTH + birdExtraLifeWidth; + int birdExtraLifeY = ((int)(Math.random() * HEIGHT));; + birdExtraLives.add(new ExtraLife(birdExtraLifeBitmap, birdExtraLifeWidth, birdExtraLifeHeight, birdExtraLifeX, birdExtraLifeY, 1)); + } + + // Update enemies + for (int i = 0; i < birdEnemies.size(); i++){ + BirdEnemy birdEnemy = birdEnemies.get(i); + boolean birdEnemyRemove = false; + + // Check if we've hit any enemies + if (bird.getRect().intersect(birdEnemy.getRect())){ + + bird.subtractLives(birdEnemy.getDamage()); + birdEnemyRemove = true; + + if (bird.getLives() < 0) { + /***** Stop the game, save the score, and reset the player and all objects *****/ + bird.setPlaying(false); + saveScore(birdScoreKey, bird.getScore()); + + // Reset + bird = new Bird(birdBitmap, birdWidth, birdHeight, birdFrames); + birdEnemies = new ArrayList<>(); + birdExtraLives = new ArrayList<>(); + } + } + + birdEnemy.update(); + + // Check if any enemies can be removed yet + if (birdEnemyRemove || birdEnemy.x + birdEnemy.width < 0){ + birdEnemies.remove(birdEnemy); + i--; + } + } + + // Check if we can add new enemies + if (birdEnemies.size() < bird.getScore() / 25 && !thread.markerFrame){ + //int enemyX = WIDTH + (int)(WIDTH * Math.random()); + int enemyX = WIDTH + birdWidth; + int enemyY = ((int)(Math.random() * HEIGHT)); + // Add constant so that the bird is always slower than the background + // Prevents birds from looking frozen or like they're going backwards + int enemySpeed = gameSpeed + ((int)(Math.random() * birdEnemySpeedVariance) + birdEnemySpeedConstant); + int numBirdEnemiesInRow = 0; + for (BirdEnemy birdEnemy : birdEnemies){ + Log.d(TAG, "GameView.update(): enemyY=" + enemyY + ", birdEnemy.y=" + birdEnemy.y); + if (birdEnemy.getRect().intersect(new Rect(birdEnemy.x, enemyY, birdEnemy.x + birdWidth, enemyY + birdHeight))){ + numBirdEnemiesInRow++; + } + } + Log.d(TAG, "GameView.update(): birdLevel=" + birdLevel); + Log.d(TAG, "GameView.update(): numBirdEnemiesInRow=" + numBirdEnemiesInRow); + + // Just for a little chaos, 1/100 chance for extra enemies + boolean addExtraEnemies = ((int) (Math.random() * 100)) == 69; + + // <= so that the game can start + if (numBirdEnemiesInRow <= birdLevel || addExtraEnemies){ + Log.d(TAG, "GameView.update(): Adding birdEnemy!"); + birdEnemies.add(new BirdEnemy(birdEnemyBitmap, birdWidth, birdHeight, birdFrames, enemyX, enemyY, enemySpeed, 1)); + } + } + + bird.update(); + } + } + + @Override + public void draw(Canvas canvas) { + + if (canvas != null) { + super.draw(canvas); + + final float scaleX = (float) getWidth()/WIDTH; + final float scaleY = (float) getHeight()/HEIGHT; + + Log.d(TAG, "GameView.draw(): Canvas not null, scaling! scaleX=" + scaleX + ", scaleY=" + scaleY); + Log.d(TAG, "GameView.draw(): Canvas not null, scaling! getScaleX()=" + getScaleX() + ", getScaleY()=" + getScaleY()); + + final int savedState = canvas.save(); + canvas.scale(scaleX, scaleY); + + // Draw all the game's objects + if (higherQualityEnabled) { + clouds.draw(canvas); + } + + background.draw(canvas); + + for (ExtraLife birdExtraLife : birdExtraLives) { + birdExtraLife.draw(canvas); + } + + for (BirdEnemy birdEnemy : birdEnemies) { + birdEnemy.draw(canvas); + } + + displayScore(canvas); + + bird.draw(canvas); + + // Prevent canvas from infinite scaling + canvas.restoreToCount(savedState); + } + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/Chicken.java b/app/src/main/java/com/hyperling/apps/games/Chicken.java new file mode 100755 index 0000000..45e118f --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/Chicken.java @@ -0,0 +1,103 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; + +/** + * Created by ling on 12/23/16. + */ + +public class Chicken extends Player { + + private boolean jumping, flapping; + private int lastY, lastDY; + private int leftFootX, rightFootX; + + public Chicken(Bitmap b, int w, int h, int numFrames){ + super(b, w, h, numFrames); + } + + public boolean isJumping() { + return jumping; + } + + public void setJumping(boolean jumping) { + this.jumping = jumping; + } + + public boolean isFlapping() { + return flapping; + } + + public void setFlapping(boolean flapping) { + this.flapping = flapping; + } + + public void jump(){ + // If we are already jumping then we should flap instead + if (jumping){ + flap(); + } + // Jumps are more powerful than flaps + else{ + jumping = true; + dy -= 20; + } + } + + private void flap(){ + // Only allow a flap after we start falling + if (!flapping){ + flapping = true; + dy -= 10; + } + } + + public void update(int platformY) { + // If we are in the same Y position and are not flapping, we are on solid ground. + if (lastY == y && !flapping){ + jumping = false; + } + // Allow flapping once the last flap wears off. + if (dy > 0){ + flapping = false; + } + + // Apply gravity + dy += 1; + + // Do not allow super flapping + if (dy < -5){ + dy = -5; + } + // Fall slower if we have jumped + else if (dy > 5 && jumping){ + dy = 5; + } + // Otherwise cap gravity + else if (dy > 15 && !jumping){ + dy = 15; + } + + // Do not fall through platforms + if (y + dy > platformY - getHeight()){ + setY(platformY - getHeight()); + setDy(0); + } + else{ + y += dy; + } + + // Do not leave top of map + if (y < 0){ + y = 0; + } + + // Remember where we used to be + lastY = y; + lastDY = dy; + + super.update(); + + + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/ChickenGameView.java b/app/src/main/java/com/hyperling/apps/games/ChickenGameView.java new file mode 100755 index 0000000..1791fe0 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/ChickenGameView.java @@ -0,0 +1,320 @@ +package com.hyperling.apps.games; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceHolder; + +import java.util.ArrayList; + +/** + * Created by ling on 12/28/16. + */ + +public class ChickenGameView extends GameView { + + private Chicken chicken; + private Bitmap chickenBitmap; + private final int chickenWidth = 20; + private final int chickenHeight = 20; + private final int chickenFrames = 2; + + private final int lavaHeight = 30; + + private ArrayList platforms; + private Bitmap platformBitmap; + private final int platformWidth = 32; + private final int platformHeight = 400; + private final int platformDefaultY = HEIGHT - lavaHeight; + + private Bitmap backgroundBitmap, lavaBitmap, cloudsBitmap; + + private int chickenGameSpeed = -4; + private int cloudsSpeed = chickenGameSpeed / 2; + private int lavaSpeed = chickenGameSpeed - 1; + + private ArrayList enemies; + private Bitmap enemyBitmap; + private final int enemyWidth = 32; + private final int enemyHeight = 32; + private final int enemyFrames = 1; + private final int enemySpeed = chickenGameSpeed * 2; + + private String chickenScoreKey; + + private int maxGapSize = 200; + + public ChickenGameView(Context context) { + super(context); + + // Keys + chickenScoreKey = resources.getString(R.string.chickenScoreKey); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + setGameSpeed(chickenGameSpeed); + + // Create global Bitmaps + if (higherQualityEnabled) { + backgroundBitmap = BitmapFactory.decodeResource(resources, R.drawable.background_forest_without_clouds); + lavaBitmap = BitmapFactory.decodeResource(resources, R.drawable.lava); + cloudsBitmap = BitmapFactory.decodeResource(resources, R.drawable.clouds); + } + else{ + backgroundBitmap = BitmapFactory.decodeResource(resources, R.drawable.background_forest_with_lava); + } + chickenBitmap = BitmapFactory.decodeResource(resources, R.drawable.chicken); + platformBitmap = BitmapFactory.decodeResource(resources, R.drawable.normal_platform); + enemyBitmap = BitmapFactory.decodeResource(resources, R.drawable.enemy); + + // Initialize Background(s) + background = new GameBackground(backgroundBitmap); + if (higherQualityEnabled) { + clouds = new GameBackground(cloudsBitmap); + lava = new GameBackground(lavaBitmap); + } + + resetPlatforms(); + + enemies = new ArrayList<>(); + + chicken = new Chicken(chickenBitmap, chickenWidth, chickenHeight, chickenFrames); + + super.surfaceCreated(holder); + } + + public void pauseGame() { + super.pauseGame(chickenScoreKey, chicken.getScore()); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (!chicken.isPlaying()) { + chicken.setPlaying(true); + } + else { + // Accelerate when moving higher in the air + /* + if (chicken.isJumping()) { + boost(2, 250); + } + // Boost harder on the a jump than a flap + else{ + boost(2, 500); + } + */ + chicken.jump(); + } + } + + return super.onTouchEvent(event); + } + + private void resetPlatforms(){ + platforms = new ArrayList<>(); + + // Create initial platform layer + int platformEndX = 0; + while (platformEndX < WIDTH){ + Platform platform = new Platform(platformBitmap, platformWidth, platformHeight, platformEndX, platformDefaultY); + platformEndX = platform.x + platform.width; + + platforms.add(platform); + } + } + + private void displayScore(Canvas canvas){ + int highScore = sharedPreferences.getInt(chickenScoreKey, 0); + textPaint.setColor(Color.parseColor("#330066")); + canvas.drawText("High: " + highScore, 0, textPaint.getTextSize(), textPaint); + canvas.drawText("Current: " + chicken.getScore(), 0, textPaint.getTextSize() * 2, textPaint); + + if (fpsEnabled){ + canvas.drawText("FPS: " + thread.averageFPS, 0, HEIGHT - 1, textPaint); + } + + if (!chicken.isPlaying()) { + textPaint.setColor(Color.parseColor("#330066")); + canvas.drawText("You are the Purple and White Chicken", WIDTH / 4, HEIGHT / 4 - textPaint.getTextSize(), textPaint); + + textPaint.setColor(Color.parseColor("#FF9900")); + canvas.drawText("Tap the Screen to Start", WIDTH / 4, HEIGHT / 4, textPaint); + canvas.drawText("Tap the Screen to Jump and Flap", WIDTH / 4, HEIGHT / 4 + textPaint.getTextSize(), textPaint); + + textPaint.setColor(Color.parseColor("#FF0000")); + canvas.drawText("Don't fall into the lava!", WIDTH / 4, HEIGHT * 3 / 4, textPaint); + } + } + + public void endGame(){ + // Stop the game, save, then reset the game + chicken.setPlaying(false); + saveScore(chickenScoreKey, chicken.getScore()); + + resetPlatforms(); + enemies = new ArrayList<>(); + chicken = new Chicken(chickenBitmap, chickenWidth, chickenHeight, chickenFrames); + } + + @Override + public void update() { + super.update(); + + if (chicken.isPlaying()) { + background.update(gameSpeed); + if (higherQualityEnabled) { + clouds.update(cloudsSpeed); + lava.update(lavaSpeed); + } + + // Remove old platforms + for (int i = 0; i < platforms.size(); i++) { + Platform platform = platforms.get(i); + + platform.update(gameSpeed); + + if (platform.x + platform.width < 0) { + platforms.remove(platform); + i--; + } + } + + // Add new platform(s) if the last platform is already being displayed + // Check where the last platform left off + boolean createPlatforms = true; + int lastPlatformEndX = 0; + for (Platform platform : platforms) { + if (platform.x > WIDTH) { + createPlatforms = false; + break; + } else { + lastPlatformEndX = platform.x + platform.width; + } + } + + if (createPlatforms && !thread.markerFrame) { + // Get X + int newPlatformX; + // Chance of a gap + boolean createGap = ((int) (Math.random() * 100) > 69); + if (createGap) { + newPlatformX = lastPlatformEndX + (int) (Math.random() * maxGapSize); + } else { + newPlatformX = lastPlatformEndX; + } + + // Get Y + int newPlatformY = platformDefaultY - ((int) (platformHeight * Math.random())) / (chickenHeight * 2); + + // Add the platform + platforms.add(new Platform(platformBitmap, platformWidth, platformHeight, newPlatformX, newPlatformY)); + } + + // Check if we fell in a hole + if (chicken.y > HEIGHT) { + endGame(); + } + + // Refresh enemies array + boolean enemyOnTop = false; + for (int i = 0; i < enemies.size() && i >= 0; i++) { + Enemy enemy = enemies.get(i); + + Log.d(TAG, "ChickenGameView.update(): enemy.getBottomY()=" + enemy.getBottomY()); + // Check if we hit an enemy + if (chicken.getRect().intersect(enemy.getRect())) { + endGame(); + break; + } + // Check if enemy is off the screen + else if (enemy.getEndX() <= 0) { + enemies.remove(enemy); + i--; + } + // Verify there is still an enemy on top + else { + if (enemy.y < chickenHeight) { + enemyOnTop = true; + } + } + } + Log.d(TAG, "ChickenGameView.update(): enemyOnTop=" + enemyOnTop); + + // Always prioritize an enemy on the top, else create normal enemies above all the platforms + if (!thread.markerFrame) { + if (!enemyOnTop) { + int enemyY = (int) (chickenHeight * Math.random()); + enemies.add(new Enemy(enemyBitmap, enemyWidth, enemyHeight, enemyFrames, WIDTH, enemyY, enemySpeed, 1)); + } + else if ((chicken.getScore() / 25) > enemies.size()) { + int newEnemyHeight = HEIGHT; + + // Make sure the enemy is always above the platforms + for (Platform platform : platforms) { + if (platform.y < newEnemyHeight) { + newEnemyHeight = platform.y; + } + } + newEnemyHeight -= enemyHeight * 2; + newEnemyHeight = (int) (newEnemyHeight * Math.random()); + enemies.add(new Enemy(enemyBitmap, enemyWidth, enemyHeight, enemyFrames, WIDTH, newEnemyHeight, enemySpeed, 1)); + } + } + + for (Enemy enemy : enemies){ + enemy.update(); + } + + chicken.update(findPlatformY(chicken, platforms)); + } + } + + @Override + public void draw(Canvas canvas) { + + if (canvas != null) { + super.draw(canvas); + final float scaleX = (float) getWidth() / WIDTH; + final float scaleY = (float) getHeight() / HEIGHT; + + Log.d(TAG, "GameView.draw(): Canvas not null, scaling! scaleX=" + scaleX + ", scaleY=" + scaleY); + Log.d(TAG, "GameView.draw(): Canvas not null, scaling! getScaleX()=" + getScaleX() + ", getScaleY()=" + getScaleY()); + + final int savedState = canvas.save(); + canvas.scale(scaleX, scaleY); + + // Draw all the game's objects + if (higherQualityEnabled) { + clouds.draw(canvas); + } + + background.draw(canvas); + + if (higherQualityEnabled) { + lava.draw(canvas); + } + + for (Platform platform : platforms) { + platform.draw(canvas); + } + + for (Enemy enemy : enemies){ + enemy.draw(canvas); + } + + displayScore(canvas); + + chicken.draw(canvas); + + // Prevent canvas from infinite scaling + canvas.restoreToCount(savedState); + } + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/Enemy.java b/app/src/main/java/com/hyperling/apps/games/Enemy.java new file mode 100755 index 0000000..73f331c --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/Enemy.java @@ -0,0 +1,72 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; +import android.graphics.Canvas; + +/** + * Created by ling on 12/26/16. + */ + +public class Enemy extends GameObject { + + protected Bitmap image; + + private Animation animation; + + private int speed, damage; + + public Enemy(Bitmap b, int w, int h, int numFrames, int x, int y, int speed, int damage){ + image = b; + width = w; + height = h; + this.x = x; + this.y = y; + this.speed = speed; + this.damage = damage; + + if (speed > -1){ + speed = -1; + } + if (this.y >= GameView.HEIGHT - this.height){ + this.y = GameView.HEIGHT - this.height; + } + + // Create animation + Bitmap[] image = new Bitmap[numFrames]; + animation = new Animation(); + + for (int i = 0; i < numFrames; i++){ + image[i] = Bitmap.createBitmap(b, width * i, 0, width, height); + } + + animation.setFrames(image); + + //animation.setDelay(100); + int delay = 25 * Math.abs(speed); + if (delay > 125){ + delay = 125; + } + else if (delay < 75){ + delay = 75; + } + animation.setDelay(delay); + animation.setCurrentFrame((int)(Math.random() * numFrames)); + } + + public void update(){ + animation.update(); + + // Move the object + x += speed; + super.updateEdgeLocations(); + } + + public void draw(Canvas canvas) { + // Draw the object + canvas.drawBitmap(animation.getImage(), getX(), getY(), null); + } + + public int getDamage() { + return damage; + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/EnvironmentObject.java b/app/src/main/java/com/hyperling/apps/games/EnvironmentObject.java new file mode 100755 index 0000000..96acca9 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/EnvironmentObject.java @@ -0,0 +1,34 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; +import android.graphics.Canvas; + +/** + * Created by ling on 12/23/16. + */ + +public abstract class EnvironmentObject extends GameObject { + + protected Bitmap image; + + public EnvironmentObject(Bitmap i, int w, int h, int x, int y){ + image = i; + width = w; + height = h; + this.x = x; + this.y = y; + } + + public void update(int gameSpeed){ + // Move the object + x += gameSpeed; + + setEndX(getX() + getWidth()); + setCenterX((getX() + getEndX()) / 2); + } + + public void draw(Canvas canvas) { + // Draw the object + canvas.drawBitmap(image, x, y, null); + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/ExtraLife.java b/app/src/main/java/com/hyperling/apps/games/ExtraLife.java new file mode 100755 index 0000000..f9c2178 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/ExtraLife.java @@ -0,0 +1,25 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; + +/** + * Created by ling on 12/26/16. + */ + +public class ExtraLife extends EnvironmentObject { + + private int numLives; + + public ExtraLife(Bitmap b, int w, int h, int x, int y, int numLives){ + super(b, w, h, x, y); + this.numLives = numLives; + + if (this.y >= GameView.HEIGHT - this.height){ + this.y = GameView.HEIGHT - this.height; + } + } + + public int getNumLives() { + return numLives; + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/GameActivity.java b/app/src/main/java/com/hyperling/apps/games/GameActivity.java new file mode 100755 index 0000000..96edaa1 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/GameActivity.java @@ -0,0 +1,56 @@ +package com.hyperling.apps.games; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.Window; +import android.view.WindowManager; + +/** + * Created by ling on 12/17/16. + */ + +public class GameActivity extends AppCompatActivity { + + BirdGameView birdGameView; + ChickenGameView chickenGameView; + + private String gameType, birdGame, cowGame, pigGame, chickenGame, catGame; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN); + + gameType = GameActivity.this.getIntent().getAction(); + + // Game types + birdGame = getString(R.string.btnGameBird); + cowGame = getString(R.string.btnGameCow); + pigGame = getString(R.string.btnGamePig); + chickenGame = getString(R.string.btnGameChicken); + catGame = getString(R.string.btnGameCat); + + if (gameType.equals(birdGame)) { + birdGameView = new BirdGameView(GameActivity.this); + setContentView(birdGameView); + } + else if (gameType.equals(chickenGame)) { + chickenGameView = new ChickenGameView(GameActivity.this); + setContentView(chickenGameView); + } + } + + @Override + protected void onPause() { + + if (gameType.equals(birdGame)) { + birdGameView.pauseGame(); + } + else if (gameType.equals(chickenGame)) { + chickenGameView.pauseGame(); + } + super.onPause(); + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/GameBackground.java b/app/src/main/java/com/hyperling/apps/games/GameBackground.java new file mode 100755 index 0000000..965692d --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/GameBackground.java @@ -0,0 +1,44 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; +import android.graphics.Canvas; + +/** + * Created by ling on 12/17/16. + */ + +public class GameBackground { + + private Bitmap image; + private int x, y; + + public GameBackground(Bitmap i){ + image = i; + } + + public void update(int gameSpeed){ + // Move the background + x += gameSpeed; + + // If the image is completely off the screen, put it back to the middle. + if (x <= -GameView.WIDTH || x >= GameView.WIDTH){ + x = 0; + } + } + + public void draw(Canvas canvas){ + // Draw the current image + canvas.drawBitmap(image, x, y, null); + + // Place two more to the right since we are to the left + if (x < 0){ + canvas.drawBitmap(image, x + GameView.WIDTH, y, null); + //canvas.drawBitmap(image, x + (2 * GameView.WIDTH), y, null); + } + // Place two more to the left since we are to the right + else if (x > 0){ + canvas.drawBitmap(image, x - GameView.WIDTH, y, null); + //canvas.drawBitmap(image, x - (2 * GameView.WIDTH), y, null); + } + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/GameLoopThread.java b/app/src/main/java/com/hyperling/apps/games/GameLoopThread.java new file mode 100755 index 0000000..0ff1e13 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/GameLoopThread.java @@ -0,0 +1,101 @@ +package com.hyperling.apps.games; + +import android.graphics.Canvas; +import android.util.Log; +import android.view.SurfaceHolder; + +/** + * Created by ling on 12/17/16. + */ + +public class GameLoopThread extends Thread { + private final int FPS = 30; + protected double averageFPS; + private SurfaceHolder surfaceHolder; + private GameView gameView; + private boolean running; + public static Canvas canvas; + + public boolean markerFrame; + + private String TAG; + + public GameLoopThread(SurfaceHolder sh, GameView gv){ + super(); + surfaceHolder = sh; + gameView = gv; + + TAG = gameView.getResources().getString(R.string.TAG); + + markerFrame = false; + } + + @Override + public void run() { + super.run(); + + long timeStart, timeRun, timeWait, timeTotal, timeTarget; + timeTotal = 0; + timeTarget = 1000/FPS; + + int frameCount = 0; + + while(running){ + timeStart = System.currentTimeMillis(); + canvas = null; + + try{ + canvas = this.surfaceHolder.lockCanvas(); + synchronized (surfaceHolder){ + this.gameView.update(); + this.gameView.draw(canvas); + } + } catch(Exception e){ + e.printStackTrace(); + } finally { + if (canvas != null) { + try { + surfaceHolder.unlockCanvasAndPost(canvas); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + timeRun = (System.currentTimeMillis() - timeStart); + timeWait = timeTarget - timeRun; + + if (timeWait > 0) { + try { + this.sleep(timeWait); + } catch (Exception e) { + e.printStackTrace(); + } + } + + timeTotal += System.currentTimeMillis()-timeStart; + frameCount++; + if (frameCount >= FPS){ + averageFPS = 1000/((timeTotal/frameCount)); + frameCount = 0; + timeTotal = 0; + + Log.i(TAG, "GameLoopThread.run(): averageFPS=" + averageFPS); + Log.d(TAG, "GameLoopThread.run(): canvas.getHeight()=" + canvas.getHeight() + ", canvas.getWidth()=" + canvas.getWidth()); + + markerFrame = true; + } + else{ + markerFrame = false; + } + } + } + + public void setRunning(boolean r){ + running = r; + + if (running) { + this.start(); + } + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/GameObject.java b/app/src/main/java/com/hyperling/apps/games/GameObject.java new file mode 100755 index 0000000..d39e4d9 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/GameObject.java @@ -0,0 +1,116 @@ +package com.hyperling.apps.games; + +import android.graphics.Rect; + +/** + * Created by ling on 12/22/16. + * https://youtu.be/kGqKNpk6VJw?list=PLWweaDaGRHjvQlpLV0yZDmRKVBdy6rSlg + */ + +public abstract class GameObject { + protected int x; + protected int y; + protected int dx; + protected int dy; + protected int width; + protected int height; + + protected int centerX; + protected int endX; + + protected int centerY; + protected int bottomY; + + public int getX() { + return x; + } + + public void setX(int x) { + this.x = x; + } + + public int getY() { + return y; + } + + public void setY(int y) { + this.y = y; + } + + public int getDx() { + return dx; + } + + public void setDx(int dx) { + this.dx = dx; + } + + public int getDy() { + return dy; + } + + public void setDy(int dy) { + this.dy = dy; + } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } + + public int getCenterX() { + return centerX; + } + + public void setCenterX(int centerX) { + this.centerX = centerX; + } + + public int getEndX() { + return endX; + } + + public void setEndX(int endX) { + this.endX = endX; + } + + public int getCenterY() { + return centerY; + } + + public void setCenterY(int centerY) { + this.centerY = centerY; + } + + public int getBottomY() { + return bottomY; + } + + public void setBottomY(int bottomY) { + this.bottomY = bottomY; + } + + public void updateEdgeLocations(){ + endX = x + width; + bottomY = y + height; + + centerX = (x + endX) / 2; + centerY = (y + bottomY) / 2; + } + + public Rect getRect(){ + return new Rect(x, y, x + width, y + height); + } + +} diff --git a/app/src/main/java/com/hyperling/apps/games/GameView.java b/app/src/main/java/com/hyperling/apps/games/GameView.java new file mode 100755 index 0000000..f5c4c92 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/GameView.java @@ -0,0 +1,203 @@ +package com.hyperling.apps.games; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.text.TextPaint; +import android.util.Log; +import android.view.MotionEvent; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import java.util.ArrayList; + +/** + * Created by ling on 12/17/16. + * https://youtu.be/-XOMJYZmfkw?list=PLWweaDaGRHjvQlpLV0yZDmRKVBdy6rSlg + */ + +public abstract class GameView extends SurfaceView implements SurfaceHolder.Callback{ + + public static final int WIDTH = 640; + public static final int HEIGHT = 400; + + protected Resources resources; + protected final String sharedPreferencesKey, higherQualityKey, fpsKey; + + protected static String TAG; + + protected SharedPreferences sharedPreferences; + protected boolean higherQualityEnabled, fpsEnabled; + + protected int gameSpeed = -5; + protected int boostQty; + protected long boostEnd; + protected boolean boosting; + + protected GameLoopThread thread; + protected GameBackground background, clouds, lava; + + protected TextPaint textPaint; + + public GameView(Context context){ + super(context); + + // For filling strings and getting Bitmaps + resources = getResources(); + + // Keys + sharedPreferencesKey = resources.getString(R.string.sharedPreferencesKey); + higherQualityKey = resources.getString(R.string.higherQualityKey); + fpsKey = resources.getString(R.string.fpsKey); + + // Initialize shared preferences + sharedPreferences = context.getSharedPreferences(sharedPreferencesKey, Context.MODE_PRIVATE); + higherQualityEnabled = sharedPreferences.getBoolean(higherQualityKey, false); + fpsEnabled = sharedPreferences.getBoolean(fpsKey, false); + + // For output + TAG = resources.getString(R.string.TAG); + + // Add the callback to SurfaceHolder (This allows control of events) + getHolder().addCallback(this); + + // Initialize engine + thread = new GameLoopThread(getHolder(), this); + } + + protected static String getTAG() { + return TAG; + } + + protected void boost(int boostMultiplier, long boostDuration){ + if (!boosting){ + boosting = true; + boostQty = boostMultiplier; + boostEnd = System.currentTimeMillis() + boostDuration; + + gameSpeed *= boostQty; + } + } + + protected void setGameSpeed(int newSpeed){ + gameSpeed = newSpeed; + } + + protected int findPlatformY(Player player, ArrayList platforms){ + + // Get the tallest (smallest) platform.y where platform.y < player.y + int platformHighestY = HEIGHT*2; + for (Platform platform : platforms){ + + if (player.endX > platform.x && + player.x < platform.endX && + player.centerY <= platform.y && + platform.y < platformHighestY){ + Log.d(TAG, "GameView.findPlatformY():" + + " player.x=" + player.x + + ", player.endX=" + player.endX + + ", player.centerY=" + player.centerY + + ", platform.x=" + platform.x + + ", platform.endX=" + platform.endX + + ", platform.y=" + platform.y + + ", platformHighestY=" + platformHighestY); + + platformHighestY = platform.y; + } + } + + Log.d(TAG, "GameView.findPlatformY(): player.y=" + player.y + ", platformHighestY=" + platformHighestY); + return platformHighestY; + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + // Safe to start the thread + textPaint = new TextPaint(); + textPaint.setTextSize(textPaint.getTextSize() * 2); + + thread.setRunning(true); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + // Try to stop the thread + boolean retry = true; + int retryCount = 0; + while(retry && retryCount < 1000){ + try{ + thread.setRunning(false); + thread.join(); + thread = null; + retry = false; + } catch(Exception e){ + e.printStackTrace(); + retryCount++; + } + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); + } + + protected void pauseGame(String scoreKey, int score){ + // Save and force a commit + saveScore(scoreKey, score); + sharedPreferences.edit().commit(); + + System.exit(1); + } + + protected void saveScore(String scoreKey, int score){ + // Check if score is better than high score + int oldScore = sharedPreferences.getInt(scoreKey, 0); + Log.d(TAG, "GameView.saveScore(): score=" + score + ", oldScore=" + oldScore); + + if (score > oldScore) { + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putInt(scoreKey, score); + editor.apply(); + } + + int highScore = sharedPreferences.getInt(scoreKey, 0); + Log.d(TAG, "GameView.saveScore(): Saved, new highScore=" + highScore); + } + + protected void update(){ + // Check if the boost is over and end it + if (boosting && System.currentTimeMillis() > boostEnd){ + boosting = false; + gameSpeed /= boostQty; + } + } + + @Override + public void draw(Canvas canvas) { + + if (canvas != null) { + super.draw(canvas); + /* + final float scaleX = (float) getWidth()/WIDTH; + final float scaleY = (float) getHeight()/HEIGHT; + Log.d(TAG, "GameView.draw(): Canvas not null, scaling! scaleX=" + scaleX + ", scaleY=" + scaleY); + Log.d(TAG, "GameView.draw(): Canvas not null, scaling! getScaleX()=" + getScaleX() + ", getScaleY()=" + getScaleY()); + final int savedState = canvas.save(); + canvas.scale(scaleX, scaleY); + + // Draw all the game's objects + background.draw(canvas); + + // Prevent canvas from infinite scaling + canvas.restoreToCount(savedState); + */ + } + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/HighScoreActivity.java b/app/src/main/java/com/hyperling/apps/games/HighScoreActivity.java new file mode 100755 index 0000000..801e643 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/HighScoreActivity.java @@ -0,0 +1,127 @@ +package com.hyperling.apps.games; + +import android.content.SharedPreferences; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.util.Log; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.google.android.gms.ads.AdView; + +public class HighScoreActivity extends AppCompatActivity { + + private String sharedPreferencesKey, adsKey, TAG, html; + private String[] allBirdScoreKeys, allChickenScoreKeys; + + private SharedPreferences sharedPreferences; + + LeaderboardHelper leaderboardHelper; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_high_score); + + TAG = getString(R.string.TAG); + + // Get keys + sharedPreferencesKey = getString(R.string.sharedPreferencesKey); + allBirdScoreKeys = getResources().getStringArray(R.array.allBirdScoreKeys); + allChickenScoreKeys = getResources().getStringArray(R.array.allChickenScoreKeys); + adsKey = getString(R.string.adsKey); + + // Shared preferences + sharedPreferences = getSharedPreferences(sharedPreferencesKey, MODE_PRIVATE); + + // Bird stuff + LinearLayout birdScoreLayout = (LinearLayout) findViewById(R.id.birdScoreLayout); + loadScoreLayout(birdScoreLayout, allBirdScoreKeys); + + // Chicken stuff + LinearLayout chickenScoreLayout = (LinearLayout) findViewById(R.id.chickenScoreLayout); + loadScoreLayout(chickenScoreLayout, allChickenScoreKeys); + } + + private void loadScoreLayout(LinearLayout layout, String[] scoreKeys){ + + for (String key : scoreKeys){ + int score = sharedPreferences.getInt(key, 0); + if (score > 0){ + String label = key; + // Add spaces to string before uppercase and numbers + label = label.replaceAll(" ", ""); + //label = label.replaceAll("0", ""); + for (int i = 1; i < label.length(); i++){ + if (label.charAt(i) == label.toUpperCase().charAt(i) || isNumeric(label.charAt(i))){ + label = label.substring(0, i) + " " + label.substring(i); + i++; + if (isNumeric(label.charAt(i))){ + label = label.substring(0, i) + "- Version " + label.substring(i); + break; + } + } + } + + label = label.concat(": "); + String scoreString = "" + score; + + // Create UI Objects + LinearLayout linearLayout = new LinearLayout(this); + TextView tvLabel = new TextView(this); + TextView tvScore = new TextView(this); + + // Set their text + tvLabel.setText(label); + tvScore.setText(scoreString); + + // Finish the layout + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + linearLayout.addView(tvLabel); + linearLayout.addView(tvScore); + + // Add score to layout + layout.addView(linearLayout); + } + } + } + + @Override + protected void onResume() { + leaderboardHelper = new LeaderboardHelper(); + displayAds(); + super.onResume(); + + Runnable getHTML = new Runnable() { + @Override + public void run() { + html = leaderboardHelper.getTable("BirdScore009"); + Log.d(TAG, "HighScoreActivity.onResume(): html=" + html); + } + }; + + Thread t = new Thread(getHTML); + t.start(); + + Log.d(TAG, "HighScoreActivity.onResume() html=" + html); + } + + private void displayAds(){ + AdsHelper.toggleAds(sharedPreferences, adsKey, getApplicationContext(), (AdView) findViewById(R.id.adViewHighScores)); + } + + private boolean isNumeric(char c){ + try{ + String s = "" + c; + int i = Integer.parseInt(s); + if (i >= 0) { + return true; + } + } + catch (Exception e){ + //e.printStackTrace(); + } + + return false; + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/LeaderboardHelper.java b/app/src/main/java/com/hyperling/apps/games/LeaderboardHelper.java new file mode 100755 index 0000000..ed65e27 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/LeaderboardHelper.java @@ -0,0 +1,69 @@ +package com.hyperling.apps.games; + +import android.util.Log; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; + +/** + * Created by ling on 1/3/17. + * Get Unique Device ID: http://stackoverflow.com/questions/16869482/how-to-get-unique-device-hardware-id-in-android#16869491 + */ + +public class LeaderboardHelper { + + private final String baseURL = "https://hyperling.com:1337/hyper_games/"; + private String getVariables = ""; + + + + public void addVariable(String key, String value){ + if (getVariables.length() == 0) { + getVariables += "?"; + } + else{ + getVariables += "&"; + } + + getVariables += key + "=" + value; + } + + public void clearVariables(){ + getVariables = ""; + } + + public String getTable(String id){ + String newURL = baseURL + "?leaderboard_id=" + id; + String html = ""; + + URL url; + InputStream is = null; + BufferedReader br; + String line; + + try { + url = new URL(newURL); + is = url.openStream(); // throws an IOException + br = new BufferedReader(new InputStreamReader(is)); + + while ((line = br.readLine()) != null) { + html = html.concat(line); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (is != null) is.close(); + } catch (IOException ioe) { + // nothing to see here + } + } + + return html; + + } + +} diff --git a/app/src/main/java/com/hyperling/apps/games/MainActivity.java b/app/src/main/java/com/hyperling/apps/games/MainActivity.java new file mode 100755 index 0000000..3d8a97d --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/MainActivity.java @@ -0,0 +1,171 @@ +package com.hyperling.apps.games; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; + +import com.google.android.gms.ads.AdView; + +public class MainActivity extends AppCompatActivity { + + private Button btnGameBird, btnGameCow, btnGamePig, btnGameChicken, btnGameCat, btnGameSquirrel, btnOptions, btnHighScores, btnHelp; + + private String TAG, sharedPreferencesKey, adsKey, birdScoreKey, chickenScoreKey; + + private SharedPreferences sharedPreferences; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + + TAG = getString(R.string.TAG); + + // Keys + sharedPreferencesKey = getString(R.string.sharedPreferencesKey); + adsKey = getString(R.string.adsKey); + birdScoreKey = getString(R.string.birdScoreKey); + chickenScoreKey = getString(R.string.chickenScoreKey); + + // Shared Preferences + sharedPreferences = getSharedPreferences(sharedPreferencesKey, MODE_PRIVATE); + + // Initialize buttons + btnGameBird = (Button) findViewById(R.id.btnBirdGame); + btnGameCow = (Button) findViewById(R.id.btnGameCow); + btnGamePig = (Button) findViewById(R.id.btnGamePig); + btnGameChicken = (Button) findViewById(R.id.btnGameChicken); + btnGameCat = (Button) findViewById(R.id.btnGameCat); + btnGameSquirrel = (Button) findViewById(R.id.btnGameSquirrel); + btnOptions = (Button) findViewById(R.id.btnOptions); + btnHighScores = (Button) findViewById(R.id.btnHighScores); + btnHelp = (Button) findViewById(R.id.btnHelp); + + // Set up game buttons + btnGameBird.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doGameButton((Button) v); + } + }); + btnGameCow.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doGameButton((Button) v); + } + }); + btnGamePig.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doGameButton((Button) v); + } + }); + btnGameChicken.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doGameButton((Button) v); + } + }); + btnGameCat.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doGameButton((Button) v); + } + }); + btnGameSquirrel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doGameButton((Button) v); + } + }); + + // Set up other buttons + btnOptions.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doOptionsButton(); + } + }); + btnHighScores.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + doHighScoresButton(); + } + }); + } + + @Override + protected void onResume() { + displayAds(); + + // Append high scores to button text + int score; + String newText; + + score = sharedPreferences.getInt(birdScoreKey, 0); + Log.d(TAG, "MainActivity.onResume(): birdScore=" + score); + if (score > 0) { + newText = getString(R.string.btnGameBird) + '\n' + getString(R.string.btnHighScoreSubHeader).concat(" ") + score; + Log.d(TAG, "MainActivity.onResume(): newText=" + newText); + btnGameBird.setText(newText); + } + else{ + btnGameBird.setText(getString(R.string.btnGameBird)); + } + + score = sharedPreferences.getInt(chickenScoreKey, 0); + if (score > 0) { + newText = getString(R.string.btnGameChicken) + '\n' + getString(R.string.btnHighScoreSubHeader).concat(" ") + score; + Log.d(TAG, "MainActivity.onResume(): newText=" + newText); + btnGameChicken.setText(newText); + } + else{ + btnGameChicken.setText(getString(R.string.btnGameChicken)); + } + + super.onResume(); + } + + // Start the game + private void doGameButton(Button b){ + Log.i(TAG, "MainActivity.doCowGameButton()"); + + // Only get the game name, not the high score + String gameType, buttonText; + buttonText = b.getText().toString(); + int newLine = buttonText.indexOf('\n'); + if (newLine > 0) { + gameType = buttonText.substring(0, buttonText.indexOf('\n')); + } + else{ + gameType = buttonText; + } + + // Start the GameActivity + Intent game = new Intent(MainActivity.this, GameActivity.class); + game.setAction(gameType); + startActivity(game); + } + + // Go to OptionsActivity + private void doOptionsButton(){ + Log.i(TAG, "MainActivity.doOptionsButton()"); + + Intent options = new Intent(MainActivity.this, OptionsActivity.class); + startActivity(options); + } + + private void displayAds(){ + AdsHelper.toggleAds(sharedPreferences, adsKey, getApplicationContext(), (AdView) findViewById(R.id.adViewMain)); + } + + private void doHighScoresButton(){ + Intent highScores = new Intent(MainActivity.this, HighScoreActivity.class); + startActivity(highScores); + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/OptionsActivity.java b/app/src/main/java/com/hyperling/apps/games/OptionsActivity.java new file mode 100755 index 0000000..0268411 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/OptionsActivity.java @@ -0,0 +1,187 @@ +package com.hyperling.apps.games; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.RelativeLayout; + +import com.google.android.gms.ads.AdRequest; +import com.google.android.gms.ads.AdView; +import com.google.android.gms.ads.MobileAds; + +/** + * Created by ling on 12/22/16. + */ + +public class OptionsActivity extends AppCompatActivity { + + private String sharedPreferencesKey, adsKey, higherQualityKey, fpsKey; + + private SharedPreferences sharedPreferences; + + private RelativeLayout layoutAds, layoutHigherQuality, layoutFPS; + private CheckBox cbAds, cbHigherQuality, cbFPS; + private boolean adsEnabled, higherQualityEnabled, fpsEnabled; + + private Button btnDeletePreferences, btnConfirmDeletePreferences; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_options); + + // Prevent the keyboard from popping up automatically + this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); + + // Get SharedPreferences + sharedPreferencesKey = getString(R.string.sharedPreferencesKey); + sharedPreferences = getSharedPreferences(sharedPreferencesKey, MODE_PRIVATE); + + // Set up Ads + adsKey = getString(R.string.adsKey); + layoutAds = (RelativeLayout) findViewById(R.id.optionAdsLayout); + cbAds = (CheckBox) findViewById(R.id.optionAdsCheckBox); + layoutAds.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + flipOption(adsKey); + } + }); + cbAds.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + flipOption(adsKey); + } + }); + setAds(); + + // Higher Quality Content + higherQualityKey = getString(R.string.higherQualityKey); + layoutHigherQuality = (RelativeLayout) findViewById(R.id.optionHigherQualityLayout); + cbHigherQuality = (CheckBox) findViewById(R.id.optionHigherQualityCheckBox); + layoutHigherQuality.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + flipOption(higherQualityKey); + } + }); + cbHigherQuality.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + flipOption(higherQualityKey); + } + }); + setHigherQuality(); + + // In-Game FPS + fpsKey = getString(R.string.fpsKey); + layoutFPS = (RelativeLayout) findViewById(R.id.optionFPSLayout); + cbFPS = (CheckBox) findViewById(R.id.fpsCheckBox); + layoutFPS.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + flipOption(fpsKey); + } + }); + cbFPS.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + flipOption(fpsKey); + } + }); + setFPS(); + + // Reset buttons + btnDeletePreferences = (Button) findViewById(R.id.btnDeletePreferences); + btnConfirmDeletePreferences = (Button) findViewById(R.id.btnConfirmDeletePreferences); + + btnDeletePreferences.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showConfirmDeletePreferencesButton((Button) v); + } + }); + btnConfirmDeletePreferences.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + deletePreferences(); + } + }); + } + + private void flipOption(String key){ + boolean option = sharedPreferences.getBoolean(key, false); + + // Save the setting + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putBoolean(key, !option); + editor.apply(); + + // Change the box + if (key.equals(adsKey)){ + setAds(); + } + else if (key.equals(higherQualityKey)){ + setHigherQuality(); + } + else if (key.equals(fpsKey)){ + setFPS(); + } + } + + private void setAds(){ + adsEnabled = sharedPreferences.getBoolean(adsKey, false); + cbAds.setChecked(adsEnabled); + toggleAds(); + } + + private void toggleAds(){ + // Enable ads? + adsEnabled = sharedPreferences.getBoolean(adsKey, false); + AdView mAdView = (AdView) findViewById(R.id.adViewOptions); + if (adsEnabled) { + mAdView.setVisibility(View.VISIBLE); + MobileAds.initialize(getApplicationContext(), "ca-app-pub-3940256099942544~3347511713"); + AdRequest adRequest = new AdRequest.Builder() + .addTestDevice(AdRequest.DEVICE_ID_EMULATOR) + .addTestDevice("C6A494DC6E7C9AC29102694D48487084") // Nexus 7 + .addTestDevice("6545BCC9B60A394005546783687339B7") // Moto G + .build(); + mAdView.loadAd(adRequest); + } + else{ + mAdView.setVisibility(View.GONE); + } + } + + public void setHigherQuality() { + higherQualityEnabled = sharedPreferences.getBoolean(higherQualityKey, false); + cbHigherQuality.setChecked(higherQualityEnabled); + } + + public void setFPS() { + fpsEnabled = sharedPreferences.getBoolean(fpsKey, false); + cbFPS.setChecked(fpsEnabled); + } + + private void showConfirmDeletePreferencesButton(Button callButton){ + callButton.setEnabled(false); + btnConfirmDeletePreferences.setVisibility(View.VISIBLE); + btnConfirmDeletePreferences.setEnabled(true); + } + + private void deletePreferences(){ + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.clear(); + editor.apply(); + + Intent resetScreen = new Intent(OptionsActivity.this, OptionsActivity.class); + startActivity(resetScreen); + finish(); + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/Platform.java b/app/src/main/java/com/hyperling/apps/games/Platform.java new file mode 100755 index 0000000..0b5686b --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/Platform.java @@ -0,0 +1,19 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; + +/** + * Created by ling on 12/23/16. + */ + +public class Platform extends EnvironmentObject { + + public Platform(Bitmap b, int w, int h, int x, int y){ + super(b, w, h, x, y); + } + + @Override + public void update(int gameSpeed) { + super.update(gameSpeed); + } +} diff --git a/app/src/main/java/com/hyperling/apps/games/Player.java b/app/src/main/java/com/hyperling/apps/games/Player.java new file mode 100755 index 0000000..c198458 --- /dev/null +++ b/app/src/main/java/com/hyperling/apps/games/Player.java @@ -0,0 +1,155 @@ +package com.hyperling.apps.games; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.util.Log; + +/** + * Created by ling on 12/22/16. + */ + +public abstract class Player extends GameObject { + + private String TAG; + + //private Bitmap spritesheet; + private int score; + + //private boolean up, down, left, right, sprint; + private boolean playing; + private Animation animation; + private long startTime; + + public Player(Bitmap b, int w, int h, int numFrames){ + TAG = GameView.getTAG(); + + setX(GameView.WIDTH/5); + setY(GameView.HEIGHT/2); + setDx(0); + setDy(0); + + score = 0; + + setWidth(w); + setHeight(h); + + Bitmap[] image = new Bitmap[numFrames]; + animation = new Animation(); + + for (int i = 0; i < numFrames; i++){ + image[i] = Bitmap.createBitmap(b, width * i, 0, width, height); + } + + animation.setFrames(image); + animation.setDelay(100); + startTime = System.currentTimeMillis(); + } + + public Player(){ + super(); + } + + /* + public void setUp(boolean b){ + up = b; + } + + public void setDown(boolean b){ + down = b; + } + + public void setLeft(boolean b){ + left = b; + } + + public void setRight(boolean b){ + right = b; + } + + public void setSprint(boolean b){ + sprint = b; + } + */ + + public boolean isPlaying(){ + return playing; + } + + public void setPlaying(boolean p){ + playing = p; + } + + public int getScore() { + return score; + } + + public void update(){ + animation.update(); + + long elapsed = (System.currentTimeMillis() - startTime); + if (elapsed > 100){ + score++; + startTime = System.currentTimeMillis(); + } + + /* Specific animals should override this + if (left){ + dx = Math.abs(dx) * -1; + } + else if (right){ + dx = Math.abs(dx); + } + + if (sprint){ + dx *= 2; + } + + if (up){ + dy += -1; + } + else{ + dy += 2; + } + if (dy < -5){ + dy = -5; + } + if (dy > 10){ + dy = 10; + } + */ + + /* Character specific as well + // Only move when going up or have not hit the ground yet. + if (y < GameView.HEIGHT - getHeight() || dy < 0) { + y += dy; + } + // Do not leave bottom of map + else{ + y = GameView.HEIGHT - getHeight(); + dy = 0; + } + + // Do not leave top of map + if (y < 0){ + y = 0; + } + */ + + setEndX(getX() + getWidth()); + setCenterX((getX() + getEndX()) / 2); + + setBottomY(getY() + getHeight()); + setCenterY((getY() + getBottomY()) / 2); + + Log.d(TAG, "Player.update():" + + " score=" + score + + ", x=" + x + + ", dx=" + dx + + ", y=" + y + + ", dy=" + dy); + } + + public void draw(Canvas canvas){ + canvas.drawBitmap(animation.getImage(), getX(), getY(), null); + } +} diff --git a/app/src/main/res/drawable-nodpi/background_forest.png b/app/src/main/res/drawable-nodpi/background_forest.png new file mode 100755 index 0000000..550096a Binary files /dev/null and b/app/src/main/res/drawable-nodpi/background_forest.png differ diff --git a/app/src/main/res/drawable-nodpi/background_forest_with_lava.png b/app/src/main/res/drawable-nodpi/background_forest_with_lava.png new file mode 100755 index 0000000..9c7c8fe Binary files /dev/null and b/app/src/main/res/drawable-nodpi/background_forest_with_lava.png differ diff --git a/app/src/main/res/drawable-nodpi/background_forest_without_clouds.png b/app/src/main/res/drawable-nodpi/background_forest_without_clouds.png new file mode 100755 index 0000000..6a5c7a8 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/background_forest_without_clouds.png differ diff --git a/app/src/main/res/drawable-nodpi/banner.png b/app/src/main/res/drawable-nodpi/banner.png new file mode 100755 index 0000000..fb010d2 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/banner.png differ diff --git a/app/src/main/res/drawable-nodpi/bird.png b/app/src/main/res/drawable-nodpi/bird.png new file mode 100755 index 0000000..8a62f89 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/bird.png differ diff --git a/app/src/main/res/drawable-nodpi/bird_enemy.png b/app/src/main/res/drawable-nodpi/bird_enemy.png new file mode 100755 index 0000000..d9cd3e3 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/bird_enemy.png differ diff --git a/app/src/main/res/drawable-nodpi/bird_extra_life.png b/app/src/main/res/drawable-nodpi/bird_extra_life.png new file mode 100755 index 0000000..605d4f2 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/bird_extra_life.png differ diff --git a/app/src/main/res/drawable-nodpi/chicken.png b/app/src/main/res/drawable-nodpi/chicken.png new file mode 100755 index 0000000..5e846bc Binary files /dev/null and b/app/src/main/res/drawable-nodpi/chicken.png differ diff --git a/app/src/main/res/drawable-nodpi/clouds.png b/app/src/main/res/drawable-nodpi/clouds.png new file mode 100755 index 0000000..30444f6 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/clouds.png differ diff --git a/app/src/main/res/drawable-nodpi/enemy.png b/app/src/main/res/drawable-nodpi/enemy.png new file mode 100755 index 0000000..038e247 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/enemy.png differ diff --git a/app/src/main/res/drawable-nodpi/icon.png b/app/src/main/res/drawable-nodpi/icon.png new file mode 100755 index 0000000..965c520 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/icon.png differ diff --git a/app/src/main/res/drawable-nodpi/lava.png b/app/src/main/res/drawable-nodpi/lava.png new file mode 100755 index 0000000..a1e52a2 Binary files /dev/null and b/app/src/main/res/drawable-nodpi/lava.png differ diff --git a/app/src/main/res/drawable-nodpi/normal_platform.png b/app/src/main/res/drawable-nodpi/normal_platform.png new file mode 100755 index 0000000..1186bbf Binary files /dev/null and b/app/src/main/res/drawable-nodpi/normal_platform.png differ diff --git a/app/src/main/res/drawable-nodpi/test_player.png b/app/src/main/res/drawable-nodpi/test_player.png new file mode 100755 index 0000000..6a55c5a Binary files /dev/null and b/app/src/main/res/drawable-nodpi/test_player.png differ diff --git a/app/src/main/res/layout/activity_high_score.xml b/app/src/main/res/layout/activity_high_score.xml new file mode 100755 index 0000000..49c3c95 --- /dev/null +++ b/app/src/main/res/layout/activity_high_score.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100755 index 0000000..85eacc5 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,125 @@ + + + + + + + + + + + + + +