Skip to content

Instantly share code, notes, and snippets.

@Powersaurus
Last active October 1, 2015 23:21
Show Gist options
  • Save Powersaurus/533d4ab969ec934be8d2 to your computer and use it in GitHub Desktop.
Save Powersaurus/533d4ab969ec934be8d2 to your computer and use it in GitHub Desktop.
Procedural hills with parallax scrolling
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