Cross Platform Games with PlayN
Lilli Thompson, Game Developer Advocate, Google
Lilli Thompson, Game Developer Advocate, Google







public class MyGame implements Game {
public void init() {
// initialize game.
}
public void update(float delta) {
// update world.
}
public void paint(float alpha) {
// render world.
}
}
// Resize to the available resolution on the current device. graphics().setSize( graphics().screenWidth(), graphics().screenHeight() ); // Keep the same aspect ratio. float sx = graphics().screenWidth() / (float) WIDTH; float sy = graphics().screenHeight() / (float) HEIGHT; // Fit to the available screen without stretching. graphics().rootLayer().setScale(Math.min(sx, sy));



// Clear the surface. surface.clear(); // Draw an image into the surface. surface.drawImage(myImage, x, y);
// Draw a scaled subsection of the source image into the surface.
surface.drawImage(image, dx, dy, dw, dh, sx, sy, sw, sh);


canvas.setFillColor(Color.rgb(100, 255, 0));
canvas.fillCircle(x, y, r);
canvas.fillRect(x, y, w, h);
canvas.drawImage(myImage, x, y);
canvas.drawText("Hello text!", x, y);
canvas.drawLine(x0, y0, x1, y1);


// Like OpenGL push. surface.save(); surface.translate(p.x, p.y); surface.rotate(p.r); surface.scale(p.sx, p.sy); // Draw something at transformed coordinates! // Like OpenGL pop. surface.restore();
pointer().setListener(new Pointer.Adapter() { public void onPointerStart(Pointer.Event event) { // Handle mouse down event. } // ...Same pattern for onPointerEnd, onPointerDrag }); keyboard().setListener(new Keyboard.Adapter() { public void onKeyDown(Event event) { // Handle key down event. } // ... Same pattern for onKeyUp });
import static playn.core.PlayN.platformType; if (platformType().equals(Platform.Type.ANDROID)) { touch().setListener(new Touch.Adapter() { @Override public void onTouchStart(Event[] touches) { // Process touch events into a zoom start position. } @Override public void onTouchMove(Event[] touches) { // Update zoom based on touches. } }); }
public interface AssetManager {
Image getImage(String path);
Sound getSound(String path);
void getText(String path, ResourceCallback callback);
boolean isDone();
int getPendingRequestCount();
}
// Ask the Asset Manager to create a new image. Image image = assetManager().getImage("myImage.png"); // Specify an onLoaded callback. image.addCallback(new ResourceCallback() { public void done(Image image) { // handle new image. } }
// To draw the image that was loaded, render it to a layer.
mySurfaceLayer.surface().drawImage(image, x, y);
AssetWatcher watcher = new AssetWatcher(new Listener() { public void done() { startGame(); } }); // Add assets to check. watcher.add(image1); watcher.add(image2); // ... // Start the watching now. watcher.start();
public interface Sound {
boolean play();
void stop();
void setLooping(boolean looping);
void setVolume(float volume);
boolean isPlaying();
}
assetManager().getSound("mySound.mp3");

/** Abstraction for Storage across platforms. */
public interface Storage {
public void setItem(String key, String data);
public void removeItem(String key);
public String getItem(String key);
// Returns true if the Storage data will be persisted across restarts.
public boolean isPersisted();
}
PlayN.assetManager().getText(JSON_FILE, new ResourceCallback() { @Override public void done(String resource) { Json.Object json = PlayN.json().parse(resource); Json.Array myArray = json.getArray("myArray"); int myInt = json.getInt("myInt"); } @Override public void error(Throwable err) { PlayN.log().error("Failed to load: " + err.getMessage()); } });
Writer writer = PlayN.json().newWriter(); writer.object(); writer.key("myInt"); writer.value(123); writer.key("myArray"); writer.array(); for (String s : arrayOfStringParams) { writer.value(s); } writer.endArray(); writer.endObject(); String output = writer.write();
public class MyGameJava {
public static void main(String[] args) {
JavaAssetManager assets = JavaPlatform.register().assetManager();
assets.setPathPrefix("src/myGame/resources");
PlayN.run(new MyGame());
}
}
public class MyGameHtml extends HtmlGame { public void start() { HtmlAssetManager assets = HtmlPlatform.register().assetManager(); assets.setPathPrefix("myGame/"); PlayN.run(new MyGame()); } }
public class MyGameAndroid {
public static void main(String[] args) {
AndroidPlatform.register();
PlayN.run(new MyGame());
}
}
public class MyGameFlash {
public static void main(String[] args) {
FlashPlatform.register();
PlayN.run(new MyGame());
}
}
private InAppPayments inappPayments = InAppPaymentsFactory.payments(); PurchaseRequest request = new PurchaseRequest.Impl("Gold Star", ...); inappPayments.encodeJWT(request, new InAppPayments.EncodeJWTCallback() { public void successHandler(String JWT) { purchaseJWT = JWT; } }); inappPayments.setCallback(new InAppPayments.Adapter() { public void successHandler(PurchaseResponse result) { PlayN.log().info("Congratulations! You've bought a product!"); } }); inappPayments.buy(purchaseJWT);
"Chrome users play 23% more than those from other ... sources, and are buying virtual goods ... [at] 147% more than average."

Early indications ... traffic from Chrome Web Store is twice as sticky as traffic from other sources.

