From e4000998cc4d99201779467ba457a6239aa45a41 Mon Sep 17 00:00:00 2001 From: Matt Low Date: Thu, 15 Nov 2018 10:34:22 +0400 Subject: [PATCH] Complete box2d implementation, all collisions handled with box2d Shield re-implemented as an entity with a box2d body Multiball powerup now spawns balls at paddle instead of from block location --- core/src/com/me/brickbuster/entity/Ball.java | 163 ++++++++---------- core/src/com/me/brickbuster/entity/Brick.java | 65 ++++--- .../src/com/me/brickbuster/entity/Entity.java | 9 + .../src/com/me/brickbuster/entity/Paddle.java | 69 +++++--- .../src/com/me/brickbuster/entity/Shield.java | 67 +++++++ .../entity/powerup/MultiBallPowerUp.java | 6 +- .../brickbuster/entity/powerup/PowerUp.java | 69 ++++---- .../me/brickbuster/physics/PhysicsBody.java | 2 + .../com/me/brickbuster/state/PlayState.java | 94 ++++++---- 9 files changed, 337 insertions(+), 207 deletions(-) create mode 100644 core/src/com/me/brickbuster/entity/Shield.java diff --git a/core/src/com/me/brickbuster/entity/Ball.java b/core/src/com/me/brickbuster/entity/Ball.java index 0a9939d..8f628e5 100644 --- a/core/src/com/me/brickbuster/entity/Ball.java +++ b/core/src/com/me/brickbuster/entity/Ball.java @@ -10,10 +10,11 @@ import com.badlogic.gdx.physics.box2d.Body; 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.PhysicsBody; import com.me.brickbuster.state.PlayState; -public class Ball extends Entity implements PhysicsBody { +public class Ball extends Entity implements PhysicsBody, CollisionListener { public static final float RADIUS = 1.2f; public static final Color BALL_COLOR = Color.CHARTREUSE; @@ -21,17 +22,56 @@ public class Ball extends Entity implements PhysicsBody { public static final float BOOST_SPEED = 55; public static final int BLOCKS_FOR_BOOST = 39; - public Vector2 direction; private float speed; private boolean isStuck = true; - private boolean isDead = false; + private boolean touchedPaddle = false; private Body body; public Ball(PlayState state) { - super(state,PlayState.BOARD_WIDTH/2, 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; + createBody(); + } + @Override + public void render(ShapeRenderer sr) { + sr.begin(ShapeType.Filled); + sr.setColor(BALL_COLOR); + sr.circle(pos.x * PlayState.PIXEL_PER_METER, + pos.y * PlayState.PIXEL_PER_METER, + RADIUS * PlayState.PIXEL_PER_METER); + sr.end(); + } + + @Override + public void update(float dt) { + if (isStuck || deleted) { + if (!deleted && Gdx.input.justTouched()) { + launch(); + } else { + return; + } + } + if (touchedPaddle) { + paddleCollision(); + touchedPaddle = false; + } + + if (getY() + RADIUS < 0) { + deleted = true; + } + + body.setLinearVelocity(body.getLinearVelocity().nor().scl(speed)); + } + + @Override + public Body getBody() { + return body; + } + + @Override + public void createBody() { BodyDef ballBody = new BodyDef(); ballBody.type = BodyDef.BodyType.DynamicBody; ballBody.position.set(pos); @@ -52,83 +92,22 @@ public class Ball extends Entity implements PhysicsBody { } @Override - public void render(ShapeRenderer sr) { - sr.begin(ShapeType.Filled); - sr.setColor(BALL_COLOR); - sr.circle(pos.x * PlayState.PIXEL_PER_METER, - pos.y * PlayState.PIXEL_PER_METER, - RADIUS * PlayState.PIXEL_PER_METER); - sr.end(); - } - - @Override - public void update(float dt) { - if (isStuck || isDead) { - if (!isDead && Gdx.input.justTouched()) { - launch(); - } else { - return; - } + public void beginContact(Entity contacted) { + if (contacted instanceof Shield) { + contacted.delete(); } -// Vector2 new_pos = pos.cpy().add(direction.cpy().scl(speed * dt)); -// -// boolean brickCollision = false; -// Iterator brickIterator = state.bricks.iterator(); -// while (!brickCollision && brickIterator.hasNext()) { -// Brick brick = brickIterator.next(); -// Vector2[] vertices = brick.getVertices(); -// for(int i = 0; i < vertices.length; i++) { -// Vector2 v1 = vertices[i]; -// Vector2 v2 = vertices[i+1 < vertices.length? i+1 : 0]; -// Vector2 segment = v2.cpy().sub(v1); -// Vector2 nearest = Utils.nearestPoint(v1.cpy(), segment, new_pos.cpy()); -// -// if (nearest.dst(new_pos.x, new_pos.y) <= RADIUS) { -// if (brick.hit()) { -// brickIterator.remove(); -// } -// Utils.reflect(direction, segment.nor()); -// brickCollision = true; -// break; -// } -// } -// } -// -// if (new_pos.x + RADIUS > BrickBuster.BOARD_WIDTH || new_pos.x - RADIUS < 0) { -// Utils.reflect(direction, Utils.VERTICAL_EDGE); -// } else if (new_pos.y + RADIUS > BrickBuster.BOARD_HEIGHT) { -// Utils.reflect(direction, Utils.HORIZONTAL_EDGE); -// } else if (state.getShieldCount() > 0 -// && new_pos.y - RADIUS < PlayState.SHIELD_HEIGHT * state.getShieldCount()) { -// Utils.reflect(direction, Utils.HORIZONTAL_EDGE); -// state.removeShield(); -// } else if (new_pos.y + RADIUS < 0) { -// isDead = true; -// return; -// } else if (direction.y < 0 && new_pos.y <= state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS) { -// Pair paddle = state.paddle.getTopEdge(); -// Vector2 lineDir = paddle.getValue().sub(paddle.getKey()); -// Vector2 nearest = Utils.nearestPoint(paddle.getKey().cpy(), lineDir, new_pos.cpy()); -// -// if (nearest.dst(new_pos.x, new_pos.y) <= RADIUS) { -// paddleCollision(); -// if (state.paddle.isSticky()) { -// return; -// } -// } -// } -// -// pos.add(direction.cpy().scl(speed * dt)); + if (contacted instanceof Paddle && !isStuck) { + touchedPaddle = true; + } } @Override - public Body getBody() { - return body; + public void endContact(Entity contacted) { } public Vector2 paddleReflectAngle() { - int trim = (int) (state.paddle.getWidth() * 0.10); + float trim = state.paddle.getWidth() * 0.10f; float rel = MathUtils.clamp((pos.x - state.paddle.getX()) + (state.paddle.getWidth()/2), trim, state.paddle.getWidth()-trim); float newAngle = MathUtils.PI - (MathUtils.PI * (rel / state.paddle.getWidth())); @@ -136,6 +115,7 @@ public class Ball extends Entity implements PhysicsBody { } public void launch() { + Vector2 direction; if (state.paddle.isSticky()) { direction = paddleReflectAngle(); } else { @@ -144,20 +124,34 @@ public class Ball extends Entity implements PhysicsBody { direction = new Vector2(MathUtils.cos(angle), MathUtils.sin(angle)); } - //body.applyForceToCenter(new Vector2(0,Float.MAX_VALUE/2), true); - //body.setLinearVelocity(new Vector2(0,10000000)); - body.setLinearVelocity(direction.cpy().scl(speed)); - body.setBullet(true); + body.setLinearVelocity(direction.scl(speed)); isStuck = false; } public void paddleCollision() { if (state.paddle.isSticky()) { isStuck = true; - pos.y = state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS; + body.setLinearVelocity(new Vector2()); + setY(state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS); return; } - direction = paddleReflectAngle(); + body.setLinearVelocity(paddleReflectAngle().scl(speed)); + } + + @Override + public void setX(float x) { + super.setX(x); + Vector2 bodyPos = body.getPosition(); + bodyPos.x = x; + body.setTransform(bodyPos, 0); + } + + @Override + public void setY(float y) { + super.setY(y); + Vector2 bodyPos = body.getPosition(); + bodyPos.y = y; + body.setTransform(bodyPos, 0); } public void setSpeed(float speed) { @@ -168,15 +162,4 @@ public class Ball extends Entity implements PhysicsBody { return isStuck; } - public boolean isDead() { - return isDead; - } - - public void setDirection(Vector2 direction) { - this.direction = direction; - } - - public void setStuck(boolean stuck) { - isStuck = stuck; - } } diff --git a/core/src/com/me/brickbuster/entity/Brick.java b/core/src/com/me/brickbuster/entity/Brick.java index bf79f92..74ea235 100644 --- a/core/src/com/me/brickbuster/entity/Brick.java +++ b/core/src/com/me/brickbuster/entity/Brick.java @@ -9,10 +9,11 @@ import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.PolygonShape; import com.me.brickbuster.entity.powerup.PowerUpType; +import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.state.PlayState; -public class Brick extends Entity implements PhysicsBody { +public class Brick extends Entity implements PhysicsBody, CollisionListener { public static final Color DEFAULT_COLOR = Color.FOREST; public static final float BRICK_WIDTH = 5f; @@ -21,9 +22,8 @@ public class Brick extends Entity implements PhysicsBody { private PowerUpType powerUpType; private Color color; - private Vector2[] vertices; - private Body body; + private boolean hitByBall = false; public Brick(PlayState state, PowerUpType powerUpType, float x, float y) { this(state, powerUpType, true, x, y); @@ -37,13 +37,35 @@ public class Brick extends Entity implements PhysicsBody { super(state, x, y); this.powerUpType = powerUpType; this.color = powerUpType != null && !hidePowerUp? powerUpType.getColor() : color; - this.vertices = new Vector2[] { - new Vector2(x, y), - new Vector2(x + BRICK_WIDTH, y), - new Vector2(x + BRICK_WIDTH, y + BRICK_HEIGHT), - new Vector2(x, y + BRICK_HEIGHT) - }; + createBody(); + } + @Override + public void render(ShapeRenderer sr) { + sr.begin(ShapeType.Filled); + sr.setColor(color); + sr.rect(getX() * PlayState.PIXEL_PER_METER, + getY() * PlayState.PIXEL_PER_METER, + BRICK_WIDTH * PlayState.PIXEL_PER_METER, + BRICK_HEIGHT * PlayState.PIXEL_PER_METER); + sr.end(); + } + + @Override + public void update(float dt) { + if (hitByBall) { + hit(); + hitByBall = false; + } + } + + @Override + public Body getBody() { + return body; + } + + @Override + public void createBody() { BodyDef brickBody = new BodyDef(); brickBody.type = BodyDef.BodyType.StaticBody; brickBody.position.set(pos.cpy()); @@ -64,23 +86,14 @@ public class Brick extends Entity implements PhysicsBody { } @Override - public void render(ShapeRenderer sr) { - sr.begin(ShapeType.Filled); - sr.setColor(color); - sr.rect(getX()*PlayState.PIXEL_PER_METER, - getY()*PlayState.PIXEL_PER_METER, - BRICK_WIDTH*PlayState.PIXEL_PER_METER, - BRICK_HEIGHT*PlayState.PIXEL_PER_METER); - sr.end(); + public void beginContact(Entity contacted) { + if (contacted instanceof Ball) { + hitByBall = true; + } } @Override - public void update(float dt) { - } - - @Override - public Body getBody() { - return body; + public void endContact(Entity contacted) { } public boolean hit() { @@ -93,11 +106,9 @@ public class Brick extends Entity implements PhysicsBody { if (powerUpType != null) { state.powerUps.add(powerUpType.createInstance(state, this)); } + + deleted = true; return true; } - public Vector2[] getVertices() { - return vertices; - } - } diff --git a/core/src/com/me/brickbuster/entity/Entity.java b/core/src/com/me/brickbuster/entity/Entity.java index cb29e92..66b7cf4 100644 --- a/core/src/com/me/brickbuster/entity/Entity.java +++ b/core/src/com/me/brickbuster/entity/Entity.java @@ -8,6 +8,7 @@ public abstract class Entity { protected PlayState state; protected Vector2 pos; + protected boolean deleted = false; public Entity(PlayState state, Vector2 pos) { this(state, pos.x, pos.y); @@ -46,4 +47,12 @@ public abstract class Entity { pos.y = y; } + public void delete() { + this.deleted = true; + } + + public boolean isDeleted() { + return deleted; + } + } diff --git a/core/src/com/me/brickbuster/entity/Paddle.java b/core/src/com/me/brickbuster/entity/Paddle.java index 57f05a7..0e405a0 100644 --- a/core/src/com/me/brickbuster/entity/Paddle.java +++ b/core/src/com/me/brickbuster/entity/Paddle.java @@ -10,6 +10,7 @@ import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.EdgeShape; import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.state.PlayState; import net.dermetfan.utils.Pair; @@ -31,24 +32,7 @@ public class Paddle extends Entity implements PhysicsBody { public Paddle(PlayState brickBuster) { super(brickBuster, PlayState.BOARD_WIDTH/2, PADDLE_Y); - - BodyDef paddleBody = new BodyDef(); - paddleBody.type = BodyDef.BodyType.KinematicBody; - paddleBody.position.set(pos); - - EdgeShape paddleShape = new EdgeShape(); - paddleShape.set(new Vector2(-DEFAULT_WIDTH/2,PADDLE_HEIGHT), - new Vector2(DEFAULT_WIDTH/2, PADDLE_HEIGHT)); - - FixtureDef paddleFixture = new FixtureDef(); - paddleFixture.shape = paddleShape; - paddleFixture.isSensor = true; - - body = state.world.createBody(paddleBody); - body.createFixture(paddleFixture); - body.setUserData(this); - - paddleShape.dispose(); + createBody(); } @Override @@ -69,7 +53,7 @@ public class Paddle extends Entity implements PhysicsBody { setX(width/2); return; } - pos.x = pos.x - PADDLE_SPEED * dt; + setX(pos.x - PADDLE_SPEED * dt); for (Ball ball : state.balls) { if (ball.isStuck()) { @@ -82,7 +66,7 @@ public class Paddle extends Entity implements PhysicsBody { setX(PlayState.BOARD_WIDTH - width/2); return; } - pos.x = pos.x + PADDLE_SPEED * dt; + setX(pos.x + PADDLE_SPEED * dt); for (Ball ball : state.balls) { if (ball.isStuck()) { @@ -92,16 +76,46 @@ public class Paddle extends Entity implements PhysicsBody { } } + @Override + public void createBody() { + BodyDef paddleBody = new BodyDef(); + paddleBody.type = BodyDef.BodyType.KinematicBody; + paddleBody.position.set(pos); + + EdgeShape paddleShape = new EdgeShape(); + paddleShape.set(new Vector2(-width/2, PADDLE_HEIGHT), + new Vector2(width/2, PADDLE_HEIGHT)); + + FixtureDef paddleFixture = new FixtureDef(); + paddleFixture.shape = paddleShape; + //paddleFixture.isSensor = true; + + body = state.world.createBody(paddleBody); + body.createFixture(paddleFixture); + body.setUserData(this); + + paddleShape.dispose(); + } + @Override public Body getBody() { return body; } - public Pair getTopEdge() { - return new Pair( - new Vector2(pos.x - width/2, pos.y + PADDLE_HEIGHT), - new Vector2(pos.x + width/2, pos.y + PADDLE_HEIGHT) - ); + @Override + public void setX(float x) { + super.setX(x); + Vector2 bodyPos = body.getPosition(); + bodyPos.x = x; + body.setTransform(bodyPos, 0); + } + + @Override + public void setY(float y) { + super.setY(y); + Vector2 bodyPos = body.getPosition(); + bodyPos.y = y; + body.setTransform(bodyPos, 0); } public float getWidth() { @@ -109,7 +123,12 @@ public class Paddle extends Entity implements PhysicsBody { } public void setWidth(float width) { + if (this.width == width) { + return; + } + state.world.destroyBody(body); this.width = width; + createBody(); } public boolean isSticky() { diff --git a/core/src/com/me/brickbuster/entity/Shield.java b/core/src/com/me/brickbuster/entity/Shield.java new file mode 100644 index 0000000..53de221 --- /dev/null +++ b/core/src/com/me/brickbuster/entity/Shield.java @@ -0,0 +1,67 @@ +package com.me.brickbuster.entity; + +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.physics.box2d.Body; +import com.badlogic.gdx.physics.box2d.BodyDef; +import com.badlogic.gdx.physics.box2d.FixtureDef; +import com.badlogic.gdx.physics.box2d.PolygonShape; +import com.me.brickbuster.entity.powerup.PowerUpType; +import com.me.brickbuster.physics.PhysicsBody; +import com.me.brickbuster.state.PlayState; + +public class Shield extends Entity implements PhysicsBody { + + public static final float SHIELD_HEIGHT = 0.75f; + + private Body body; + + public Shield(PlayState state) { + super(state, 0, state.getShieldCount() * SHIELD_HEIGHT); + createBody(); + } + + @Override + public void render(ShapeRenderer sr) { + sr.begin(ShapeRenderer.ShapeType.Filled); + sr.setColor(PowerUpType.SHIELD.getColor()); + sr.rect(0, pos.y * PlayState.PIXEL_PER_METER, + PlayState.BOARD_WIDTH * PlayState.PIXEL_PER_METER, + SHIELD_HEIGHT * PlayState.PIXEL_PER_METER); + sr.end(); + } + + @Override + public void update(float dt) { + if (deleted) { + state.removeShield(this); + } + } + + @Override + public void createBody() { + BodyDef brickBody = new BodyDef(); + brickBody.type = BodyDef.BodyType.StaticBody; + brickBody.position.set(pos.cpy()); + + PolygonShape brickShape = new PolygonShape(); + brickShape.setAsBox(PlayState.BOARD_WIDTH/2, SHIELD_HEIGHT/2, + new Vector2(PlayState.BOARD_WIDTH/2,SHIELD_HEIGHT/2), 0); + + FixtureDef brickFixture = new FixtureDef(); + brickFixture.shape = brickShape; + brickFixture.friction = 0f; + + body = state.world.createBody(brickBody); + body.createFixture(brickFixture); + body.setUserData(this); + + brickShape.dispose(); + } + + @Override + public Body getBody() { + return body; + } +} diff --git a/core/src/com/me/brickbuster/entity/powerup/MultiBallPowerUp.java b/core/src/com/me/brickbuster/entity/powerup/MultiBallPowerUp.java index 16d894c..f2c4048 100644 --- a/core/src/com/me/brickbuster/entity/powerup/MultiBallPowerUp.java +++ b/core/src/com/me/brickbuster/entity/powerup/MultiBallPowerUp.java @@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.me.brickbuster.entity.Ball; +import com.me.brickbuster.entity.Paddle; import com.me.brickbuster.state.PlayState; public class MultiBallPowerUp extends PowerUp { @@ -19,10 +20,7 @@ public class MultiBallPowerUp extends PowerUp { public void activate() { for (int x = 0; x < 2; x++) { Ball ball = new Ball(state); - ball.setPos(pos.cpy()); - float angle = MathUtils.random(MathUtils.PI*2); - ball.setDirection(new Vector2(MathUtils.cos(angle), MathUtils.sin(angle))); - ball.setStuck(false); + ball.launch(); state.balls.add(ball); } } diff --git a/core/src/com/me/brickbuster/entity/powerup/PowerUp.java b/core/src/com/me/brickbuster/entity/powerup/PowerUp.java index 78dba27..8afbfe4 100644 --- a/core/src/com/me/brickbuster/entity/powerup/PowerUp.java +++ b/core/src/com/me/brickbuster/entity/powerup/PowerUp.java @@ -10,11 +10,13 @@ import com.badlogic.gdx.physics.box2d.CircleShape; import com.badlogic.gdx.physics.box2d.FixtureDef; import com.me.brickbuster.Utils; import com.me.brickbuster.entity.Entity; +import com.me.brickbuster.entity.Paddle; +import com.me.brickbuster.physics.CollisionListener; import com.me.brickbuster.physics.PhysicsBody; import com.me.brickbuster.state.PlayState; import net.dermetfan.utils.Pair; -public abstract class PowerUp extends Entity implements PhysicsBody { +public abstract class PowerUp extends Entity implements PhysicsBody, CollisionListener { public static final float RADIUS = 1.2f; public static final float FALL_SPEED = 15f; @@ -27,7 +29,38 @@ public abstract class PowerUp extends Entity implements PhysicsBody { public PowerUp(PlayState state, Vector2 pos, Color color) { super(state, pos); this.color = color; + createBody(); + } + @Override + public void render(ShapeRenderer sr) { + sr.begin(ShapeType.Filled); + sr.setColor(color); + sr.circle(getX() * PlayState.PIXEL_PER_METER, + getY() * PlayState.PIXEL_PER_METER, + RADIUS * PlayState.PIXEL_PER_METER); + sr.end(); + } + + @Override + public void update(float dt) { + if (isCaught) { + activate(); + delete(); + } + + if (getY() + RADIUS < 0) { + delete(); + } + } + + @Override + public Body getBody() { + return body; + } + + @Override + public void createBody() { BodyDef ballBody = new BodyDef(); ballBody.type = BodyDef.BodyType.DynamicBody; ballBody.position.set(pos); @@ -43,45 +76,21 @@ public abstract class PowerUp extends Entity implements PhysicsBody { body.createFixture(ballFixture); body.setUserData(this); + body.setLinearVelocity(0f, -FALL_SPEED); + ballShape.dispose(); } @Override - public void render(ShapeRenderer sr) { - sr.begin(ShapeType.Filled); - sr.setColor(color); - sr.circle(getX() * PlayState.PIXEL_PER_METER, - getY() * PlayState.PIXEL_PER_METER, - RADIUS * PlayState.PIXEL_PER_METER); - sr.end(); - } - - @Override - public void update(float dt) { - setY(getY() - FALL_SPEED * dt); - - Pair paddle = state.paddle.getTopEdge(); - Vector2 lineDir = paddle.getValue().sub(paddle.getKey()); - Vector2 nearest = Utils.nearestPoint(paddle.getKey().cpy(), lineDir, getPos().cpy()); - - if (nearest.dst(getX(), getY()) <= RADIUS) { - activate(); - isCaught = true; - } - - if (getY() + RADIUS < 0) { + public void beginContact(Entity contacted) { + if (contacted instanceof Paddle) { isCaught = true; } } @Override - public Body getBody() { - return body; - } + public void endContact(Entity contacted) {} public abstract void activate(); - public boolean isCaught() { - return isCaught; - } } diff --git a/core/src/com/me/brickbuster/physics/PhysicsBody.java b/core/src/com/me/brickbuster/physics/PhysicsBody.java index c1059f7..bca22ed 100644 --- a/core/src/com/me/brickbuster/physics/PhysicsBody.java +++ b/core/src/com/me/brickbuster/physics/PhysicsBody.java @@ -4,6 +4,8 @@ import com.badlogic.gdx.physics.box2d.Body; public interface PhysicsBody { + void createBody(); + Body getBody(); } diff --git a/core/src/com/me/brickbuster/state/PlayState.java b/core/src/com/me/brickbuster/state/PlayState.java index 57c7fc9..8ce6d62 100644 --- a/core/src/com/me/brickbuster/state/PlayState.java +++ b/core/src/com/me/brickbuster/state/PlayState.java @@ -2,18 +2,19 @@ package com.me.brickbuster.state; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; -import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.*; +import com.badlogic.gdx.utils.Array; import com.me.brickbuster.BrickBuster; -import com.me.brickbuster.entity.Ball; -import com.me.brickbuster.entity.Brick; -import com.me.brickbuster.entity.Paddle; -import com.me.brickbuster.entity.powerup.*; +import com.me.brickbuster.entity.*; +import com.me.brickbuster.entity.powerup.PowerUp; +import com.me.brickbuster.entity.powerup.PowerUpType; import com.me.brickbuster.physics.Box2dContactListener; -import java.util.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; public class PlayState extends State { @@ -22,8 +23,6 @@ public class PlayState extends State { public static final float BOARD_HEIGHT = 96f; public static final float EDGE_PADDING = .125f; - - public static final float SHIELD_HEIGHT = 0.75f; public static final float POWERUP_CHANCE = 0.15f; public static final int COLUMNS = 9; @@ -39,14 +38,16 @@ public class PlayState extends State { new Vector2(EDGE_PADDING, BrickBuster.BOARD_HEIGHT/PIXEL_PER_METER-EDGE_PADDING); public World world; + public Body playArea; + public Array bodies; public List powerUps; public Paddle paddle; public List balls; public List bricks; + public List shields; - private int shieldCount = 0; private float updateTime = 0f; private final Box2DDebugRenderer debugRenderer; @@ -64,7 +65,9 @@ public class PlayState extends State { // define a playArea body with position set to 0 BodyDef playAreaDef = new BodyDef(); + playAreaDef.type = BodyDef.BodyType.StaticBody; playAreaDef.position.set(new Vector2()); + EdgeShape screenEdge = new EdgeShape(); playArea = world.createBody(playAreaDef); @@ -78,8 +81,8 @@ public class PlayState extends State { screenEdge.set(upperLeftCorner, lowerLeftCorner); playArea.createFixture(screenEdge, 0f); // Bottom edge - screenEdge.set(lowerLeftCorner, lowerRightCorner); - playArea.createFixture(screenEdge, 0f); + //screenEdge.set(lowerLeftCorner, lowerRightCorner); + //playArea.createFixture(screenEdge, 0f); screenEdge.dispose(); powerUps = new ArrayList(); @@ -103,10 +106,21 @@ public class PlayState extends State { balls = new ArrayList(); balls.add(new Ball(this)); + + shields = new ArrayList(); } @Override public void render() { + Array bodies = new Array(); + world.getBodies(bodies); + for (Body b : bodies) { + Entity e = (Entity) b.getUserData(); + if (e instanceof Ball || e instanceof PowerUp) { + e.setPos(b.getPosition()); + } + } + long start = System.nanoTime(); for (Brick block : bricks) { block.render(game.sr); @@ -117,14 +131,12 @@ public class PlayState extends State { for (Ball ball : balls) { ball.render(game.sr); } + for (Shield shield : shields) { + shield.render(game.sr); + } paddle.render(game.sr); - if (getShieldCount() > 0) { - game.sr.begin(ShapeType.Filled); - game.sr.setColor(Color.SALMON); - game.sr.rect(0, 0, BrickBuster.BOARD_WIDTH, getShieldCount() * SHIELD_HEIGHT); - game.sr.end(); - } + //debugRenderer.render(world, game.cam.combined.cpy().scl(PIXEL_PER_METER)); long renderTime = System.nanoTime() - start; game.sb.begin(); @@ -132,22 +144,19 @@ public class PlayState extends State { game.font.draw(game.sb, String.format("FPS: %d Update: %.2f ms Render: %.2f ms", Gdx.graphics.getFramesPerSecond(), updateTime/1000000f, renderTime/1000000f), 10, BrickBuster.BOARD_HEIGHT-10); game.sb.end(); - - debugRenderer.render(world, game.cam.combined.cpy().scl(PIXEL_PER_METER)); } @Override public void update(float dt) { long start = System.nanoTime(); - world.step(dt, 6, 2); - paddle.update(dt); for (Iterator it = balls.iterator(); it.hasNext();) { Ball ball = it.next(); ball.update(dt); - if (ball.isDead()) { + if (ball.isDeleted()) { it.remove(); + world.destroyBody(ball.getBody()); } } if (balls.isEmpty()) { @@ -157,15 +166,36 @@ public class PlayState extends State { for (Iterator it = powerUps.iterator(); it.hasNext();) { PowerUp powerUp = it.next(); powerUp.update(dt); - if(powerUp.isCaught()) { + if(powerUp.isDeleted()) { it.remove(); + world.destroyBody(powerUp.getBody()); } } + for (Iterator it = shields.iterator(); it.hasNext();) { + Shield shield = it.next(); + shield.update(dt); + if(shield.isDeleted()) { + it.remove(); + world.destroyBody(shield.getBody()); + } + } + + for (Iterator it = bricks.iterator(); it.hasNext();) { + Brick brick = it.next(); + brick.update(dt); + if (brick.isDeleted()) { + it.remove(); + world.destroyBody(brick.getBody()); + } + } if (bricks.isEmpty()) { game.setScreen(new MenuState(game)); dispose(); + return; } + + world.step(dt, 6, 2); updateTime = System.nanoTime() - start; } @@ -173,6 +203,8 @@ public class PlayState extends State { public void dispose() { super.dispose(); + world.dispose(); + powerUps.clear(); powerUps = null; balls.clear(); @@ -183,25 +215,25 @@ public class PlayState extends State { } public int getShieldCount() { - return shieldCount; + return shields.size(); } public void addShield() { - shieldCount++; - paddle.setY(paddle.getY() + SHIELD_HEIGHT); + Shield shield = new Shield(this); + shields.add(shield); + paddle.setY(paddle.getY() + Shield.SHIELD_HEIGHT); for (Ball ball : balls) { if (ball.isStuck()) { - ball.setY(ball.getY() + SHIELD_HEIGHT); + ball.setY(ball.getY() + Shield.SHIELD_HEIGHT); } } } - public void removeShield() { - shieldCount--; - paddle.setY(paddle.getY() - SHIELD_HEIGHT); + public void removeShield(Shield shield) { + paddle.setY(paddle.getY() - Shield.SHIELD_HEIGHT); for (Ball ball : balls) { if (ball.isStuck()) { - ball.setY(ball.getY() - SHIELD_HEIGHT); + ball.setY(ball.getY() - Shield.SHIELD_HEIGHT); } } }