Created
October 1, 2013 18:27
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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