Skip to content

Instantly share code, notes, and snippets.

@darkwave
Created October 1, 2013 18:27
Show Gist options
  • Save darkwave/6782878 to your computer and use it in GitHub Desktop.
Save darkwave/6782878 to your computer and use it in GitHub Desktop.
Full source code of Spaghetti Coder's Eat and Play for the Game Jam IndieSpeedRun 2013. PBox2D Library by Daniel Shiffman needed.
class Circle {
float radius;
Body body;
BodyType bodyType;
PImage ballImage;
PImage ballReflexImage;
Circle(float x, float y, float radius) {
this(x, y, radius, true, 1.0);
}
Circle(float x, float y, float radius, float friction) {
this(x, y, radius, true , friction);
}
Circle(float x, float y, float radius, boolean isDynamic) {
this(x, y, radius, isDynamic, 1.0);
}
Circle(float x, float y, float radius, boolean isDynamic, float friction) {
if (isDynamic)
bodyType = BodyType.DYNAMIC;
else
bodyType = BodyType.STATIC;
this.radius = radius;
makeBody(new Vec2(x, y), friction);
ballImage = loadImage("img/palla.png");
ballImage.resize((int) (radius * 2.5), (int) (radius * 2.5));
ballReflexImage = loadImage("img/riflessopalla.png");
ballReflexImage.resize((int) (radius * 2.5), (int) (radius * 2.5));
}
void makeBody(Vec2 center, float friction) {
CircleShape circle = new CircleShape();
circle.m_radius = box2d.scalarPixelsToWorld(radius);
// Define a fixture
FixtureDef fd = new FixtureDef();
fd.shape = circle;
// Parameters that affect physics
fd.density = 1;
fd.friction = friction;
//fd.restitution = 0.5;
// Define the body
BodyDef bd = new BodyDef();
bd.type = bodyType;
bd.position.set(box2d.coordPixelsToWorld(center));
body = box2d.createBody(bd);
body.createFixture(circle, 1.0);
}
void display() {
Vec2 pos = box2d.getBodyPixelCoord(body);
float a = body.getAngle();
/*
pushMatrix();
fill(128);
stroke(0, 0, 0, 255);
translate(pos.x, pos.y);
rotate(-a);
ellipse(0, 0, radius * 2, radius * 2);
line(0, 0, radius, 0);
popMatrix();
*/
imageMode(CENTER);
pushMatrix();
translate(pos.x, pos.y);
rotate(PI * - 0.55);
pushMatrix();
rotate(-a);
image(ballImage, 0, 0);
popMatrix();
image(ballReflexImage, 0, 0);
popMatrix();
imageMode(CORNER);
}
void killBody() {
box2d.destroyBody(body);
}
boolean done() {
Vec2 pos = box2d.getBodyPixelCoord(body);
if (pos.y > height + 100) {
killBody();
return true;
}
return false;
}
}
import pbox2d.*;
import org.jbox2d.collision.shapes.*;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.*;
final int GAME_INIT = -1;
final int GAME_MENU = 0;
final int GAME_RUNNING = 1;
final int GAME_WIN = 2;
final int GAME_LOOSE = 3;
final int GAME_TEAM = 4;
final int GAME_BUY = 5;
final int maxLevel = 10;
static int levelCounter = 1;
int gameState = GAME_INIT;
String[] loading = new String[] {
"Cooking", "Cooking.", "Cooking..", "Cooking..."
};
int dotCounter = 0;
int lastDot;
boolean alreadyLoaded = false;
PBox2D box2d;
LevelManager lv;
int gameLoadedTime;
PImage splashScreen, startMenu, youWin, youLoose;
ArrayList<Polygon> polygons;
Circle ball;
PImage levelImage;
PImage eraserImage;
PImage grassImage;
PImage lakeImage;
PImage recipeImage;
PImage teamImage;
void setup() {
size(1200, 600, P3D);
PFont font = createFont("Ubuntu Bold", 25);
textFont(font, 25);
textAlign(CENTER, CENTER);
thread("loadAsset");
}
void loadImages() {
levelImage = loadImage("img/livello1.png");
eraserImage = loadImage("img/eraser0.png");
eraserImage.resize(60, 60);
grassImage = loadImage("img/erbadazero.png");
lakeImage = loadImage("img/lago_movimento.png");
splashScreen = loadImage("img/splash.png");
startMenu = loadImage("img/menu.png");
youWin = loadImage("img/win.png");
youLoose = loadImage("img/lost.png");
recipeImage = loadImage("img/ricetta.png");
teamImage = loadImage("img/team.png");
}
void loadAsset() {
box2d = new PBox2D(this);
box2d.createWorld();
box2d.setGravity(0, -100.0);
lv = new LevelManager(this);
polygons = lv.loadScene("data/test.json");
ball = new Circle(20, 20, 20);
if (!alreadyLoaded) {
loadImages();
alreadyLoaded = true;
}
/* gameLoadedTime = millis();
while (millis () - gameLoadedTime < 1000) {
}
gameLoadedTime = millis();*/
gameState = GAME_MENU;
}
void erasePolygon(PVector targetVertexA, PVector targetVertexB) {
if (mouseX >= targetVertexA.x && mouseX <= targetVertexB.x && mouseY >= targetVertexA.y && mouseY <= targetVertexB.y && mousePressed) {
//fill(255, 255, 255);
//text("HIT!", 40, 500);
// looking for victim polygon
boolean found = false;
for (int i = 0; i < polygons.size() && !found; i++) {
Polygon p = polygons.get(i);
if (p.vertices.contains(targetVertexA)) {
p.hit = true;
p.done();
polygons.remove(i);
found = true;
break;
}
}
}
}
void draw() {
if (gameState == GAME_RUNNING) {
box2d.step();
// Draw background & text
image(levelImage, 0, 0, width, height);/*
fill(255, 128, 0);
text(frameRate, 40, 10);
text(mouseX + "," + mouseY, 180, 10);
text(levelCounter, 300, 10);*/
// Draw lake
image(lakeImage, 0, 0, width, height);
// Draw polygons
for (Polygon p: polygons)
p.display();
// Draw ball
ball.display();
// Pruning
for (int i = polygons.size() -1; i >= 0; i--) {
Polygon p = polygons.get(i);
if (p.done())
polygons.remove(i);
}
// Win/loose conditions
if (ball.done()) {
if (box2d.getBodyPixelCoord(ball.body).x > width) {
levelCounter++;
gameState = GAME_LOOSE;
println("LOOSE--");
}
else {
gameState = GAME_WIN;
levelCounter++;
println("WIN--");
}
}
// Draw grass
image(grassImage, 0, 0, width, height);
// Draw eraser
pushMatrix();
translate(mouseX, mouseY);
noStroke();
if (mousePressed) {
fill(80, 80, 80, 200);
ellipse(0, 0, eraserImage.width * 0.5, 12);
translate(eraserImage.width / 2, 0);
rotate(PI);
}
else {
fill(80, 80, 80, 100);
ellipse(0, 0, eraserImage.width * 0.8, 12);
translate(eraserImage.width / 2, - 10);
rotate(PI + 0.8);
}
image(eraserImage, 0, 0);
popMatrix();
// Hit points...
erasePolygon(new PVector(342, 308), new PVector(445, 344));
}
else if (gameState == GAME_MENU) {
if (millis() - gameLoadedTime > 3000) {
image(startMenu, 0, 0, width, height);
}
else {
background(255, 128, 0);
image(splashScreen, 0, 0, width, height);
}
}
else if (gameState == GAME_WIN) {
image(youWin, 0, 0, width, height);
if (levelCounter > maxLevel) {
image(recipeImage, 0, 0, width, height);
}
}
else if (gameState == GAME_LOOSE) {
image(youLoose, 0, 0, width, height);
if (levelCounter > maxLevel) {
image(recipeImage, 0, 0, width, height);
}
}
else if (gameState == GAME_INIT) {
if (millis() - lastDot > 500) {
background(0);
lastDot = millis();
textAlign(LEFT, CENTER);
text(loading[dotCounter++], width / 2, height / 2);
dotCounter %= loading.length;
}
}
else if (gameState == GAME_TEAM) {
image(teamImage, 0, 0, width, height);
}
else if (gameState == GAME_BUY) {
}
}
void keyPressed() {
levelCounter = 0;
}
void mouseClicked() {
if (gameState == GAME_MENU) {
println("menu");
if (dist(mouseX, mouseY, 220, 345) < 96) { // play
gameState = GAME_RUNNING;
}
else if (dist(mouseX, mouseY, 268, 500) < 47) { // buy
gameState = GAME_BUY;
exit();
}
else if (dist(mouseX, mouseY, 1043, 414) < 99) { // kitchen
gameState = GAME_TEAM;
}
} else if (gameState == GAME_TEAM) {
gameState = GAME_MENU;
}
else if ((gameState == GAME_WIN) || (gameState == GAME_LOOSE)) {
gameState = GAME_INIT;
thread("loadAsset");
}
}
class LevelManager {
PApplet parent;
PShape scene;
ArrayList<PVector> currentShape = new ArrayList<PVector>();
LevelManager(PApplet parent) {
this.parent = parent;
scene = parent.createShape(PConstants.GROUP);
}
void addPolygon(PVector... vertices) {
PShape polygon = parent.createShape();
polygon.beginShape();
polygon.stroke(90, 90, 90);
polygon.strokeWeight(2);
for (int i = 0; i < vertices.length; i++) {
polygon.vertex(vertices[i].x, vertices[i].y);
}
polygon.endShape(PConstants.CLOSE);
scene.addChild(polygon);
currentShape.clear();
}
ArrayList<Polygon> loadScene(String filename) {
ArrayList<Polygon> result = new ArrayList<Polygon>();
JSONArray jsonScene = parent.loadJSONArray(filename);
int shapesCounter = 0;
for (int i = 0; i < jsonScene.size(); i++) {
JSONObject jsonShape = jsonScene.getJSONObject(i);
JSONArray jsonVertices = jsonShape.getJSONArray("vertices");
PVector[] vertices = new PVector[jsonVertices.size() / 2];
for (int index = 0; index < jsonVertices.size(); index += 2) {
PVector v = new PVector(jsonVertices.getFloat(index), jsonVertices.getFloat(index + 1));
vertices[index / 2] = v;
}
Polygon currPolygon;
if (jsonShape.getString("type").equals("dynamic")) {
currPolygon = new Polygon(true, 10.0, vertices);
}
else {
currPolygon = new Polygon(false, 10.0, vertices);
}
if (currPolygon.vertices.contains(new PVector(342, 308))) {
currPolygon.setSprite(new PVector(342 + 15, 308 - 25), new PVector(445 + 15, 344 - 25), 0.8, "img/ponte.png");
}
result.add(currPolygon);
}
return result;
}
void saveScene(String filename) {
JSONArray jsonScene = new JSONArray();
int shapesCounter = 0;
for (int i = 0; i < scene.getChildCount(); i++) {
PShape thisShape = scene.getChild(i);
JSONObject jsonShape = new JSONObject();
JSONArray jsonVertices = new JSONArray();
int counter = 0;
for (int index = 0; index < thisShape.getVertexCount(); index++) {
PVector vertex = thisShape.getVertex(index);
jsonVertices.setFloat(counter++, vertex.x);
jsonVertices.setFloat(counter++, vertex.y);
}
jsonShape.setJSONArray("vertices", jsonVertices);
jsonScene.setJSONObject(shapesCounter++, jsonShape);
}
println("saving " + jsonScene.size());
parent.saveJSONArray(jsonScene, filename);
}
}
class Polygon {
ArrayList<PVector> vertices;
Body body;
BodyType bodyType;
float friction;
boolean hit;
PImage sprite;
PVector spriteVertexA, spriteVertexB; // top-left vertex and bottom-right vertex for the sprite
float spriteScale;
Polygon(PVector... vertices) {
this(true, 1.0, vertices);
}
Polygon(float friction, PVector... vertices) {
this(true, friction, vertices);
}
Polygon(boolean isDynamic, PVector... vertices) {
this(isDynamic, 1.0, vertices);
}
Polygon(boolean isDynamic, float friction, PVector... vertices) {
hit = false;
this.vertices = new ArrayList<PVector>();
for (PVector v: vertices) {
this.vertices.add(v);
}
if (isDynamic)
bodyType = BodyType.DYNAMIC;
else
bodyType = BodyType.STATIC;
this.friction = friction;
makeBody();
}
Vec2 center(Vec2[] vertices, int n) {
float sumX = 0;
float sumY = 0;
for (Vec2 v: vertices) {
sumX += v.x;
sumY += v.y;
}
// TODO calcolo del centro
//return new Vec2(sumX / n, sumY / n);
return new Vec2(0, 0);
}
void makeBody() {
// Shape
PolygonShape shape = new PolygonShape();
Vec2[] vertices = new Vec2[this.vertices.size()];
for (int i = 0; i < this.vertices.size(); i++) {
vertices[i] = box2d.vectorPixelsToWorld(this.vertices.get(i));
}
shape.set(vertices, this.vertices.size());
// Fixture
/*
FixtureDef fd = new FixtureDef();
fd.shape = shape;
// Parameters that affect physics
fd.density = 1;
fd.friction = friction;
//fd.restitution = 0.5;*/
// Body
BodyDef bd = new BodyDef();
bd.type = bodyType;
if (vertices.length > 0) {
bd.position.set(box2d.coordPixelsToWorld(center(vertices, vertices.length)));
}
else {
// FIXME
println("#ERROR: No vertex?");
}
body = box2d.createBody(bd);
body.createFixture(shape, 1.0);
}
void display() {
if (sprite == null || bodyType == BodyType.STATIC)
return;
Vec2 pos = box2d.getBodyPixelCoord(body);
float a = body.getAngle();
Fixture f = body.getFixtureList();
PolygonShape ps = (PolygonShape) f.getShape();
fill(128);
imageMode(CENTER);
pushMatrix();
translate(pos.x, pos.y);
rotate(-a);
/*
beginShape();
for (int i = 0; i < ps.getVertexCount(); i++) {
Vec2 v = box2d.vectorWorldToPixels(ps.getVertex(i));
vertex(v.x, v.y);
}
endShape(CLOSE);*/
translate((spriteVertexA.x + spriteVertexB.x) / 2, (spriteVertexA.y + spriteVertexB.y) / 2);
scale(spriteScale);
image(sprite, 0, 0);
popMatrix();
imageMode(CORNER);
}
void killBody() {
box2d.destroyBody(body);
}
boolean done() {
Vec2 pos = box2d.getBodyPixelCoord(body);
//boolean hit = dist(pos.x, pos.y, mouseX, mouseY) < 10;
if (pos.y > height * 2 || hit) {
println("RIP polygon: hit=" + hit);
killBody();
return true;
}
else return false;
}
void setSprite(PVector A, PVector B, float scale, String path) {
spriteVertexA = A;
spriteVertexB = B;
spriteScale = scale;
sprite = loadImage(path);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment