Last active
October 1, 2015 23:21
-
-
Save Powersaurus/533d4ab969ec934be8d2 to your computer and use it in GitHub Desktop.
Procedural hills with parallax scrolling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package com.powersaurus.landscape; | |
| import android.app.*; | |
| import android.os.*; | |
| import android.view.*; | |
| import android.widget.*; | |
| import android.content.pm.*; | |
| import android.util.*; | |
| import android.content.*; | |
| import android.graphics.*; | |
| import java.util.*; | |
| import android.view.View.*; | |
| public class MainActivity extends Activity { | |
| private static final int CHUNK_WIDTH = 400; | |
| private int screenWidth = 800; | |
| private int screenHeight = 480; | |
| @Override | |
| public void onCreate(Bundle savedInstanceState) { | |
| super.onCreate(savedInstanceState); | |
| hideAllAndroidUi(); | |
| storeScreenDimensions(); | |
| final LandscapeView landscapeView = new LandscapeView(this); | |
| setContentView(landscapeView); | |
| } | |
| private void storeScreenDimensions() { | |
| WindowManager wm = getWindowManager(); | |
| Display display = wm.getDefaultDisplay(); | |
| DisplayMetrics d = new DisplayMetrics(); | |
| display.getRealMetrics(d); | |
| screenWidth = d.widthPixels; | |
| screenHeight = d.heightPixels; | |
| } | |
| private void hideAllAndroidUi() { | |
| getWindow().setFlags( | |
| WindowManager.LayoutParams.FLAG_FULLSCREEN, | |
| WindowManager.LayoutParams.FLAG_FULLSCREEN); | |
| requestWindowFeature(Window.FEATURE_NO_TITLE); | |
| setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); | |
| getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); | |
| } | |
| private class Layer { | |
| public int x = 0; | |
| public Bitmap landscapeBmp = Bitmap.createBitmap(400, 240, Bitmap.Config.ARGB_8888); | |
| public Canvas bitmapCanvas = new Canvas(landscapeBmp); | |
| } | |
| private class LandscapeChunk { | |
| private int[] landscape = new int[CHUNK_WIDTH]; | |
| private Rect r = new Rect(); | |
| private Paint paint = new Paint(); | |
| private Layer[] layers = new Layer[5]; | |
| private int horizon = 80; | |
| private int var = 90; | |
| private float varDecay = 0.7f; | |
| private int colourIndex = 0; | |
| private int[] colours = new int[] { | |
| Color.rgb(140, 100, 150), | |
| Color.rgb(95, 80, 160), | |
| Color.rgb(90, 170, 85), | |
| Color.rgb(115, 195, 100), | |
| Color.rgb(160, 223, 100) | |
| }; | |
| private Random rand; | |
| private int x, y; | |
| public LandscapeChunk(Random rand, int x, int y) { | |
| this.rand = rand; | |
| this.x = x; | |
| this.y = y; | |
| } | |
| public void generateAll() { | |
| for (int j = 0; j < layers.length; j++) { | |
| layers[j] = new Layer(); | |
| layers[j].x = x; | |
| for (int i = 0; i < CHUNK_WIDTH; i++) { | |
| landscape[i] = 0; | |
| } | |
| landscape[0] = horizon; | |
| landscape[CHUNK_WIDTH - 1] = horizon; | |
| generateColumn((CHUNK_WIDTH - 1) / 2, 0, CHUNK_WIDTH - 1, var); | |
| horizon *= 1.23; | |
| var -= 10; | |
| varDecay -= 0.05; | |
| paint.setColor(colours[colourIndex]); | |
| colourIndex = (colourIndex + 1) % colours.length; | |
| Paint clearPaint = new Paint(); | |
| clearPaint.setColor(0); | |
| for (int y = 0; y < layers[j].bitmapCanvas.getHeight(); y++) { | |
| for (int x = 0; x < layers[j].bitmapCanvas.getWidth(); x++) { | |
| if (landscape[x] <= y) { | |
| layers[j].bitmapCanvas.drawPoint(x, y, paint); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| private void generateColumn(int pos, int left, int right, int variance) { | |
| if (variance > 0) { | |
| landscape[pos] = ((landscape[left] + landscape[right]) / 2) + (rand.nextInt(variance) - (variance / 2)); | |
| } else { | |
| landscape[pos] = (landscape[left] + landscape[right]) / 2; | |
| } | |
| if (pos != left && pos != right) { | |
| generateColumn((left + pos) / 2, left, pos, variance *= varDecay); | |
| generateColumn((pos + right) / 2, pos, right, variance *= varDecay); | |
| } | |
| } | |
| public void draw(int layerIndex, Canvas canvas, Paint paint) { | |
| Layer layer = layers[layerIndex]; | |
| layer.x += (1 + layerIndex); | |
| if (layer.x > screenWidth * 2) { | |
| layer.x -= (screenWidth * 3); | |
| } | |
| r.set(layer.x, y, layer.x + screenWidth, y + screenHeight); | |
| canvas.drawBitmap(layer.landscapeBmp, null, r, paint); | |
| } | |
| } | |
| private class LandscapeView extends View { | |
| private Random rand = new Random(); | |
| private Rect r = new Rect(); | |
| private Paint paint = new Paint(); | |
| private int skyColour = Color.argb(255, 70, 20, 210); | |
| private LandscapeChunk[] landscapeChunks = new LandscapeChunk[3]; | |
| private int chunksReady = 0; | |
| public LandscapeView(Context context) { | |
| super(context); | |
| for (int i = 0; i < landscapeChunks.length; i++) { | |
| final int index = i; | |
| new Thread(new Runnable() { | |
| public void run() { | |
| landscapeChunks[index] = new LandscapeChunk(rand, (index - 1)* screenWidth, 0); | |
| landscapeChunks[index].generateAll(); | |
| chunkReady(); | |
| } | |
| }).start(); | |
| } | |
| } | |
| private void chunkReady() { | |
| chunksReady++; | |
| } | |
| @Override | |
| protected void onDraw(Canvas canvas) { | |
| canvas.drawColor(skyColour); | |
| if (chunksReady < landscapeChunks.length) { | |
| drawLoadingScreen(canvas); | |
| } else { | |
| for (int layer = 0; layer < 5; layer++) { | |
| for (int i = 0; i < landscapeChunks.length; i++) { | |
| landscapeChunks[i].draw(layer, canvas, paint); | |
| } | |
| } | |
| } | |
| invalidate(); | |
| } | |
| private void drawLoadingScreen(Canvas canvas) { | |
| canvas.drawColor(Color.BLACK); | |
| paint.setColor(Color.GRAY); | |
| r.set(screenWidth / 2 - 90, screenHeight / 2 + 40, screenWidth / 2 + 90, screenHeight / 2 + 70); | |
| canvas.drawRect(r, paint); | |
| paint.setColor(Color.WHITE); | |
| float textWidth = paint.measureText("Loading"); | |
| canvas.drawText("Loading", screenWidth / 2 - (textWidth / 2), screenHeight / 2, paint); | |
| r.set(screenWidth / 2 - 90, screenHeight / 2 + 40, screenWidth / 2 - 90 + (chunksReady * 60), screenHeight / 2 + 70); | |
| canvas.drawRect(r, paint); | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment