Compare commits

..

3 Commits

Author SHA1 Message Date
adebc42c16 Add Box2d collision filtering, allow collecting power ups with balls 2018-11-15 14:22:42 +04:00
74aa10de04 Refactor to use libGdx Array instead of java ArrayList
Render bricks with their box2d angle
Add ball density = 1f
2018-11-15 13:43:48 +04:00
b44b48097c Update paddle.update() to handle edge collision more nicely + cleaner code
Calculates an adjust variable which locates the paddle at exactly the
screen edge if a regular speed * dt move would put it past. Applies
the same adjust to stuck balls so they don't drift.
2018-11-15 12:24:33 +04:00
7 changed files with 83 additions and 46 deletions

View File

@ -6,11 +6,9 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.MathUtils;
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.*;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState; import com.me.brickbuster.state.PlayState;
@ -30,7 +28,7 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
public Ball(PlayState state) { public Ball(PlayState state) {
super(state, state.paddle.getX(), state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS); super(state, state.paddle.getX(), state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS);
this.speed = state.bricks.size() > BLOCKS_FOR_BOOST? DEFAULT_SPEED : BOOST_SPEED; this.speed = state.bricks.size > BLOCKS_FOR_BOOST? DEFAULT_SPEED : BOOST_SPEED;
createBody(); createBody();
} }
@ -83,6 +81,10 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
ballFixture.shape = ballShape; ballFixture.shape = ballShape;
ballFixture.restitution = 1f; ballFixture.restitution = 1f;
ballFixture.friction = 0f; ballFixture.friction = 0f;
ballFixture.density = 1f;
ballFixture.filter.categoryBits = EntityType.BALL;
ballFixture.filter.maskBits = EntityType.BOUNDARY | EntityType.BRICK | EntityType.PADDLE | EntityType.POWER_UP;
body = state.world.createBody(ballBody); body = state.world.createBody(ballBody);
body.createFixture(ballFixture); body.createFixture(ballFixture);

View File

@ -3,6 +3,8 @@ package com.me.brickbuster.entity;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
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.graphics.glutils.ShapeRenderer.ShapeType;
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;
@ -10,6 +12,7 @@ import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape; import com.badlogic.gdx.physics.box2d.PolygonShape;
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.PhysicsBody; import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState; import com.me.brickbuster.state.PlayState;
@ -44,10 +47,11 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
public void render(ShapeRenderer sr) { public void render(ShapeRenderer sr) {
sr.begin(ShapeType.Filled); sr.begin(ShapeType.Filled);
sr.setColor(color); sr.setColor(color);
sr.rect(getX() * PlayState.PIXEL_PER_METER, sr.rect(pos.x * PlayState.PIXEL_PER_METER, pos.y * PlayState.PIXEL_PER_METER,
getY() * PlayState.PIXEL_PER_METER, 0f, 0f,
BRICK_WIDTH * PlayState.PIXEL_PER_METER, BRICK_WIDTH * PlayState.PIXEL_PER_METER, BRICK_HEIGHT * PlayState.PIXEL_PER_METER,
BRICK_HEIGHT * PlayState.PIXEL_PER_METER); 1f, 1f,
body.getAngle() * MathUtils.radiansToDegrees);
sr.end(); sr.end();
} }
@ -78,6 +82,9 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
brickFixture.shape = brickShape; brickFixture.shape = brickShape;
brickFixture.friction = 0f; brickFixture.friction = 0f;
brickFixture.filter.categoryBits = EntityType.BRICK;
brickFixture.filter.maskBits = EntityType.BALL;
body = state.world.createBody(brickBody); body = state.world.createBody(brickBody);
body.createFixture(brickFixture); body.createFixture(brickFixture);
body.setUserData(this); body.setUserData(this);
@ -97,7 +104,7 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
} }
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) {
ball.setSpeed(Ball.BOOST_SPEED); ball.setSpeed(Ball.BOOST_SPEED);
} }

View File

@ -5,12 +5,14 @@ import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
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.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
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.EdgeShape; import com.badlogic.gdx.physics.box2d.EdgeShape;
import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState; import com.me.brickbuster.state.PlayState;
import net.dermetfan.utils.Pair; import net.dermetfan.utils.Pair;
@ -48,29 +50,27 @@ public class Paddle extends Entity implements PhysicsBody {
@Override @Override
public void update(float dt) { public void update(float dt) {
float displacement = PADDLE_SPEED * dt;
float adjust = 0;
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) { if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
if (pos.x - width/2 - PADDLE_SPEED * dt < 0) { if (pos.x - width / 2 - displacement < PlayState.EDGE_PADDING) {
setX(width/2); adjust = -(pos.x - width/2 - PlayState.EDGE_PADDING);
return; } else {
} adjust = -displacement;
setX(pos.x - PADDLE_SPEED * dt);
for (Ball ball : state.balls) {
if (ball.isStuck()) {
ball.setX(ball.getX() - PADDLE_SPEED * dt);
}
} }
} }
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) { if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
if (pos.x + width/2 + PADDLE_SPEED * dt > PlayState.BOARD_WIDTH) { if (pos.x + width / 2 + displacement > PlayState.BOARD_WIDTH-PlayState.EDGE_PADDING) {
setX(PlayState.BOARD_WIDTH - width/2); adjust = PlayState.BOARD_WIDTH - PlayState.EDGE_PADDING - width/2 - pos.x;
return; } else {
adjust = displacement;
} }
setX(pos.x + PADDLE_SPEED * dt); }
if (!MathUtils.isZero(adjust)) {
setX(pos.x + adjust);
for (Ball ball : state.balls) { for (Ball ball : state.balls) {
if (ball.isStuck()) { if (ball.isStuck()) {
ball.setX(ball.getX() + PADDLE_SPEED * dt); ball.setX(ball.getX() + adjust);
} }
} }
} }
@ -88,7 +88,9 @@ public class Paddle extends Entity implements PhysicsBody {
FixtureDef paddleFixture = new FixtureDef(); FixtureDef paddleFixture = new FixtureDef();
paddleFixture.shape = paddleShape; paddleFixture.shape = paddleShape;
//paddleFixture.isSensor = true;
paddleFixture.filter.categoryBits = EntityType.PADDLE;
paddleFixture.filter.maskBits = EntityType.BALL | EntityType.POWER_UP;
body = state.world.createBody(paddleBody); body = state.world.createBody(paddleBody);
body.createFixture(paddleFixture); body.createFixture(paddleFixture);

View File

@ -8,6 +8,7 @@ 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.me.brickbuster.entity.powerup.PowerUpType; import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState; import com.me.brickbuster.state.PlayState;
@ -53,6 +54,9 @@ public class Shield extends Entity implements PhysicsBody {
brickFixture.shape = brickShape; brickFixture.shape = brickShape;
brickFixture.friction = 0f; brickFixture.friction = 0f;
brickFixture.filter.categoryBits = EntityType.SHIELD;
brickFixture.filter.maskBits = EntityType.BALL;
body = state.world.createBody(brickBody); body = state.world.createBody(brickBody);
body.createFixture(brickFixture); body.createFixture(brickFixture);
body.setUserData(this); body.setUserData(this);

View File

@ -9,9 +9,11 @@ import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape; import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.me.brickbuster.Utils; import com.me.brickbuster.Utils;
import com.me.brickbuster.entity.Ball;
import com.me.brickbuster.entity.Entity; import com.me.brickbuster.entity.Entity;
import com.me.brickbuster.entity.Paddle; import com.me.brickbuster.entity.Paddle;
import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState; import com.me.brickbuster.state.PlayState;
import net.dermetfan.utils.Pair; import net.dermetfan.utils.Pair;
@ -72,6 +74,9 @@ public abstract class PowerUp extends Entity implements PhysicsBody, CollisionLi
ballFixture.shape = ballShape; ballFixture.shape = ballShape;
ballFixture.isSensor = true; ballFixture.isSensor = true;
ballFixture.filter.categoryBits = EntityType.POWER_UP;
ballFixture.filter.maskBits = EntityType.PADDLE | EntityType.BALL;
body = state.world.createBody(ballBody); body = state.world.createBody(ballBody);
body.createFixture(ballFixture); body.createFixture(ballFixture);
body.setUserData(this); body.setUserData(this);
@ -83,7 +88,7 @@ public abstract class PowerUp extends Entity implements PhysicsBody, CollisionLi
@Override @Override
public void beginContact(Entity contacted) { public void beginContact(Entity contacted) {
if (contacted instanceof Paddle) { if (contacted instanceof Paddle || contacted instanceof Ball) {
isCaught = true; isCaught = true;
} }
} }

View File

@ -0,0 +1,12 @@
package com.me.brickbuster.physics;
public final class EntityType {
public static final short BOUNDARY = 0x1;
public static final short BALL = 0x1 << 1;
public static final short BRICK = 0x1 << 2;
public static final short PADDLE = 0x1 << 3;
public static final short POWER_UP = 0x1 << 4;
public static final short SHIELD = 0x1 << 5;
}

View File

@ -11,10 +11,9 @@ import com.me.brickbuster.entity.*;
import com.me.brickbuster.entity.powerup.PowerUp; import com.me.brickbuster.entity.powerup.PowerUp;
import com.me.brickbuster.entity.powerup.PowerUpType; import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.physics.Box2dContactListener; import com.me.brickbuster.physics.Box2dContactListener;
import com.me.brickbuster.physics.EntityType;
import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
public class PlayState extends State { public class PlayState extends State {
@ -42,11 +41,11 @@ public class PlayState extends State {
public Body playArea; public Body playArea;
public Array<Body> bodies; public Array<Body> bodies;
public List<PowerUp> powerUps; public Array<PowerUp> powerUps;
public Paddle paddle; public Paddle paddle;
public List<Ball> balls; public Array<Ball> balls;
public List<Brick> bricks; public Array<Brick> bricks;
public List<Shield> shields; public Array<Shield> shields;
private float updateTime = 0f; private float updateTime = 0f;
@ -70,26 +69,32 @@ public class PlayState extends State {
EdgeShape screenEdge = new EdgeShape(); EdgeShape screenEdge = new EdgeShape();
FixtureDef playAreaFixture = new FixtureDef();
playAreaFixture.shape = screenEdge;
playAreaFixture.filter.categoryBits = EntityType.BOUNDARY;
playAreaFixture.filter.maskBits = EntityType.BALL | EntityType.BRICK;
playArea = world.createBody(playAreaDef); playArea = world.createBody(playAreaDef);
// Right edge // Right edge
screenEdge.set(lowerRightCorner, upperRightCorner); screenEdge.set(lowerRightCorner, upperRightCorner);
playArea.createFixture(screenEdge, 0f); playArea.createFixture(playAreaFixture);
// Top edge // Top edge
screenEdge.set(upperRightCorner, upperLeftCorner); screenEdge.set(upperRightCorner, upperLeftCorner);
playArea.createFixture(screenEdge, 0f); playArea.createFixture(playAreaFixture);
// Left edge // Left edge
screenEdge.set(upperLeftCorner, lowerLeftCorner); screenEdge.set(upperLeftCorner, lowerLeftCorner);
playArea.createFixture(screenEdge, 0f); playArea.createFixture(playAreaFixture);
// Bottom edge // Bottom edge
//screenEdge.set(lowerLeftCorner, lowerRightCorner); //screenEdge.set(lowerLeftCorner, lowerRightCorner);
//playArea.createFixture(screenEdge, 0f); //playArea.createFixture(playAreaFixture);
screenEdge.dispose(); screenEdge.dispose();
powerUps = new ArrayList<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 = ((BrickBuster.BOARD_WIDTH/PIXEL_PER_METER) - COLUMNS * Brick.BRICK_WIDTH) / (COLUMNS + 1);
bricks = new ArrayList<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 = 0; row < ROWS; row++) {
float x = brick_padding + (col * (Brick.BRICK_WIDTH + brick_padding)); float x = brick_padding + (col * (Brick.BRICK_WIDTH + brick_padding));
@ -104,10 +109,10 @@ public class PlayState extends State {
} }
} }
balls = new ArrayList<Ball>(); balls = new Array<Ball>();
balls.add(new Ball(this)); balls.add(new Ball(this));
shields = new ArrayList<Shield>(); shields = new Array<Shield>();
} }
@Override @Override
@ -116,7 +121,7 @@ public class PlayState extends State {
world.getBodies(bodies); world.getBodies(bodies);
for (Body b : bodies) { for (Body b : bodies) {
Entity e = (Entity) b.getUserData(); Entity e = (Entity) b.getUserData();
if (e instanceof Ball || e instanceof PowerUp) { if (e instanceof Ball || e instanceof PowerUp || e instanceof Brick) {
e.setPos(b.getPosition()); e.setPos(b.getPosition());
} }
} }
@ -159,7 +164,7 @@ public class PlayState extends State {
world.destroyBody(ball.getBody()); world.destroyBody(ball.getBody());
} }
} }
if (balls.isEmpty()) { if (balls.size == 0) {
ballReset(); ballReset();
} }
@ -189,7 +194,7 @@ public class PlayState extends State {
world.destroyBody(brick.getBody()); world.destroyBody(brick.getBody());
} }
} }
if (bricks.isEmpty()) { if (bricks.size == 0) {
game.setScreen(new MenuState(game)); game.setScreen(new MenuState(game));
dispose(); dispose();
return; return;
@ -215,7 +220,7 @@ public class PlayState extends State {
} }
public int getShieldCount() { public int getShieldCount() {
return shields.size(); return shields.size;
} }
public void addShield() { public void addShield() {