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
This commit is contained in:
		| @ -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<Brick> 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<Vector2, Vector2> 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; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -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; | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -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<Vector2, Vector2> getTopEdge() { | ||||
| 		return new Pair<Vector2, Vector2>( | ||||
| 				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() { | ||||
|  | ||||
							
								
								
									
										67
									
								
								core/src/com/me/brickbuster/entity/Shield.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								core/src/com/me/brickbuster/entity/Shield.java
									
									
									
									
									
										Normal file
									
								
							| @ -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; | ||||
| 	} | ||||
| } | ||||
| @ -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); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -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<Vector2, Vector2> 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; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -4,6 +4,8 @@ import com.badlogic.gdx.physics.box2d.Body; | ||||
|  | ||||
| public interface PhysicsBody { | ||||
|  | ||||
| 	void createBody(); | ||||
|  | ||||
| 	Body getBody(); | ||||
|  | ||||
| } | ||||
|  | ||||
| @ -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<Body> bodies; | ||||
|  | ||||
| 	public List<PowerUp> powerUps; | ||||
| 	public Paddle paddle; | ||||
| 	public List<Ball> balls; | ||||
| 	public List<Brick> bricks; | ||||
| 	public List<Shield> 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<PowerUp>(); | ||||
| @ -103,10 +106,21 @@ public class PlayState extends State { | ||||
|  | ||||
| 		balls = new ArrayList<Ball>(); | ||||
| 		balls.add(new Ball(this)); | ||||
|  | ||||
| 		shields = new ArrayList<Shield>(); | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public void render() { | ||||
| 		Array<Body> bodies = new Array<Body>(); | ||||
| 		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<Ball> 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<PowerUp> 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<Shield> it = shields.iterator(); it.hasNext();) { | ||||
| 			Shield shield = it.next(); | ||||
| 			shield.update(dt); | ||||
| 			if(shield.isDeleted()) { | ||||
| 				it.remove(); | ||||
| 				world.destroyBody(shield.getBody()); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		for (Iterator<Brick> 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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
		Reference in New Issue
	
	Block a user