Compare commits

...

5 Commits

9 changed files with 185 additions and 28 deletions

View File

@ -6,6 +6,7 @@ import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.utils.viewport.FitViewport; import com.badlogic.gdx.utils.viewport.FitViewport;
@ -25,6 +26,7 @@ public class BrickBuster extends Game {
public BitmapFont font; public BitmapFont font;
public SpriteBatch sb; public SpriteBatch sb;
public ShapeRenderer sr; public ShapeRenderer sr;
public PolygonSpriteBatch pb;
@Override @Override
public void create () { public void create () {
@ -38,6 +40,7 @@ public class BrickBuster extends Game {
sb = new SpriteBatch(); sb = new SpriteBatch();
sr = new ShapeRenderer(); sr = new ShapeRenderer();
pb = new PolygonSpriteBatch();
setScreen(new MenuState(this)); setScreen(new MenuState(this));
} }
@ -56,6 +59,7 @@ public class BrickBuster extends Game {
sb.setProjectionMatrix(cam.combined); sb.setProjectionMatrix(cam.combined);
sr.setProjectionMatrix(cam.combined); sr.setProjectionMatrix(cam.combined);
pb.setProjectionMatrix(cam.combined);
super.resize(width, height); super.resize(width, height);
} }

View File

@ -21,6 +21,7 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
public static final int BLOCKS_FOR_BOOST = 39; public static final int BLOCKS_FOR_BOOST = 39;
public static final float MINIMUM_ANGLE = MathUtils.PI/16; public static final float MINIMUM_ANGLE = MathUtils.PI/16;
public static final float CORRECTION_IMPULSE = 3f;
private float speed; private float speed;
private boolean isStuck = true; private boolean isStuck = true;
@ -64,12 +65,13 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
} }
Vector2 velocity = body.getLinearVelocity(); Vector2 velocity = body.getLinearVelocity();
body.setLinearVelocity(velocity.nor().scl(speed));
float rad = velocity.angleRad(); float rad = velocity.angleRad();
if (Math.abs(rad) < MINIMUM_ANGLE || Math.abs(rad) > MathUtils.PI - MINIMUM_ANGLE) { if (Math.abs(rad) < MINIMUM_ANGLE || Math.abs(rad) > MathUtils.PI - MINIMUM_ANGLE) {
body.applyLinearImpulse(new Vector2(0, rad > 0? 1 : -1), pos, true); Vector2 impulse = new Vector2(0, rad > 0? CORRECTION_IMPULSE : -CORRECTION_IMPULSE);
body.applyLinearImpulse(impulse, pos, true);
} }
body.setLinearVelocity(velocity.nor().scl(speed));
} }
@Override @Override

View File

@ -1,15 +1,19 @@
package com.me.brickbuster.entity; package com.me.brickbuster.entity;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.math.EarClippingTriangulator;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape; import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.utils.ShortArray;
import com.me.brickbuster.entity.powerup.PowerUpType; import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType; import com.me.brickbuster.physics.EntityType;
@ -22,8 +26,17 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
public static final float BRICK_WIDTH = 5f; public static final float BRICK_WIDTH = 5f;
public static final float BRICK_HEIGHT = 2.5f; public static final float BRICK_HEIGHT = 2.5f;
private static final EarClippingTriangulator ECT = new EarClippingTriangulator();
private static final Vector2 tmp = new Vector2();
private BrickType type;
private BrickShape shape;
private PowerUpType powerUpType; private PowerUpType powerUpType;
private Color color; private Color color;
private Pixmap pm;
private Texture solid;
private TextureRegion region;
private Body body; private Body body;
private boolean hitByBall = false; private boolean hitByBall = false;
@ -32,27 +45,46 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
this(state, powerUpType, true, x, y); this(state, powerUpType, true, x, y);
} }
public Brick(PlayState state, PowerUpType powerUpType, boolean hidePowerup, float x, float y) { public Brick(PlayState state, BrickShape shape, PowerUpType powerUpType, float x, float y) {
this(state, powerUpType, DEFAULT_COLOR, hidePowerup, x, y); this(state, BrickType.STANDARD_10, shape, powerUpType, DEFAULT_COLOR, true, x, y);
} }
public Brick(PlayState state, PowerUpType powerUpType, Color color, boolean hidePowerUp, float x, float y) { public Brick(PlayState state, PowerUpType powerUpType, boolean hidePowerup, float x, float y) {
this(state, BrickType.STANDARD_10, BrickShape.RECTANGLE, powerUpType, DEFAULT_COLOR, hidePowerup, x, y);
}
public Brick(PlayState state, BrickType type, BrickShape shape, PowerUpType powerUpType, Color color, boolean hidePowerUp, float x, float y) {
super(state, x, y); super(state, x, y);
this.type = type;
this.shape = shape;
this.powerUpType = powerUpType; this.powerUpType = powerUpType;
this.color = powerUpType != null && !hidePowerUp? powerUpType.getColor() : color; this.color = powerUpType != null && !hidePowerUp? powerUpType.getColor() : color;
this.pm = new Pixmap(1,1, Pixmap.Format.RGBA8888);
pm.setColor(color);
pm.fill();
this.solid = new Texture(pm);
this.region = new TextureRegion(solid);
createBody(); createBody();
} }
@Override @Override
public void render(ShapeRenderer sr) { public void render(ShapeRenderer sr) {
sr.begin(ShapeType.Filled); PolygonShape shape = (PolygonShape) body.getFixtureList().get(0).getShape();
sr.setColor(color); float[] vertices = new float[shape.getVertexCount()*2];
sr.rect(pos.x * PlayState.PIXEL_PER_METER, pos.y * PlayState.PIXEL_PER_METER, for (int i = 0; i < vertices.length/2; i++) {
0f, 0f, shape.getVertex(i, tmp);
BRICK_WIDTH * PlayState.PIXEL_PER_METER, BRICK_HEIGHT * PlayState.PIXEL_PER_METER, Vector2 vertex = body.getWorldPoint(tmp);
1f, 1f, vertices[i*2] = vertex.x * PlayState.PIXEL_PER_METER;
body.getAngle() * MathUtils.radiansToDegrees); vertices[i*2 + 1] = vertex.y * PlayState.PIXEL_PER_METER;
sr.end(); }
ShortArray triangleIndices = ECT.computeTriangles(vertices);
PolygonRegion polyRegion = new PolygonRegion(region, vertices, triangleIndices.toArray());
PolygonSpriteBatch pb = state.getGame().pb;
pb.begin();
pb.draw(polyRegion, 0, 0);
pb.end();
} }
@Override @Override
@ -75,15 +107,88 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
brickBody.position.set(pos.cpy()); brickBody.position.set(pos.cpy());
PolygonShape brickShape = new PolygonShape(); PolygonShape brickShape = new PolygonShape();
brickShape.setAsBox(BRICK_WIDTH/2, BRICK_HEIGHT/2,
new Vector2(BRICK_WIDTH/2,BRICK_HEIGHT/2), 0); switch (shape) {
case DIAMOND:
brickShape.set(new float[] {
-BRICK_WIDTH/2, 0, // Left
0, BRICK_HEIGHT/2, // Up
BRICK_WIDTH/2, 0, // Right
0, -BRICK_HEIGHT/2 // Down
});
break;
case DOWN_RIGHT_TRIANGLE:
brickShape.set(new float[] {
BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top right
BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom right
-BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom left
});
break;
case UP_RIGHT_TRIANGLE:
brickShape.set(new float[] {
BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top right
BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom right
-BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top left
});
break;
case UP_LEFT_TRIANGLE:
brickShape.set(new float[] {
-BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top left
BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top right
-BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom left
});
break;
case DOWN_LEFT_TRIANGLE:
brickShape.set(new float[] {
-BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top left
BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom right
-BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom left
});
break;
case HALF_LOWER:
brickShape.set(new float[] {
-BRICK_WIDTH/2, 0, // Top left
BRICK_WIDTH/2, 0, // Top right
BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom right
-BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom left
});
break;
case HALF_UPPER:
brickShape.set(new float[] {
-BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top left
BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top right
BRICK_WIDTH/2, 0, // Bottom right
-BRICK_WIDTH/2, 0, // Bottom left
});
break;
case HALF_LEFT:
brickShape.set(new float[] {
-BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top left
0, BRICK_HEIGHT/2, // Top right
0, -BRICK_HEIGHT/2, // Bottom right
-BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom left
});
break;
case HALF_RIGHT:
brickShape.set(new float[] {
0, BRICK_HEIGHT/2, // Top left
BRICK_WIDTH/2, BRICK_HEIGHT/2, // Top right
BRICK_WIDTH/2, -BRICK_HEIGHT/2, // Bottom right
0, -BRICK_HEIGHT/2, // Bottom left
});
break;
default:
brickShape.setAsBox(BRICK_WIDTH/2, BRICK_HEIGHT/2, Vector2.Zero, 0f);
}
FixtureDef brickFixture = new FixtureDef(); FixtureDef brickFixture = new FixtureDef();
brickFixture.shape = brickShape; brickFixture.shape = brickShape;
brickFixture.friction = 0f; brickFixture.friction = 0f;
brickFixture.density = 0.5f;
brickFixture.filter.categoryBits = EntityType.BRICK; brickFixture.filter.categoryBits = EntityType.BRICK;
brickFixture.filter.maskBits = EntityType.BALL; brickFixture.filter.maskBits = EntityType.BALL | EntityType.BRICK | EntityType.BOUNDARY;
body = state.world.createBody(brickBody); body = state.world.createBody(brickBody);
body.createFixture(brickFixture); body.createFixture(brickFixture);
@ -103,6 +208,12 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
public void endContact(Entity contacted) { public void endContact(Entity contacted) {
} }
@Override
public void dispose() {
solid.dispose();
pm.dispose();
}
public boolean hit() { public boolean hit() {
if (state.bricks.size-1 <= Ball.BLOCKS_FOR_BOOST) { if (state.bricks.size-1 <= Ball.BLOCKS_FOR_BOOST) {
for (Ball ball : state.balls) { for (Ball ball : state.balls) {

View File

@ -0,0 +1,17 @@
package com.me.brickbuster.entity;
public enum BrickShape {
RECTANGLE,
DIAMOND,
DOWN_RIGHT_TRIANGLE,
UP_RIGHT_TRIANGLE,
UP_LEFT_TRIANGLE,
DOWN_LEFT_TRIANGLE,
HALF_UPPER,
HALF_LOWER,
HALF_LEFT,
HALF_RIGHT,
;
}

View File

@ -0,0 +1,19 @@
package com.me.brickbuster.entity;
public enum BrickType {
STANDARD_10,
STANDARD_20,
STANDARD_30,
STANDARD_40,
STANDARD_50,
STANDARD_60,
STANDARD_70,
STANDARD_80,
EXPLOSIVE,
HARD,
HARDER,
UNBREAKABLE
;
}

View File

@ -23,6 +23,8 @@ public abstract class Entity {
public abstract void update(float dt); public abstract void update(float dt);
public void dispose() {}
public Vector2 getPos() { public Vector2 getPos() {
return pos; return pos;
} }

View File

@ -42,9 +42,7 @@ public enum PowerUpType {
} }
public PowerUp createInstance(PlayState state, Brick brick) { public PowerUp createInstance(PlayState state, Brick brick) {
return createInstance(state, return createInstance(state, new Vector2(brick.getX(), brick.getY()));
new Vector2(brick.getX()+Brick.BRICK_WIDTH/2,
brick.getY()+Brick.BRICK_HEIGHT/2));
} }
public PowerUp createInstance(PlayState state, Vector2 pos) { public PowerUp createInstance(PlayState state, Vector2 pos) {

View File

@ -95,19 +95,19 @@ public class PlayState extends State {
powerUps = new Array<PowerUp>(); powerUps = new Array<PowerUp>();
paddle = new Paddle(this); paddle = new Paddle(this);
float brick_padding = ((BrickBuster.BOARD_WIDTH/PIXEL_PER_METER) - COLUMNS * Brick.BRICK_WIDTH) / (COLUMNS + 1); float brick_padding = (BOARD_WIDTH - COLUMNS * Brick.BRICK_WIDTH) / (COLUMNS + 1);
bricks = new Array<Brick>(); bricks = new Array<Brick>();
for (int col = 0; col < COLUMNS; col++) { for (int col = 0; col < COLUMNS; col++) {
for (int row = 0; row < ROWS; row++) { for (int row = ROWS-1; row >= 0; row--) {
float x = brick_padding + (col * (Brick.BRICK_WIDTH + brick_padding)); float x = brick_padding + Brick.BRICK_WIDTH/2 + (col * (Brick.BRICK_WIDTH + brick_padding));
float y = brick_padding + Brick.BRICK_HEIGHT + (row * (Brick.BRICK_HEIGHT + brick_padding)); float y = brick_padding + Brick.BRICK_HEIGHT/2 + (row * (Brick.BRICK_HEIGHT + brick_padding));
PowerUpType powerUpType = null; PowerUpType powerUpType = null;
if (MathUtils.randomBoolean(POWERUP_CHANCE)) { if (MathUtils.randomBoolean(POWERUP_CHANCE)) {
powerUpType = PowerUpType.getWeightedRandom(); powerUpType = PowerUpType.getWeightedRandom();
} }
bricks.add(new Brick(this, powerUpType, x, BrickBuster.BOARD_HEIGHT/PIXEL_PER_METER - y)); bricks.add(new Brick(this, powerUpType, x, BOARD_HEIGHT - y));
} }
} }

View File

@ -26,6 +26,10 @@ public abstract class State extends ScreenAdapter {
this.disposed = true; this.disposed = true;
} }
public BrickBuster getGame() {
return game;
}
public abstract void setup(); public abstract void setup();
public abstract void render(); public abstract void render();