Refactor Part 1: ArrayLists

This commit is contained in:
naomi 2025-05-14 01:35:55 +00:00
parent 50cc8e2a7b
commit 475af2c03e
11 changed files with 938 additions and 775 deletions

View file

@ -1,12 +1,15 @@
package dev.boyfailure.quajra.vectorbreakout;
import java.util.Arrays;
public class Ball {
short ballX = 250;
short ballY = 300;
short ballWidth = 7;
short ballHeight = 7;
boolean isActive = false;
private boolean isActive = false;
private boolean isInvincible = false;
byte ballColor = 0;
Hitbox hitBox;
@ -28,11 +31,13 @@ public class Ball {
public void spawnBall(boolean useChancey) {
if (useChancey) {
this.ballX += (short) (gameState.chancey * 3);
this.ballY += (short) gameState.chancey;
this.ballX += (short) (gameState.getChancey() * 3);
this.ballY += (short) gameState.getChancey();
}
gameState.ballsOnScreen++;
this.isActive = true;
gameState.lives--;
gameState.textElementList.get(4).setText(String.valueOf(gameState.lives));
}
public void spawnBall(int x, int y) {
@ -40,6 +45,8 @@ public class Ball {
this.ballY = (short) y;
gameState.ballsOnScreen++;
this.isActive = true;
gameState.lives--;
gameState.textElementList.get(4).setText(String.valueOf(gameState.lives));
}
public void moveBall() {
@ -55,7 +62,7 @@ public class Ball {
switch((byte) bounceType) {
case 0:
this.speedY = (byte) -(this.speedY);
switch (gameState.chancey) {
switch (gameState.getChancey()) {
case 0: break;
case 1: this.speedX++; break;
case 2: break;
@ -110,25 +117,26 @@ public class Ball {
this.ballY = 32767;
gameState.ballsOnScreen--;
if (gameState.ballsOnScreen <= 0) {
gameState.lives--;
gameState.ballsOnScreen = 0;
if (gameState.lives <= 0) {
gameState.gameLose();
}
}
if (gameState.lives <= 0) {
gameState.gameLose();
}
gameState.currentTextElements[1].setText(String.valueOf(gameState.lives));
}
// Checks to see if the ball is in contact with bricks, paddles, or walls
public void checkCollision() {
this.setInvincibilityState(true); // Delay bouncing again for a frame
// Check floor
if (this.ballY >= gameState.gameResY) {
if (this.ballY >= gameState.getInternalResY()) {
this.destroyBall();
return;
}
// Check ceiling
else if (this.ballY <= 0) {
this.bounce((byte) 0);
this.bounce(0);
this.ballY = 0;
this.wallBounceAnimation();
return;
@ -136,105 +144,92 @@ public class Ball {
// Check walls
if (this.ballX <= 20) {
this.bounce((byte) 1);
this.bounce(1);
this.ballX = 22;
this.wallBounceAnimation();
return;
}
else if ((this.ballX + this.ballWidth) >= (gameState.gameResX - 20 - this.ballWidth)) {
else if ((this.ballX + this.ballWidth) >= (gameState.getInternalResX() - 20 - this.ballWidth)) {
this.bounce((byte) 1);
this.ballX = (short) (gameState.gameResX - 25 - this.ballWidth);
this.ballX = (short) (gameState.getInternalResX() - 25 - this.ballWidth);
this.wallBounceAnimation();
return;
}
// Check bricks
if (gameState.currentLevel != null) {
for (short i = 0; i < gameState.currentLevel.levelBricks.length; i++) {
if (gameState.currentLevel.levelBricks[i] != null && !gameState.currentLevel.levelBricks[i].isBroken) {
if (this.hitBox.collides(gameState.currentLevel.levelBricks[i].hitBox.bounds)) {
gameState.currentLevel.levelBricks[i].breakBrick();
this.bounce((byte) 0);
return;
if (gameState.currentLevel.brickList != null) {
for (Brick brick : gameState.currentLevel.brickList) {
if (this.hitBox.collides(brick.hitBox.getBounds())) {
brick.breakBrick();
this.bounce(0);
gameState.brickCollector.add(brick);
return;
}
}
}
}
// Check paddles
for (byte i = 0; i < gameState.currentPaddles.length; i++) {
if (gameState.currentPaddles[i] != null) {
if (this.hitBox.collides(gameState.currentPaddles[i].hitBox.bounds)) {
if (this.hitBox.collides(gameState.currentPaddles[i].hitBoxLeft.bounds)) {
this.bounce(2);
}
else if (this.hitBox.collides(gameState.currentPaddles[i].hitBoxRight.bounds)) {
this.bounce(3);
}
else {
this.bounce(0);
}
this.ballY -= 2;
// Draw particles
byte ballParticleGen = 0;
for (byte ii = 0; ii < gameState.currentParticles.length; ii++) {
if (gameState.currentParticles[ii] == null) {
ballParticleGen++;
switch(ballParticleGen) {
case 1:
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX, this.ballY - 10, 0, -2, 1, 2, 7, 3);
gameState.currentParticles[ii].spawn(5);
break;
case 2:
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX - 3, this.ballY - 10, -2, -4, 1, 2, 6, 3);
gameState.currentParticles[ii].spawn(5);
break;
case 3:
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX + 10, this.ballY - 10, 2, -4, 1, 2, 8, 3);
gameState.currentParticles[ii].spawn(5);
break;
}
if (ballParticleGen < 3) {continue;}
else {return;}
}
}
return;
for (Paddle paddle : gameState.paddleList) {
if (this.hitBox.collides(paddle.hitBox.getBounds())) {
if (this.hitBox.collides(paddle.hitBoxLeft.getBounds())) {
this.bounce(2);
}
else if (this.hitBox.collides(paddle.hitBoxRight.getBounds())) {
this.bounce(3);
}
else {
this.bounce(0);
}
this.ballY -= 2;
// Draw particles
Particle particle1, particle2, particle3;
particle1 = new Particle(gameState, 0, this.ballX, this.ballY - 10, 0, -2, 1, 2, 7, 3);
particle2 = new Particle(gameState, 0, this.ballX - 3, this.ballY - 10, -2, -4, 1, 2, 6, 3);
particle3 = new Particle(gameState, 0, this.ballX + 10, this.ballY - 10, 2, -4, 1, 2, 8, 3);
gameState.particleList.add(particle1);
gameState.particleList.add(particle2);
gameState.particleList.add(particle3);
particle1.spawn(5);
particle2.spawn(5);
particle3.spawn(5);
return; // Prevents bouncing multiple times
}
}
}
private void wallBounceAnimation() {
byte ballParticleGen = 0;
for (byte ii = 0; ii < gameState.currentParticles.length; ii++) {
if (gameState.currentParticles[ii] == null) {
ballParticleGen++;
switch(ballParticleGen) {
case 1: // Up left
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX - 3, this.ballY - 10, -2, -2, 1, 2, 6, 3);
gameState.currentParticles[ii].spawn(5);
break;
case 2: // Up right
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX + 10, this.ballY - 10, 2, -2, 1, 2, 8, 3);
gameState.currentParticles[ii].spawn(5);
break;
case 3: // Down right
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX - 3, this.ballY + 3, 2, 2, 1, 2, 2, 3);
gameState.currentParticles[ii].spawn(5);
break;
case 4: // Down left
gameState.currentParticles[ii] = new Particle(gameState, 0, this.ballX + 10, this.ballY + 3, -2, 2, 1, 2, 4, 3);
gameState.currentParticles[ii].spawn(5);
break;
}
if (ballParticleGen < 4) {continue;}
else {return;}
}
}
Particle particle1, particle2, particle3, particle4;
particle1 = new Particle(gameState, 0, this.ballX - 3, this.ballY - 10, -2, -2, 1, 2, 6, 3);
particle2 = new Particle(gameState, 0, this.ballX + 10, this.ballY - 10, 2, -2, 1, 2, 8, 3);
particle3 = new Particle(gameState, 0, this.ballX - 3, this.ballY + 3, 2, 2, 1, 2, 2, 3);
particle4 = new Particle(gameState, 0, this.ballX + 10, this.ballY + 3, -2, 2, 1, 2, 4, 3);
gameState.particleList.add(particle1);
gameState.particleList.add(particle2);
gameState.particleList.add(particle3);
gameState.particleList.add(particle4);
particle1.spawn(5);
particle2.spawn(5);
particle3.spawn(5);
particle4.spawn(5);
}
public boolean getActiveState() {
return this.isActive;
}
public void setActiveState(boolean activeState) {
this.isActive = activeState;
}
public boolean getInvincibilityState() {
return this.isInvincible;
}
public void setInvincibilityState(boolean invincibilityState) {
this.isInvincible = invincibilityState;
}
}

View file

@ -6,7 +6,7 @@ public class Brick {
short brickY;
short brickWidth = 40;
short brickHeight = 17;
boolean isBroken = false;
private boolean isBroken = false;
byte brickColor = 0;
byte scoreOnBreak = 10;
byte specialAbility = 0;
@ -39,20 +39,15 @@ public class Brick {
if (!isBroken) {
isBroken = true;
gameState.score += this.scoreOnBreak + (gameState.level - 1);
gameState.currentTextElements[0].setText(String.valueOf(gameState.score));
gameState.textElementList.get(3).setText(String.valueOf(gameState.score));
gameState.bricksOnScreen--;
switch(this.specialAbility) {
case 1:
gameState.lives++;
break;
case 2:
for (byte i = 0; i < gameState.currentBalls.length; i++) {
if (gameState.currentBalls[i] == null) {
gameState.currentBalls[i] = new Ball(gameState, 300, 300, 7, 7, 0, true);
gameState.currentBalls[i].spawnBall((this.brickX + (this.brickWidth / 2)), (this.brickY + (this.brickHeight / 2)));
return;
}
}
Ball ball = new Ball(gameState, 300, 300, 7, 7, 0, true);
ball.spawnBall((this.brickX + (this.brickWidth / 2)), (this.brickY + (this.brickHeight / 2)));
break;
default:
break;
@ -60,32 +55,27 @@ public class Brick {
}
// Draw particles
byte brickParticleGen = 0;
for (byte ii = 0; ii < gameState.currentParticles.length; ii++) {
if (gameState.currentParticles[ii] == null) {
brickParticleGen++;
switch(brickParticleGen) {
case 1:
gameState.currentParticles[ii] = new Particle(gameState, 0, this.brickX + 12, this.brickY + 3, 1, 1, this.brickColor, 2, 4, 1);
gameState.currentParticles[ii].spawn(5);
break;
case 2:
gameState.currentParticles[ii] = new Particle(gameState, 0, this.brickX + 20, this.brickY + 13, 1, 1, this.brickColor, 2, 3, 1);
gameState.currentParticles[ii].spawn(5);
break;
case 3:
gameState.currentParticles[ii] = new Particle(gameState, 0, this.brickX + 32, this.brickY + 7, 1, 1, this.brickColor, 2, 2, 1);
gameState.currentParticles[ii].spawn(5);
break;
}
if (brickParticleGen < 3) {continue;}
else {return;}
}
}
Particle particle1, particle2, particle3;
particle1 = new Particle(gameState, 0, this.brickX + 12, this.brickY + 3, 1, 1, this.brickColor, 2, 4, 1);
particle2 = new Particle(gameState, 0, this.brickX + 20, this.brickY + 13, 1, 1, this.brickColor, 2, 3, 1);
particle3 = new Particle(gameState, 0, this.brickX + 32, this.brickY + 7, 1, 1, this.brickColor, 2, 2, 1);
gameState.particleList.add(particle1);
gameState.particleList.add(particle2);
gameState.particleList.add(particle3);
particle1.spawn(5);
particle2.spawn(5);
particle3.spawn(5);
this.brickX = 32767;
this.brickY = 32767;
this.hitBox.moveTo(32760, 32760, 2, 2);
}
public boolean getBrokenState() {
return this.isBroken;
}
public void setBrokenState(boolean brokenState) {
this.isBroken = brokenState;
}
}

View file

@ -4,35 +4,48 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
public class GameState {
public String gameName = "Vector Breakout";
public String gameVersion = "20250511";
public boolean isGameStarted = false;
public boolean isPaused = false;
public boolean debugMenuEnabled = false;
private boolean isGameStarted = false;
private boolean isPaused = false;
private boolean debugMenuEnabled = false;
public boolean isLost = false;
public boolean movingLeft = false;
public boolean movingRight = false;
public boolean confettiMode = false;
public boolean collectorActive = false;
public byte lives = 5;
public byte chancey = 0;
private byte chancey = 0;
private final byte maxChanceyValue = 16;
public byte ballsOnScreen = 0;
public byte targetFrameRate = 60;
public byte actualFrames = 0;
public byte actualFrameRate = 0;
private short targetFrameRate = 60;
public short actualFrames = 0;
private short actualFrameRate = 0;
public byte gameTickRate = 60;
public short gameResX = 800;
public short gameResY = 600;
private short internalResX = 800;
private short internalResY = 600;
private short windowResX = 1024;
private short windowResY = 768;
public short level = 1;
public short bricksOnScreen = 0;
public int score = 0;
public long frameCounter = 0;
public Ball[] currentBalls = new Ball[10];
public Particle[] currentParticles = new Particle[127];
public Paddle[] currentPaddles = new Paddle[2];
public TextElement[] currentTextElements = new TextElement[63];
private long frameCounter = 0;
public ArrayList<Ball> ballList;
public ArrayList<Particle> particleList;
public ArrayList<Paddle> paddleList;
public ArrayList<TextElement> textElementList;
public ArrayList<Ball> ballCollector;
public ArrayList<Particle> particleCollector;
public ArrayList<Paddle> paddleCollector;
public ArrayList<TextElement> textElementCollector;
public ArrayList<Brick> brickCollector;
public Level currentLevel;
// Debug stuffs
@ -41,20 +54,13 @@ public class GameState {
public short debugStartLevel = 1;
public GameState() {
this.initComponents();
this.showTitleScreen();
}
public KeyListener getKeyListener() {
return new GameKeyListener();
}
public byte getGameTickRate() {
return gameTickRate;
}
public byte getTargetFrameRate() {
return targetFrameRate;
}
public ActionListener getGameStateUpdateActionListener() {
return new GameStateUpdateListener();
@ -63,62 +69,48 @@ public class GameState {
public ActionListener getGameTickActionListener() {
return new GameTickActionListener();
}
class GameTickActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
onGameTick();
}
}
class GameKeyListener implements KeyListener {
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case 27: // Escape
debugMenuEnabled = !debugMenuEnabled;
toggleDebugMenu();
break;
case 10: // Enter
if (isGameStarted) {
isPaused = !isPaused;
if (!isPaused) {
for (byte i = 0; i < currentTextElements.length; i++) {
if (currentTextElements[i] != null && "PAUSED".equals(currentTextElements[i].text)) {
currentTextElements[i].cull();
return;
}
}
if (GameState.this.getGameStartedState()) {
GameState.this.togglePausedState();
if (!GameState.this.getPausedState()) {
GameState.this.textElementList.get(6).setVisibility(false);
}
else {
for (byte i = 0; i < currentTextElements.length; i++) {
if (currentTextElements[i] == null) {
currentTextElements[i] = new TextElement(GameState.this, "PAUSED", 5, 142, 310, 1, 4);
currentTextElements[i].activate();
return;
}
}
GameState.this.textElementList.get(6).setVisibility(true);
}
}
break;
case 35: // End
if (isLost || !isGameStarted) {isGameStarted = true;newGame(true);return;}
if (isLost || !GameState.this.getGameStartedState()) {GameState.this.setGameStartedState(true);GameState.this.newGame(true);}
break;
case 32: // Space
if (isLost || !isGameStarted) {isGameStarted = true;newGame();return;}
if (!isPaused) {
if (isLost || !GameState.this.getGameStartedState()) {GameState.this.setGameStartedState(true);GameState.this.newGame();}
else if (!GameState.this.getPausedState()) {
if (ballsOnScreen < 1) {
for (byte i = 0; i < currentBalls.length; i++) {
if (currentBalls[i] == null) {
currentBalls[i] = new Ball(GameState.this, 200, 300, 7, 7, 0, true);
currentBalls[i].spawnBall(true);
if (!debugSpawnAllBalls) {return;}
}
}
Ball newBall = new Ball(GameState.this, 200, 300, 7, 7, 0, true);
GameState.this.ballList.add(newBall);
newBall.spawnBall(true);
}
}
break;
case 37: // Left
if (isGameStarted) {movingLeft = true;}
if (GameState.this.getGameStartedState()) {movingLeft = true;}
break;
case 39: // Right
if (isGameStarted) {movingRight = true;}
if (GameState.this.getGameStartedState()) {movingRight = true;}
break;
}
}
@ -137,117 +129,201 @@ public class GameState {
class GameStateUpdateListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
bricksOnScreen = 0;
actualFrameRate = actualFrames;
actualFrames = 0;
if (currentLevel != null) {
for (short i = 0; i < currentLevel.levelBricks.length; i++) {
if (currentLevel.levelBricks[i] != null) {
if (currentLevel.levelBricks[i].isBroken) {
currentLevel.levelBricks[i] = null;
}
else {bricksOnScreen++;}
}
}
}
for (byte i = 0; i < currentBalls.length; i++) {
if (currentBalls[i] != null) {
if (currentBalls[i].isActive == false) {
currentBalls[i] = null;
}
}
}
for (byte i = 0; i < currentParticles.length; i++) {
if (currentParticles[i] != null) {
if (currentParticles[i].isActive == false) {
currentParticles[i] = null;
}
}
}
for (byte i = 0; i < currentTextElements.length; i++) {
if (currentTextElements[i] != null) {
if (currentTextElements[i].active == false) {
currentTextElements[i] = null;
}
}
}
if (bricksOnScreen <= 0 && isGameStarted && !isLost) {
level++;
currentLevel = new Level(GameState.this, level);
currentLevel.startLevel();
GameState.this.collectorActive = true;
GameState.this.ballCollector = new ArrayList<>();
GameState.this.particleCollector = new ArrayList<>();
GameState.this.paddleCollector = new ArrayList<>();
GameState.this.textElementCollector = new ArrayList<>();
GameState.this.brickCollector = new ArrayList<>();
bricksOnScreen = 0;
actualFrameRate = actualFrames;
actualFrames = 0;
if (GameState.this.currentLevel != null) {
if (GameState.this.currentLevel.brickList != null) {
for (Brick brick : GameState.this.currentLevel.brickList) {
if (brick.getBrokenState()) {
GameState.this.brickCollector.add(brick);
//GameState.this.currentLevel.brickList.remove(brick);
}
else {
bricksOnScreen++;
}
}
}
}
for (Ball ball : GameState.this.ballList) {
if (!ball.getActiveState()) {
//GameState.this.ballList.remove(ball);
GameState.this.ballCollector.add(ball);
}
}
for (Particle particle: GameState.this.particleList) {
if (!particle.getActiveState()) {
//GameState.this.particleList.remove(particle);
GameState.this.particleCollector.add(particle);
}
}
if (bricksOnScreen <= 0 && GameState.this.getGameStartedState() && !isLost) {
level++;
GameState.this.currentLevel = new Level(GameState.this, level);
GameState.this.currentLevel.constructLevel();
}
GameState.this.ballList.removeAll(GameState.this.ballCollector);
GameState.this.paddleList.removeAll(GameState.this.paddleCollector);
GameState.this.particleList.removeAll(GameState.this.particleCollector);
GameState.this.textElementList.removeAll(GameState.this.textElementCollector);
if (GameState.this.currentLevel != null) {
GameState.this.currentLevel.brickList.removeAll(GameState.this.brickCollector);
}
GameState.this.collectorActive = false;
}
}
public void incrementFrameCounter() {
this.frameCounter++;
}
public void onGameTick() {
// i will implement something better than "chancey" eventually
chancey++;
if (chancey >= 16) {
chancey = 0;
public long getFrameCounter() {
return this.frameCounter;
}
public void incrementChancey() {
this.chancey++;
if (this.chancey >= this.maxChanceyValue) {
this.chancey = 0;
}
}
public byte getChancey() {
return this.chancey;
}
public byte getGameTickRate() {
return this.gameTickRate;
}
public short getTargetFrameRate() {
return this.targetFrameRate;
}
public short getActualFrameRate() {
return this.actualFrameRate;
}
public boolean getPausedState() {
return this.isPaused;
}
public void togglePausedState() {
this.isPaused = !this.isPaused;
}
public boolean getDebugMenuState() {
return this.debugMenuEnabled;
}
public void toggleDebugMenu() {
this.debugMenuEnabled = !this.debugMenuEnabled;
}
public boolean getGameStartedState() {
return this.isGameStarted;
}
public void setGameStartedState(boolean startState) {
this.isGameStarted = startState;
}
public short getInternalResX() {
return this.internalResX;
}
public short getInternalResY() {
return this.internalResY;
}
public short getWindowResX() {
return this.windowResX;
}
public short getWindowResY() {
return this.windowResY;
}
public void setWindowResX(short resolution) {
this.windowResX = resolution;
}
public void setWindowResY(short resolution) {
this.windowResY = resolution;
}
public void onGameTick() {
this.incrementChancey();
if (isPaused) {return;}
if (this.getPausedState()) {return;}
// Move player if keys are held
for (byte i = 0; i < currentPaddles.length; i++) {
if (currentPaddles[i] != null) {
if (movingLeft) {
currentPaddles[i].movePaddle(false);
}
else if (movingRight) {
currentPaddles[i].movePaddle(true);
}
else {
currentPaddles[i].paddleSpeed = 0;
}
for (Paddle paddle : this.paddleList) {
if (this.movingLeft) {
paddle.movePaddle(false);
}
else if (this.movingRight) {
paddle.movePaddle(true);
}
else {
paddle.paddleSpeed = 0;
}
}
// Ball logic (movement, collision checks)
for (byte i = 0; i < currentBalls.length; i++) {
if (currentBalls[i] != null) {
if (currentBalls[i].isActive) {
currentBalls[i].moveBall();
try {
for (Ball ball : this.ballList) {
if (ball.getActiveState()) {
ball.moveBall();
}
}
} catch(java.util.ConcurrentModificationException except) {
System.err.println("ConcurrentModificationException, onGameTick() Ball iteration\n"
+ "Resetting ballList ArrayList.");
// except.printStackTrace();
this.ballList = new ArrayList<>();
}
// Particles
for (byte i = 0; i < currentParticles.length; i++) {
if (currentParticles[i] != null) {
if (currentParticles[i].isActive) {
currentParticles[i].update();
}
for (Particle particle : this.particleList) {
if (particle.getActiveState()) {
particle.update();
}
}
}
public void showTitleScreen() {
currentTextElements[0] = new TextElement(this, "VECTOR BREAKOUT", 2.5f, 67, 280, 15, 2);
currentTextElements[1] = new TextElement(this, "MMXXV BOYFAILURE.DEV", 0.75f, 259, 315, 15, 1);
currentTextElements[2] = new TextElement(this, "PRESS SPACE TO BEGIN", 1, 215, 345, 15, 2);
currentTextElements[0].activate();
currentTextElements[1].activate();
currentTextElements[2].activate();
textElementList.get(0).activateTimer();
textElementList.get(1).activateTimer();
textElementList.get(2).activateTimer();
}
public void gameLose() {
if (currentLevel != null) {
for (short i = 0; i < currentLevel.levelBricks.length; i++) {
currentLevel.levelBricks[i] = null;
if (this.currentLevel != null) {
for (Brick brick : this.currentLevel.brickList) {
brick.setBrokenState(true);
this.brickCollector.add(brick);
}
}
for (byte i = 0; i < currentBalls.length; i++) {
currentBalls[i] = null;
for (Ball ball : this.ballList) {
ball.setActiveState(false);
this.ballCollector.add(ball);
}
isLost = true;
ballsOnScreen = 0;
for (Paddle paddle : this.paddleList) {
paddle.setActiveState(false);
this.paddleCollector.add(paddle);
}
this.isLost = true;
this.ballsOnScreen = 0;
this.textElementList.get(3).setVisibility(false);
this.textElementList.get(4).setVisibility(false);
this.textElementList.get(5).setVisibility(false);
this.textElementList.get(8).setVisibility(true);
this.textElementList.get(9).setVisibility(true);
this.getGameStateUpdateActionListener().actionPerformed(new ActionEvent(this, 0, ""));
}
public void newGame() {
@ -255,9 +331,6 @@ public class GameState {
}
public void newGame(boolean debugLevel) {
for (byte i = 0; i < currentTextElements.length; i++) {
currentTextElements[i] = null;
}
lives = 5;
isLost = false;
score = 0;
@ -267,17 +340,53 @@ public class GameState {
ballsOnScreen = 0;
movingLeft = false;
movingRight = false;
if (debugUseGiantPaddle) {currentPaddles[0] = new Paddle(this, 0, 500, 800, 60, 0);}
else {currentPaddles[0] = new Paddle(this, 350, 500, 100, 15, 0);}
currentTextElements[0] = new TextElement(this, String.valueOf(score), 1, 20, -13, 1, 2);
currentTextElements[1] = new TextElement(this, String.valueOf(lives), 1, 200, -13, 1, 2);
currentTextElements[2] = new TextElement(this, String.valueOf(level), 1, 380, -13, 1, 2);
currentTextElements[0].activate();
currentTextElements[1].activate();
currentTextElements[2].activate();
if (debugUseGiantPaddle) {this.paddleList.add(new Paddle(this, 0, 500, 800, 60, 0));}
else {this.paddleList.add(new Paddle(this, 350, 500, 100, 15, 0));}
if (this.debugUseGiantPaddle) {
this.paddleList.add(new Paddle(this, 0, 500, 800, 60, 0));
}
else {
this.paddleList.add(new Paddle(this, 350, 500, 100, 15, 0));
}
this.textElementList.get(0).setVisibility(false);
this.textElementList.get(1).setVisibility(false);
this.textElementList.get(2).setVisibility(false);
this.textElementList.get(3).setVisibility(true);
this.textElementList.get(4).setVisibility(true);
this.textElementList.get(5).setVisibility(true);
textElementList.get(3).setText(String.valueOf(this.score));
textElementList.get(4).setText(String.valueOf(this.lives));
textElementList.get(5).setText(String.valueOf(this.level));
this.textElementList.get(8).setVisibility(false);
this.textElementList.get(9).setVisibility(false);
if (debugStartLevel > 1) {level = debugStartLevel;}
currentLevel = new Level(this, level);
currentLevel.startLevel();
this.currentLevel = new Level(this, level);
this.currentLevel.constructLevel();
this.updateStaticTextElements();
}
public void initComponents() {
this.ballList = new ArrayList<>();
this.particleList = new ArrayList<>();
this.paddleList = new ArrayList<>();
this.textElementList = new ArrayList<>();
// List of indices
textElementList.add(new TextElement(this, "VECTOR BREAKOUT", 2.5f, 67, 280, 15, 2)); // 0 - Title
textElementList.add(new TextElement(this, "MMXXV BOYFAILURE.DEV", 0.75f, 259, 315, 15, 1)); // 1 - Copyright
textElementList.add(new TextElement(this, "PRESS SPACE TO BEGIN", 1, 215, 345, 15, 2)); // 2 - Space
textElementList.add(new TextElement(this, String.valueOf(score), 1, 20, -13, 1, 2)); // 3 - Score
textElementList.add(new TextElement(this, String.valueOf(lives), 1, 200, -13, 1, 2)); // 4 - Lives
textElementList.add(new TextElement(this, String.valueOf(level), 1, 380, -13, 1, 2)); // 5 - Level
textElementList.add(new TextElement(this, "PAUSED", 5, 142, 310, 1, 4)); // 6 - Paused
textElementList.add(new TextElement(this, "Level Name", 1, 24, 480, 15, 2, 3000)); // 7 - Level Name
textElementList.add(new TextElement(this, " GAME OVER ", 2.5f, 67, 280, 10, 2)); // 8 - Lose
textElementList.add(new TextElement(this, "PRESS SPACE TO RETRY", 1, 215, 315, 10, 1)); // 9 - Retry
}
public void updateStaticTextElements() {
textElementList.get(3).setText(String.valueOf(score));
textElementList.get(4).setText(String.valueOf(lives));
textElementList.get(5).setText(String.valueOf(level));
}
}

View file

@ -4,7 +4,7 @@ import java.awt.geom.Rectangle2D;
public class Hitbox {
Rectangle2D bounds;
private Rectangle2D bounds;
byte padding = 0;
public Hitbox(int x, int y, int x2, int y2, int padding) {
@ -25,4 +25,11 @@ public class Hitbox {
this.bounds.setRect(x - this.padding, y - this.padding, x2 + padding, y2 + padding);
}
public Rectangle2D getBounds() {
return this.bounds;
}
public void setBounds(int x, int y, int x2, int y2) {
this.bounds = new Rectangle2D.Float(x - this.padding, y - this.padding, x2 + this.padding, y2 + this.padding);
}
}

View file

@ -1,5 +1,7 @@
package dev.boyfailure.quajra.vectorbreakout;
import java.util.ArrayList;
public class Level {
short levelID;
@ -7,10 +9,11 @@ public class Level {
String levelName = "LEVEL";
byte[] levelLayout; // 19 bricks per row
byte[] colorMap;
Brick[] levelBricks;
ArrayList<Brick> brickList;
private GameState gameState;
public Level(GameState gameState, int id) {
this.gameState = gameState;
this.levelID = (short) id;
@ -190,50 +193,50 @@ public class Level {
}
}
public void startLevel() {
public void constructLevel() {
this.brickList = new ArrayList<>();
// Brick placement
short brickLeftPlacement = 20;
if (this.levelLayout != null) {
this.levelBricks = new Brick[this.levelLayout.length];
for (int i = 0; i < this.levelLayout.length; i++) {
switch (this.levelLayout[i]) {
case 1:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 4, 0);
break;
case 2:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0);
break;
case 3:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 16, 0);
break;
case 4:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 32, 0);
break;
case 5:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 64, 0);
break;
case 6:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0);
break;
case 7:
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0);
break;
case 16: // Spawns a ball
this.levelBricks[i] = new Brick(gameState, brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 2);
break;
default:
this.levelBricks[i] = null;
break;
}
brickLeftPlacement += 40;
if (brickLeftPlacement >= 760) {brickLeftPlacement = 20;}
for (int i = 0; i < this.levelLayout.length; i++) {
switch (this.levelLayout[i]) {
case 1:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 4, 0));
break;
case 2:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0));
break;
case 3:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 16, 0));
break;
case 4:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 32, 0));
break;
case 5:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 64, 0));
break;
case 6:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0));
break;
case 7:
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0));
break;
case 16: // Spawns a ball
this.brickList.add(new Brick(gameState, brickLeftPlacement, (((i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 2));
break;
default:
break;
}
brickLeftPlacement += 40;
if (brickLeftPlacement >= 760) {brickLeftPlacement = 20;}
}
gameState.bricksOnScreen = (short) this.levelBricks.length;
gameState.currentTextElements[2].setText(String.valueOf(this.levelID));
gameState.currentTextElements[3] = new TextElement(gameState, this.levelName, 1, 24, 480, 15, 2, 3000);
gameState.currentTextElements[3].activate();
this.startLevel();
}
public void startLevel() {
gameState.bricksOnScreen = (short) this.brickList.size();
gameState.textElementList.set(7, new TextElement(gameState, this.levelName, 1, 24, 480, 15, 2, 3000));
gameState.textElementList.get(7).activateTimer();
}
}

View file

@ -1,9 +1,13 @@
package dev.boyfailure.quajra.vectorbreakout;
import java.util.ArrayList;
public class Menu {
public String menuTitle = "Menu";
public byte index = 0;
private ArrayList<TextElement> textElementList;
private GameState gameState;
@ -11,4 +15,30 @@ public class Menu {
this.gameState = gameState;
}
/**
* Adds a TextElement to the Menu.
* @param text The text that will be displayed.
* @param textScale The size of the text on screen.
* @param x The x coordinate of the text's origin point.
* @param y The y coordinate of the text's origin point.
* @param textColor The color of the text.
* @param vectorScale The scale of the text.
*/
public void addTextElement(String text, float textScale, int x, int y, int textColor, float vectorScale) {
textElementList.add(new TextElement(this.gameState, text, textScale, x, y, textColor, vectorScale));
}
/**
* Gets the TextElement at the specified index in the Menu.
* @param index
* @return The TextElement at the index.
*/
public TextElement getTextElement(int index) {
return textElementList.get(index);
}
public void activate() {
}
}

View file

@ -33,7 +33,7 @@ public class Paddle {
if (direction) {this.paddleX += (this.paddleSpeed * this.speedMultiplier);}
else {this.paddleX -= (this.paddleSpeed * this.speedMultiplier);}
if (this.paddleX <= 20) {this.paddleX = 20;}
else if (this.paddleX >= (gameState.gameResX - this.paddleWidth - 20)) {this.paddleX = (short) (gameState.gameResX - this.paddleWidth - 20);}
else if (this.paddleX >= (gameState.getInternalResX() - this.paddleWidth - 20)) {this.paddleX = (short) (gameState.getInternalResX() - this.paddleWidth - 20);}
this.hitBox.moveTo(this.paddleX, this.paddleY, this.paddleWidth, this.paddleHeight);
this.hitBoxLeft.moveTo(this.paddleX, this.paddleY, this.paddleWidth / 5, this.paddleHeight);
@ -46,4 +46,11 @@ public class Paddle {
this.paddleY = 32767;
}
public boolean getActiveState() {
return this.isActive;
}
public void setActiveState(boolean activeState) {
this.isActive = activeState;
}
}

View file

@ -54,5 +54,9 @@ public class Particle {
this.isActive = false;
}
}
public boolean getActiveState() {
return this.isActive;
}
}

View file

@ -6,7 +6,8 @@ import java.util.TimerTask;
public class TextElement {
String text;
boolean active = false;
boolean active = true;
private boolean isVisible = false;
float textScale = 1;
float vectorScale = 1;
byte textColor;
@ -25,6 +26,7 @@ public class TextElement {
* @param x The x coordinate of the text's origin point.
* @param y The y coordinate of the text's origin point.
* @param textColor The color of the text.
* @param vectorScale The scale of the text.
*/
public TextElement(GameState gameState, String text, float textScale, int x, int y, int textColor, float vectorScale) {
this.gameState = gameState;
@ -44,6 +46,7 @@ public class TextElement {
* @param x The x coordinate of the text's origin point.
* @param y The y coordinate of the text's origin point.
* @param textColor The color of the text.
* @param vectorScale The scale of the text.
* @param duration How long the text will stay on screen, in milliseconds.
*/
public TextElement(GameState gameState, String text, float textScale, int x, int y, int textColor, float vectorScale, int duration) {
@ -57,29 +60,34 @@ public class TextElement {
this.duration = (short) duration;
this.creationTime = System.currentTimeMillis();
}
public boolean getActiveState() {
return this.active;
}
/**
* Prepares the TextElement for rendering.
*/
public void activate() {
public void activateTimer() {
this.active = true;
long testLong = this.creationTime;
if (this.duration > 0) {
Timer levelTitleGTFO = new Timer();
levelTitleGTFO.schedule(new TimerTask() {
public void run() {
for (byte i = 0; i < gameState.currentTextElements.length; i++) {
if (gameState.currentTextElements[i] != null) {
if (gameState.currentTextElements[i].creationTime == testLong) {
gameState.currentTextElements[i].cull();
}
}
}
TextElement.this.setVisibility(false);
}
}, this.duration);
}
this.setVisibility(true);
}
public boolean getVisibility() {
return this.isVisible;
}
public void setVisibility(boolean visibility) {
this.isVisible = visibility;
}
/**
* Prepares the TextElement for culling.
*/

View file

@ -28,7 +28,7 @@ public class VectorBreakout {
// Set the game window's properties
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameFrame.setTitle(gameState.gameName);
gameFrame.setSize(gameState.gameResX, gameState.gameResY);
gameFrame.setSize(gameState.getInternalResX(), gameState.getInternalResY());
gameFrame.getContentPane().setBackground(Color.black);
gameFrame.getContentPane().add(gameCanvas);
gameFrame.setVisible(true);
@ -38,8 +38,10 @@ public class VectorBreakout {
// Adapts vector drawing scale when the window is resized
gameFrame.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent componentEvent) {
GameDisplay.beamScaleX = gameFrame.getBounds().width / 800f;
GameDisplay.beamScaleY = gameFrame.getBounds().height / 600f;
gameState.setWindowResX((short) gameFrame.getBounds().width);
gameState.setWindowResY((short) gameFrame.getBounds().height);
gameCanvas.setBeamScaleX(gameState.getWindowResX() / 800f);
gameCanvas.setBeamScaleY(gameState.getWindowResY() / 600f);
}
});