Building Games With Google Technologies

Johan Euphrosine
Nov 1, 2011

proppy-playn101.appspot.com

About Me

proppy-playn101.appspot.com

Remember Angry Birds?

proppy-playn101.appspot.com

Leverage Google Open Technologies and Platforms

proppy-playn101.appspot.com

Build with the Play library

proppy-playn101.appspot.com

Hardware acceleration

proppy-playn101.appspot.com

Each platform implements the same set of APIs

proppy-playn101.appspot.com

And You implement the Game Interface

package playn.core;

public interface Game {

  void init();

  void update(float delta);

  void paint(float alpha);

  int updateRate();
}
proppy-playn101.appspot.com

Play 101

proppy-playn101.appspot.com

Every game should start with a blue sky

public class MyGame implements Game {

  @Override
  public void init() {
    int width = 640;
    int height = 480;
    CanvasImage bgImage = graphics().createImage(width, height);
    Canvas canvas = bgImage.canvas();
    canvas.setFillColor(0xff87ceeb);
    canvas.fillRect(0, 0, width, height);
    ImageLayer bg = graphics().createImageLayer(bgImage);
    graphics().rootLayer().add(bg);
  }
}
proppy-playn101.appspot.com

Every game should start with a blue sky

proppy-playn101.appspot.com

And some white clouds

Image cloudImage = assets().getImage("images/cloud.png");
ImageLayer cloud = graphics().createImageLayer(cloudImage);
graphics().rootLayer().add(cloud);
float x = 24.0f;
float y = 3.0f;
cloud.setTranslation(x, y);
proppy-playn101.appspot.com

And some white clouds

proppy-playn101.appspot.com

Layer can be animated

@Override
public void paint(float delta) {
  x += 0.1f * delta;
  if (x > bgImage.width() + cloudImage.width()) {
    x = -cloudImage.width();
  }
  cloud.setTranslation(x, y);
}
proppy-playn101.appspot.com

Layer can be animated

proppy-playn101.appspot.com

You can hook on click event and create new layers

Image ballImage = assets().getImage("images/ball.png");
GroupLayer ballsLayer = graphics().createGroupLayer();
graphics().rootLayer().add(ballsLayer);
pointer().setListener(new Pointer.Adapter() {
  @Override
  public void onPointerEnd(Pointer.Event event) {
    ImageLayer ball = graphics().createImageLayer(ballImage);
    ball.setTranslation(event.x(), event.y());
    ballsLayer.add(ball);
  }
});
proppy-playn101.appspot.com

You can listen for click even and create new layers

proppy-playn101.appspot.com

import org.jbox2d.*;

float physUnitPerScreenUnit = 1 / 26.666667f;
Vec2 gravity = new Vec2(0.0f, 10.0f);
world = new World(gravity, true);
ballsLayer.setScale(1f / physUnitPerScreenUnit);
class Ball {
  public initPhysics() {
    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyType.DYNAMIC;
    body = world.createBody(bodyDef);
    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = new CircleShape();
    fixtureDef.circleShape.m_radius = 0.5f;
    fixtureDef.density = 1.0f;
    body.createFixture(fixtureDef);
  }
}
proppy-playn101.appspot.com

And eventually some physics will come in

proppy-playn101.appspot.com

Don't forget to add the ground!

float worldWidth = physUnitPerScreenUnit * width;
float worldHeight = physUnitPerScreenUnit * height;
Body ground = world.createBody(new BodyDef());
PolygonShape groundShape = new PolygonShape();
groundShape.setAsEdge(new Vec2(0, worldHeight),
                      new Vec2(worldWidth, worldHeight));
ground.createFixture(groundShape, 0.0f);
proppy-playn101.appspot.com

Don't forget to add the ground!

proppy-playn101.appspot.com

Let's add more blocks

Image blockImage = assets().getImage("images/block.png");    
float blockWidth = blockImage.width()*physUnitPerScreenUnit;
float blockHeight = blockImage.height()*physUnitPerScreenUnit;
GroupLayer blocksLayer = graphics().createGroupLayer();
blocksLayer.setScale(1f / physUnitPerScreenUnit);
Body blocksBody = world.createBody(new BodyDef());
  for (int i = 0; i < 4; i++) {
    ImageLayer block = graphics().createImageLayer(blockImage);
    block.setTranslation((1+2*i)*blockWidth, worldHeight-height);
    blocksLayer.add(block);
    PolygonShape shape = new PolygonShape();
    shape.setAsBox(blockWidth/2f, blockHeight/2f,
		   block.transform().translation(), 0f);
    blocksBody.createFixture(shape, 0.0f);
  }
}
proppy-playn101.appspot.com

Let's add more blocks

proppy-playn101.appspot.com

And some nails

public void initNails() {
  for (int x = 100; x < bgImage.width() - 100; x += 50) {
    for (int y = 150; y < 450; y+= 100) {
	canvas.setFillColor(0xffaaaaaa);
	canvas.fillCircle(x, y, radius);
	CircleShape circleShape = new CircleShape();
	circleShape.m_radius = 5f*physUnitPerScreenUnit;
	circleShape.m_p.set(x*physUnitPerScreenUnit,
                            y*physUnitPerScreenUnit);
	FixtureDef fixtureDef = new FixtureDef();
	fixtureDef.shape = circleShape;
	fixtureDef.restitution = 0.6f;
	ground.createFixture(fixtureDef);
    }
  }
}
proppy-playn101.appspot.com

パチンコ!

proppy-playn101.appspot.com

The only thing missing is a score

int[] pointsTable = {-10, 10, 50, 10, -10};
int points = 0;
@Override
public void update(float delta) {
  for (Ball ball : balls) {
    Vector pos = ball.layer.transform().translation();
    if (pos.y() >= scoringHeight) {
      int slot = (int)pos.x() / (int)scoringWidth;
      points += pointsTable[slot];
      points = Math.max(0, points);
      ballsLayer.remove(ball.layer);
      world.destroyBody(ball.body);
      removeBalls.add(ball);
    }
  }
}
proppy-playn101.appspot.com

See how we draw the score.

CanvasImage pointsImage;
ImageLayer pointsLayer;
void initPoints() {
  pointsImage = graphics().createImage(width, 50);
  pointsLayer = graphics().createImageLayer(pointsImage);
  pointsLayer.setScale(3f);
  graphics().rootLayer().add(pointsLayer);
}
public void paint(float delta) {
  String s = Integer.toString(points);
  pointsImage.canvas().clear();
  pointsImage.canvas().setFillColor(0xff000000);
  pointsImage.canvas().drawText(s, 10f, 20f);
}
proppy-playn101.appspot.com

The only thing missing is a score

proppy-playn101.appspot.com

And prevent cheating

    pointer().setListener(new Pointer.Adapter() {
      @Override
      public void onPointerEnd(Pointer.Event event) {
	float y = event.y();
	if (y > 100) {
	    y = 100;
	}
	Ball ball = new Ball(ballImage, physUnitPerScreenUnit * event.x(),
			     physUnitPerScreenUnit * y);
	balls.add(ball);
	ballLayer.add(ball.layer);
      }
    });
	

And prevent cheating

proppy-playn101.appspot.com

Homework

proppy-playn101.appspot.com

One more thing

playn101-android-1.0-SNAPSHOT.apk

proppy-playn101.appspot.com

Thanks!

proppy-playn101.appspot.com