Compare commits

..

9 Commits

Author SHA1 Message Date
39ad9eb4b8 Unload assets with asset manager instead of disposing them 2018-11-22 23:06:47 +04:00
88833ae206 Add 15% powerup chance to level_1 and level_2 2018-11-22 23:06:29 +04:00
b1db9c7048 Spawn additional balls at point of existing balls 2018-11-22 22:47:42 +04:00
d32cccebd6 Add randomPowerUpChance to Level type.
Allow defining said chance in level files.
Generate powerups on the fly when a brick is hit and the chance is met
2018-11-22 21:46:49 +04:00
35dea75776 Reset sprite batch color when rendering menu button 2018-11-22 21:21:32 +04:00
a9bca04f1c Move Utils class to utils package 2018-11-22 21:13:01 +04:00
84cdddc4b9 Write a CompositeIterator and use it to clean up entity iteration 2018-11-22 21:12:35 +04:00
4d27a2671a Cleanup Brick.render() 2018-11-22 20:52:20 +04:00
451ca13566 Add missing semicolon. 2018-11-22 18:55:15 +04:00
17 changed files with 134 additions and 80 deletions

View File

@ -1,4 +1,5 @@
{
randomPowerUpChance: 0.15
bricks: [
{
row: 15

View File

@ -1,4 +1,5 @@
{
randomPowerUpChance: 0.15
bricks: [
{
row: 5

View File

@ -177,4 +177,8 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
return isStuck;
}
public void setStuck(boolean isStuck) {
this.isStuck = isStuck;
}
}

View File

@ -42,9 +42,7 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
@Override
public void render(SpriteBatch sb, ShapeRenderer sr) {
sb.setColor(type.getColor());
float x = pos.x - BRICK_WIDTH/2;
float y = pos.y - BRICK_HEIGHT/2;
sb.draw(region, x, y,
sb.draw(region, pos.x - BRICK_WIDTH/2, pos.y - BRICK_HEIGHT/2,
BRICK_WIDTH/2, BRICK_HEIGHT/2,
BRICK_WIDTH, BRICK_HEIGHT,
1f, 1f,
@ -167,6 +165,11 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
}
}
float powerUpChance = ((PlayState) state).currentLevel.getRandomPowerUpChance();
if (powerUpType == null && powerUpChance > 0f && MathUtils.randomBoolean(powerUpChance)) {
powerUpType = PowerUpType.getWeightedRandom();
}
if (powerUpType != null) {
((PlayState) state).powerUps.add(powerUpType.createInstance((PlayState) state, this));
}

View File

@ -31,7 +31,7 @@ public abstract class Entity {
}
public void setPos(Vector2 pos) {
this.pos = pos;
this.pos.set(pos);
}
public float getX() {

View File

@ -3,6 +3,7 @@ package com.me.brickbuster.entity.powerup;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.me.brickbuster.entity.Ball;
import com.me.brickbuster.entity.Paddle;
import com.me.brickbuster.state.PlayState;
@ -10,6 +11,7 @@ import com.me.brickbuster.state.PlayState;
public class MultiBallPowerUp extends PowerUp {
private Vector2 pos;
private static final Array<Ball> ballsToAdd = new Array<Ball>();
public MultiBallPowerUp(PlayState state, Vector2 brick, Color color) {
super(state, brick, color);
@ -18,10 +20,26 @@ public class MultiBallPowerUp extends PowerUp {
@Override
public void activate() {
for (int x = 0; x < 2; x++) {
Ball ball = new Ball((PlayState) state);
ball.launch();
((PlayState) state).balls.add(ball);
final Array<Ball> existing = ((PlayState) state).balls;
if (existing.size >= 3) {
return;
}
for (Ball b : existing) {
Vector2 velocity = b.getBody().getLinearVelocity();
velocity.setAngleRad(velocity.angleRad() - MathUtils.PI/8);
for (int x = 0; x < 2; x++) {
Ball ball = new Ball((PlayState) state);
ball.setX(b.getX());
ball.setY(b.getY());
ball.setStuck(false);
ball.getBody().setLinearVelocity(velocity);
ballsToAdd.add(ball);
velocity.setAngleRad(velocity.angleRad() + MathUtils.PI/4);
}
}
existing.addAll(ballsToAdd);
ballsToAdd.clear();
}
}

View File

@ -9,7 +9,6 @@ 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.Utils;
import com.me.brickbuster.entity.Ball;
import com.me.brickbuster.entity.Entity;
import com.me.brickbuster.entity.Paddle;
@ -17,7 +16,6 @@ import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
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, CollisionListener {

View File

@ -1,30 +1,26 @@
package com.me.brickbuster.layout;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Json;
import com.me.brickbuster.entity.Brick;
import com.me.brickbuster.state.FieldState;
import com.me.brickbuster.state.PlayState;
public class FileLayout implements BrickLayout {
private static final Json JSON = new Json();
private PlayState state;
private FieldState state;
private LevelJsonTemplate template;
private Array<Brick> bricks;
private FileHandle file;
public FileLayout(PlayState state, FileHandle file) {
public FileLayout(FieldState state, LevelJsonTemplate template) {
this.state = state;
this.file = file;
this.template = template;
}
@Override
public void initialize() {
bricks = new Array<Brick>();
LevelJsonTemplate level = JSON.fromJson(LevelJsonTemplate.class, file);
for (LevelJsonTemplate.BrickJsonTemplate brick : level.bricks) {
for (LevelJsonTemplate.BrickJsonTemplate brick : template.bricks) {
final float x = PlayState.EDGE_PADDING + Brick.BRICK_WIDTH/2 + brick.col * Brick.BRICK_WIDTH;
final float y = PlayState.EDGE_PADDING + Brick.BRICK_HEIGHT/2 + brick.row * Brick.BRICK_HEIGHT;

View File

@ -2,14 +2,19 @@ package com.me.brickbuster.layout;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.utils.Json;
import com.me.brickbuster.state.FieldState;
import com.me.brickbuster.state.PlayState;
public class FileLevelLoader implements LevelLoader {
private PlayState state;
private static final Json JSON = new Json();
private FieldState state;
private int level = 1;
public FileLevelLoader(PlayState state) {
public FileLevelLoader(FieldState state) {
this.state = state;
}
@ -17,8 +22,15 @@ public class FileLevelLoader implements LevelLoader {
public Level getNextLevel() {
FileHandle file = Gdx.files.internal("levels/level_" + level + ".json");
if (file.exists()) {
LevelJsonTemplate template = JSON.fromJson(LevelJsonTemplate.class, file);
Texture background = null;
if (template.backgroundFile != null && !"".equals(template.backgroundFile)) {
background = new Texture(Gdx.files.internal(template.backgroundFile));
}
level++;
return new Level(new FileLayout(state, file), null, null);
return new Level(new FileLayout(state, template), background, template.randomPowerUpChance);
}
return null;
}

View File

@ -15,7 +15,7 @@ public class GridLevelLoader implements LevelLoader {
private int playCount = 0;
public GridLevelLoader(PlayState state) {
this(state, false, false)
this(state, false, false);
}
public GridLevelLoader(PlayState state, boolean randomShape, boolean randomType) {

View File

@ -6,16 +6,16 @@ public class Level {
private final BrickLayout layout;
private final Texture background;
private final Texture border;
private final float randomPowerUpChance;
public Level(BrickLayout layout) {
this(layout, null, null);
this(layout, null, 0f);
}
public Level(BrickLayout layout, Texture background, Texture border) {
public Level(BrickLayout layout, Texture background, float randomPowerUpChance) {
this.layout = layout;
this.background = background;
this.border = border;
this.randomPowerUpChance = randomPowerUpChance;
}
public BrickLayout getLayout() {
@ -26,8 +26,8 @@ public class Level {
return background;
}
public Texture getBorder() {
return border;
public float getRandomPowerUpChance() {
return randomPowerUpChance;
}
}

View File

@ -9,7 +9,7 @@ import java.util.List;
public class LevelJsonTemplate {
public String backgroundFile;
public String borderFile;
public float randomPowerUpChance;
public List<BrickJsonTemplate> bricks;
public static class BrickJsonTemplate {

View File

@ -24,7 +24,7 @@ public abstract class FieldState extends State {
@Override
public void dispose() {
super.dispose();
textures.dispose();
game.assets.unload("textures.atlas");
}
}

View File

@ -2,6 +2,7 @@ package com.me.brickbuster.state;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector3;
import com.me.brickbuster.BrickBuster;
@ -23,6 +24,7 @@ public class MenuState extends State {
public void render() {
game.sb.setProjectionMatrix(game.cam.combined);
game.sb.begin();
game.sb.setColor(Color.WHITE);
game.sb.draw(playButton,
BrickBuster.BOARD_WIDTH/2-playButton.getWidth()/2,
BrickBuster.BOARD_HEIGHT/2-playButton.getHeight()/2);

View File

@ -2,17 +2,20 @@ package com.me.brickbuster.state;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
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.utils.CompositeIterator;
import com.me.brickbuster.entity.*;
import com.me.brickbuster.entity.powerup.PowerUp;
import com.me.brickbuster.layout.*;
import com.me.brickbuster.layout.BrickLayout;
import com.me.brickbuster.layout.FileLevelLoader;
import com.me.brickbuster.layout.Level;
import com.me.brickbuster.layout.LevelLoader;
import com.me.brickbuster.physics.Box2dContactListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import java.util.Iterator;
@ -81,25 +84,20 @@ public class PlayState extends FieldState {
long start = System.nanoTime();
game.sb.begin();
for (Brick block : bricks) {
block.render(game.sb, game.sr);
}
for (Ball ball : balls) {
ball.render(game.sb, game.sr);
Iterator<? extends Entity> it = CompositeIterator.concat(balls, bricks);
while (it.hasNext()) {
it.next().render(game.sb, game.sr);
}
game.sb.end();
for (PowerUp powerUp : powerUps) {
powerUp.render(game.sb, game.sr);
}
for (Shield shield : shields) {
shield.render(game.sb, game.sr);
it = CompositeIterator.concat(powerUps, shields);
while (it.hasNext()) {
it.next().render(game.sb, game.sr);
}
paddle.render(game.sb, game.sr);
//debugRenderer.render(world, game.cam.combined.cpy().scl(PIXEL_PER_METER));
long renderTime = System.nanoTime() - start;
game.fb.begin();
game.font.setColor(Color.GRAY);
game.font.draw(game.fb, String.format("FPS: %d Update: %.2f ms Render: %.2f ms",
@ -110,47 +108,26 @@ public class PlayState extends FieldState {
@Override
public void update(float dt) {
long start = System.nanoTime();
paddle.update(dt);
for (Iterator<Ball> it = balls.iterator(); it.hasNext();) {
Ball ball = it.next();
ball.update(dt);
if (ball.isDeleted()) {
Iterator<? extends Entity> it = CompositeIterator.concat(balls, powerUps, shields, bricks);
while (it.hasNext()) {
Entity ent = it.next();
ent.update(dt);
if (ent.isDeleted()) {
it.remove();
world.destroyBody(ball.getBody());
if (ent instanceof PhysicsBody) {
world.destroyBody(((PhysicsBody) ent).getBody());
}
ent.dispose();
}
}
if (balls.size == 0) {
ballReset();
}
for (Iterator<PowerUp> it = powerUps.iterator(); it.hasNext();) {
PowerUp powerUp = it.next();
powerUp.update(dt);
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();
brick.dispose();
world.destroyBody(brick.getBody());
}
}
if (bricks.size == 0) {
currentLevel = levelLoader.getNextLevel();
if (currentLevel == null) {
@ -161,7 +138,6 @@ public class PlayState extends FieldState {
}
return;
}
world.step(dt, 6, 2);
updateTime = System.nanoTime() - start;
}

View File

@ -0,0 +1,43 @@
package com.me.brickbuster.utils;
import java.util.Iterator;
public class CompositeIterator<T> implements Iterator<T> {
private short index = 0;
private Iterator<? extends T> iterator;
private Iterable<? extends T>[] iterables;
private CompositeIterator(Iterable<? extends T>... iterables) {
this.iterables = iterables;
this.iterator = iterables[index].iterator();
}
@Override
public boolean hasNext() {
if (iterator.hasNext()) {
return true;
} else {
if (++index < iterables.length) {
iterator = iterables[index].iterator();
return hasNext();
}
}
return false;
}
@Override
public T next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
public static <E> CompositeIterator<E> concat(Iterable<? extends E>... iterables) {
return new CompositeIterator<E>(iterables);
}
}

View File

@ -1,4 +1,4 @@
package com.me.brickbuster;
package com.me.brickbuster.utils;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;