teaching machines

CS 436 Lecture 20 – The Game Loop (on Android)

October 31, 2014 by . Filed under cs436, fall 2014, lectures.

Agenda

Code

Particle.java

package org.twodee.rain;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;

import java.util.Random;

public class Particle {
  private static Random g = new Random();

  private Paint paint;
  private float x;
  private float y;
  private float velocityX;
  private float velocityY;

  public Particle(int width, int height) {
    x = g.nextInt(2 * width);
    y = -g.nextInt(height);
    velocityX = g.nextFloat() * -100.0f - 70.0f;
    velocityY = g.nextFloat() * 100.0f + 250.0f;

    paint = new Paint();
    paint.setColor(Color.GRAY);
    paint.setStrokeWidth(3.0f);
  }

  public void update(float elapsedSeconds) {
    x += velocityX * elapsedSeconds;
    y += velocityY * elapsedSeconds;
  }

  public void draw(Canvas canvas) {
    canvas.drawLine(x, y, x - 15, y + 40, paint);
  }

  public boolean isDead(int width, int height) {
    return y > height || x < 0;
  }
}

ParticleSystem.java

package org.twodee.rain;

import android.graphics.Canvas;

public class ParticleSystem {
  private Particle[] particles;

  public ParticleSystem(int width, int height) {
    particles = new Particle[500];
    for (int i = 0; i < particles.length; ++i) {
      particles[i] = new Particle(width, height);
    }
  }

  public void update(Canvas canvas, float elapsedSeconds) {
    for (int i = 0; i < particles.length; ++i) {
      if (particles[i].isDead(canvas.getWidth(), canvas.getHeight())) {
        particles[i] = new Particle(canvas.getWidth(), canvas.getHeight());
      }
      particles[i].update(elapsedSeconds);
    }
  }

  public void draw(Canvas canvas) {
    for (Particle particle : particles) {
      particle.draw(canvas);
    }
  }
}

MainActivity.java

package org.twodee.rain;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;


public class MainActivity extends ActionBarActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  }
}

AnimationView.java

package org.twodee.rain;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class AnimationView extends SurfaceView implements Callback {

  private SurfaceHolder holder;
  private int width;
  private int height;
  private DrawingThread dt;

  public AnimationView(Context context,
                       AttributeSet attrs) {
    super(context, attrs);
    holder = getHolder();
    holder.addCallback(this);

//    system = new ParticleSystem()
  }


  @Override
  public void surfaceCreated(SurfaceHolder holder) {

  }

  @Override
  public void surfaceChanged(SurfaceHolder holder,
                             int format,
                             int width,
                             int height) {
    this.width = width;
    this.height = height;
    dt = new DrawingThread();
    dt.start();
  }

  @Override
  public void surfaceDestroyed(SurfaceHolder holder) {
    dt.blockTillJoined();
  }

  private class DrawingThread extends Thread {
    private ParticleSystem system;
    private long lastFrameAt;
    private boolean isRequestedToStop;

    private DrawingThread() {
      lastFrameAt = SystemClock.uptimeMillis();
      system = new ParticleSystem(width, height);
      isRequestedToStop = false;
    }

    protected void draw(Canvas canvas) {
      long currentFrameAt = SystemClock.uptimeMillis();
      float elapsedSeconds = (currentFrameAt - lastFrameAt) / 1000.0f;
      system.update(canvas, elapsedSeconds);
      canvas.drawColor(Color.BLACK);
      system.draw(canvas);
      lastFrameAt = currentFrameAt;
    }

    @Override
    public void run() {
      super.run();
      while (!isRequestedToStop) {
        Canvas canvas = holder.lockCanvas();
        if (canvas != null) {
          draw(canvas);
          holder.unlockCanvasAndPost(canvas);
        }
        Log.d("FOO", "Any junk you want");
      }
    }

    public void blockTillJoined() {
      isRequestedToStop = true;
      boolean isJoined = false;

      while (!isJoined) {
        try {
          join();
          isJoined = true;
        } catch (InterruptedException e) {
        }
      }
    }
  }
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                tools:context=".MainActivity">

  <view
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    class="org.twodee.rain.AnimationView"
    android:id="@+id/view"
    android:layout_centerVertical="true"
    android:layout_centerHorizontal="true"/>
</RelativeLayout>