Implementing state objects

This commit is contained in:
naomi 2025-05-11 05:09:50 +00:00
parent 0bb650e72e
commit 50cc8e2a7b
12 changed files with 813 additions and 499 deletions

View file

@ -1,11 +1,13 @@
# Vector Breakout
A clone of Breakout built using swing/awt in Java
A clone of Breakout built in pure Java, using AWT/Swing
Very early proof of concept for a "vector graphics engine" for arcade style games. Eventual plans to create a real vector graphics game engine, potentially using LWJGL, once I have enough knowledge and experience.
**Caveat emptor: I am a very novice programmer, and you might gag a bit when you see my code...**
The repository as is is built with JDK 21, but I am testing the code as far back as JDK 1.5.
This repository is built with JDK 21 (Maven), but I am testing the code as far back as JDK 1.5 (hurrah for people archiving old JDKs and NetBeans installers!).
Special thanks to my friend [Ada](https://github.com/ProphetofAtnu) for getting it through my head that I need to move game code out of the main class lal
___
@ -20,17 +22,8 @@ These controls may change, and I may add a controls config in the future.
___
## TODO
- Improve ball collision
- "Path-casting" (for lack of a better term) for ball collision
- The idea is to change ball collision to instead check if a brick/paddle/etc will be in its path in the next frame, and if so, execute the collision instructions
- Bouncing horizontally off the sides of bricks
- Implement levels as their own class
- Each level will have unique properties, like varying playfield width, brick count/layouts, etc
- Will be much better than just the single hardcoded level and each individual brick being put into an array
## ISSUES
- Ball sometimes passes through paddle, or gets stuck in right wall
- This should be fixed with the aforementioned collision changes once I get to that
## I AM AWARE THAT:
- I could use a switch statement for the score/lives/level display. However, I want backwards compatability because I'm a silly nerd :3, and JDK 1.5 doesn't support passing a split string through a switch statement. If there is a better way to get the individual digits, please let me know.
- Update hitboxes for bricks (the plan is to have individual sections of the brick make the ball move differently upon impact, sorta like how I did it in [the QuickBASIC version of the game](https://codeberg.org/boyfailure/quickout/src/branch/main/QUICKOUT.BAS))
- Add complete javadoc
- Implement menus
- Look into sound effects
- Clean up/optimize rendering code

18
pom.xml
View file

@ -1,15 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>dev.boyfailure.quajra</groupId>
<artifactId>VectorBreakout</artifactId>
<version>1.0-SNAPSHOT</version>
<version>20250411_test1</version>
<packaging>jar</packaging>
<name>Vector Breakout</name>
<description>A clone of Breakout with a QuadraScan-inspired vector graphics artstyle.</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>21</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<exec.mainClass>dev.boyfailure.quajra.vectorbreakout.VectorBreakout</exec.mainClass>
</properties>
<build>
<plugins>
<plugin>
@ -26,4 +37,5 @@
</plugin>
</plugins>
</build>
</project>

View file

@ -13,7 +13,10 @@ public class Ball {
byte speedX = 5;
byte speedY = 5;
public Ball(int x, int y, int width, int height, int color, boolean active) {
private GameState gameState;
public Ball(GameState gameState, int x, int y, int width, int height, int color, boolean active) {
this.gameState = gameState;
this.ballX = (short) x;
this.ballY = (short) y;
this.ballWidth = (short) width;
@ -25,17 +28,17 @@ public class Ball {
public void spawnBall(boolean useChancey) {
if (useChancey) {
this.ballX += (short) (VectorBreakout.chancey * 3);
this.ballY += (short) VectorBreakout.chancey;
this.ballX += (short) (gameState.chancey * 3);
this.ballY += (short) gameState.chancey;
}
VectorBreakout.ballsOnScreen++;
gameState.ballsOnScreen++;
this.isActive = true;
}
public void spawnBall(int x, int y) {
this.ballX = (short) x;
this.ballY = (short) y;
VectorBreakout.ballsOnScreen++;
gameState.ballsOnScreen++;
this.isActive = true;
}
@ -52,7 +55,7 @@ public class Ball {
switch((byte) bounceType) {
case 0:
this.speedY = (byte) -(this.speedY);
switch (VectorBreakout.chancey) {
switch (gameState.chancey) {
case 0: break;
case 1: this.speedX++; break;
case 2: break;
@ -105,21 +108,21 @@ public class Ball {
this.isActive = false;
this.ballX = 32767;
this.ballY = 32767;
VectorBreakout.ballsOnScreen--;
if (VectorBreakout.ballsOnScreen <= 0) {
VectorBreakout.lives--;
gameState.ballsOnScreen--;
if (gameState.ballsOnScreen <= 0) {
gameState.lives--;
}
if (VectorBreakout.lives <= 0) {
VectorBreakout.gameLose();
if (gameState.lives <= 0) {
gameState.gameLose();
}
VectorBreakout.currentTextElements[1].setText(String.valueOf(VectorBreakout.lives));
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() {
// Check floor
if (this.ballY >= VectorBreakout.gameResY) {
if (this.ballY >= gameState.gameResY) {
this.destroyBall();
return;
}
@ -138,19 +141,19 @@ public class Ball {
this.wallBounceAnimation();
return;
}
else if ((this.ballX + this.ballWidth) >= (VectorBreakout.gameResX - 20 - this.ballWidth)) {
else if ((this.ballX + this.ballWidth) >= (gameState.gameResX - 20 - this.ballWidth)) {
this.bounce((byte) 1);
this.ballX = (short) (VectorBreakout.gameResX - 25 - this.ballWidth);
this.ballX = (short) (gameState.gameResX - 25 - this.ballWidth);
this.wallBounceAnimation();
return;
}
// Check bricks
if (VectorBreakout.currentLevel != null) {
for (short i = 0; i < VectorBreakout.currentLevel.levelBricks.length; i++) {
if (VectorBreakout.currentLevel.levelBricks[i] != null && !VectorBreakout.currentLevel.levelBricks[i].isBroken) {
if (this.hitBox.collides(VectorBreakout.currentLevel.levelBricks[i].hitBox.bounds)) {
VectorBreakout.currentLevel.levelBricks[i].breakBrick();
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;
}
@ -159,14 +162,14 @@ public class Ball {
}
// Check paddles
for (byte i = 0; i < VectorBreakout.currentPaddles.length; i++) {
if (VectorBreakout.currentPaddles[i] != null) {
if (this.hitBox.collides(VectorBreakout.currentPaddles[i].hitBox.bounds)) {
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(VectorBreakout.currentPaddles[i].hitBoxLeft.bounds)) {
if (this.hitBox.collides(gameState.currentPaddles[i].hitBoxLeft.bounds)) {
this.bounce(2);
}
else if (this.hitBox.collides(VectorBreakout.currentPaddles[i].hitBoxRight.bounds)) {
else if (this.hitBox.collides(gameState.currentPaddles[i].hitBoxRight.bounds)) {
this.bounce(3);
}
else {
@ -177,21 +180,21 @@ public class Ball {
// Draw particles
byte ballParticleGen = 0;
for (byte ii = 0; ii < VectorBreakout.currentParticles.length; ii++) {
if (VectorBreakout.currentParticles[ii] == null) {
for (byte ii = 0; ii < gameState.currentParticles.length; ii++) {
if (gameState.currentParticles[ii] == null) {
ballParticleGen++;
switch(ballParticleGen) {
case 1:
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX, this.ballY - 10, 0, -2, 1, 2, 7, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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:
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX - 3, this.ballY - 10, -2, -4, 1, 2, 6, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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:
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX + 10, this.ballY - 10, 2, -4, 1, 2, 8, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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;}
@ -207,25 +210,25 @@ public class Ball {
private void wallBounceAnimation() {
byte ballParticleGen = 0;
for (byte ii = 0; ii < VectorBreakout.currentParticles.length; ii++) {
if (VectorBreakout.currentParticles[ii] == null) {
for (byte ii = 0; ii < gameState.currentParticles.length; ii++) {
if (gameState.currentParticles[ii] == null) {
ballParticleGen++;
switch(ballParticleGen) {
case 1: // Up left
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX - 3, this.ballY - 10, -2, -2, 1, 2, 6, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX + 10, this.ballY - 10, 2, -2, 1, 2, 8, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX - 3, this.ballY + 3, 2, 2, 1, 2, 2, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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
VectorBreakout.currentParticles[ii] = new Particle(0, this.ballX + 10, this.ballY + 3, -2, 2, 1, 2, 4, 3);
VectorBreakout.currentParticles[ii].spawn(5);
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;}

View file

@ -12,16 +12,20 @@ public class Brick {
byte specialAbility = 0;
Hitbox hitBox;
private GameState gameState;
/**
* Bricks.
* @param x The x coordinate
* @param y The y coordinate
* @param isBroken Is it broken
* @param brickColor The color of the brick
* @param score The score the player receives upon breaking the brick
* @param specialAbility A special event that occurs upon breaking the brick
* @param gameState The GameState in which the Brick will reside.
* @param x The x coordinate of the Brick.
* @param y The y coordinate of the Brick.
* @param isBroken Determines whether the Brick is broken.
* @param brickColor The color code of the Brick.
* @param score The score the Player earns upon breaking the Brick.
* @param specialAbility A special event that occurs upon breaking the Brick.
*/
public Brick(int x, int y, boolean isBroken, int brickColor, int score, int specialAbility) {
public Brick(GameState gameState, int x, int y, boolean isBroken, int brickColor, int score, int specialAbility) {
this.gameState = gameState;
this.brickX = (short) x;
this.brickY = (short) y;
this.isBroken = isBroken;
@ -34,18 +38,18 @@ public class Brick {
public void breakBrick() {
if (!isBroken) {
isBroken = true;
VectorBreakout.score += this.scoreOnBreak + (VectorBreakout.level - 1);
VectorBreakout.currentTextElements[0].setText(String.valueOf(VectorBreakout.score));
VectorBreakout.bricksOnScreen--;
gameState.score += this.scoreOnBreak + (gameState.level - 1);
gameState.currentTextElements[0].setText(String.valueOf(gameState.score));
gameState.bricksOnScreen--;
switch(this.specialAbility) {
case 1:
VectorBreakout.lives++;
gameState.lives++;
break;
case 2:
for (byte i = 0; i < VectorBreakout.currentBalls.length; i++) {
if (VectorBreakout.currentBalls[i] == null) {
VectorBreakout.currentBalls[i] = new Ball(300, 300, 7, 7, 0, true);
VectorBreakout.currentBalls[i].spawnBall((this.brickX + (this.brickWidth / 2)), (this.brickY + (this.brickHeight / 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;
}
}
@ -57,21 +61,21 @@ public class Brick {
// Draw particles
byte brickParticleGen = 0;
for (byte ii = 0; ii < VectorBreakout.currentParticles.length; ii++) {
if (VectorBreakout.currentParticles[ii] == null) {
for (byte ii = 0; ii < gameState.currentParticles.length; ii++) {
if (gameState.currentParticles[ii] == null) {
brickParticleGen++;
switch(brickParticleGen) {
case 1:
VectorBreakout.currentParticles[ii] = new Particle(0, this.brickX + 12, this.brickY + 3, 1, 1, this.brickColor, 2, 4, 1);
VectorBreakout.currentParticles[ii].spawn(5);
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:
VectorBreakout.currentParticles[ii] = new Particle(0, this.brickX + 20, this.brickY + 13, 1, 1, this.brickColor, 2, 3, 1);
VectorBreakout.currentParticles[ii].spawn(5);
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:
VectorBreakout.currentParticles[ii] = new Particle(0, this.brickX + 32, this.brickY + 7, 1, 1, this.brickColor, 2, 2, 1);
VectorBreakout.currentParticles[ii].spawn(5);
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;}

View file

@ -9,49 +9,55 @@ import java.awt.geom.Line2D;
public class GameDisplay extends JComponent {
float beamX = 0; // Horizontal location of "vector beam"
float beamY = 0; // Vertical location of "vector beam"
// Change this to 1 if you build for older versions of Java. Older versions
// will render a leading zero otherwise. (tested on JDK 1.5)
byte iStart = 0;
float beamX = 0; // Horizontal location of "vector beam"
float beamY = 0; // Vertical location of "vector beam"
public static float beamScaleX = 1; // Horizontal drawing scale
public static float beamScaleY = 1; // Vertical drawing scale
public static float beamThicknessScale = 1; // Thickness of lines
private GameState gameState;
public GameDisplay(GameState gameState) {
this.gameState = gameState;
}
public void paint(Graphics gameGraphics) {
super.paint(gameGraphics);
Graphics2D g2 = (Graphics2D) gameGraphics;
g2.setColor(Color.white);
// Walls
g2.setColor(Color.gray);
g2.setStroke(bt(10));
resetBeam();
moveBeam(15, 0);
g2.draw(drawVec(0, 600));
moveBeam(770, 0);
g2.draw(drawVec(0, -600));
moveBeam(15, -5);
g2.draw(drawVec(-800, 0));
if (gameState.isGameStarted) {
g2.setColor(Color.gray);
g2.setStroke(bt(10));
resetBeam();
moveBeam(15, 0);
g2.draw(drawVec(0, 600));
moveBeam(770, 0);
g2.draw(drawVec(0, -600));
moveBeam(15, -5);
g2.draw(drawVec(-800, 0));
}
// Bricks
if (VectorBreakout.currentLevel != null) {
for (short i = 0; i < VectorBreakout.currentLevel.levelBricks.length; i++) {
if (VectorBreakout.currentLevel.levelBricks[i] != null) {
if (VectorBreakout.currentLevel.levelBricks[i].isBroken == false) {
if (gameState.currentLevel != null) {
for (short i = 0; i < gameState.currentLevel.levelBricks.length; i++) {
if (gameState.currentLevel.levelBricks[i] != null) {
if (gameState.currentLevel.levelBricks[i].isBroken == false) {
resetBeam();
g2.setStroke(bt(3));
moveBeam(VectorBreakout.currentLevel.levelBricks[i].brickX + 1, VectorBreakout.currentLevel.levelBricks[i].brickY + 1);
g2.setColor(vc(VectorBreakout.currentLevel.levelBricks[i].brickColor));
g2.draw(drawVec(VectorBreakout.currentLevel.levelBricks[i].brickWidth - 2, 0));
g2.draw(drawVec(0, -(VectorBreakout.currentLevel.levelBricks[i].brickHeight - 2)));
g2.draw(drawVec(-(VectorBreakout.currentLevel.levelBricks[i].brickWidth - 2), 0));
g2.draw(drawVec(0, VectorBreakout.currentLevel.levelBricks[i].brickHeight - 2));
moveBeam(gameState.currentLevel.levelBricks[i].brickX + 1, gameState.currentLevel.levelBricks[i].brickY + 1);
g2.setColor(vc(gameState.currentLevel.levelBricks[i].brickColor));
g2.draw(drawVec(gameState.currentLevel.levelBricks[i].brickWidth - 2, 0));
g2.draw(drawVec(0, -(gameState.currentLevel.levelBricks[i].brickHeight - 2)));
g2.draw(drawVec(-(gameState.currentLevel.levelBricks[i].brickWidth - 2), 0));
g2.draw(drawVec(0, gameState.currentLevel.levelBricks[i].brickHeight - 2));
}
}
}
@ -59,16 +65,16 @@ public class GameDisplay extends JComponent {
// Paddles
g2.setColor(Color.white);
for (byte i = 0; i < VectorBreakout.currentPaddles.length; i++) {
if (VectorBreakout.currentPaddles[i] != null) {
if (VectorBreakout.currentPaddles[i].isActive) {
for (byte i = 0; i < gameState.currentPaddles.length; i++) {
if (gameState.currentPaddles[i] != null) {
if (gameState.currentPaddles[i].isActive) {
resetBeam();
g2.setStroke(bt(3));
moveBeam(VectorBreakout.currentPaddles[i].paddleX, VectorBreakout.currentPaddles[i].paddleY);
g2.draw(drawVec(VectorBreakout.currentPaddles[i].paddleWidth, 0));
g2.draw(drawVec(0, -(VectorBreakout.currentPaddles[i].paddleHeight)));
g2.draw(drawVec(-(VectorBreakout.currentPaddles[i].paddleWidth), 0));
g2.draw(drawVec(0, VectorBreakout.currentPaddles[i].paddleHeight));
moveBeam(gameState.currentPaddles[i].paddleX, gameState.currentPaddles[i].paddleY);
g2.draw(drawVec(gameState.currentPaddles[i].paddleWidth, 0));
g2.draw(drawVec(0, -(gameState.currentPaddles[i].paddleHeight)));
g2.draw(drawVec(-(gameState.currentPaddles[i].paddleWidth), 0));
g2.draw(drawVec(0, gameState.currentPaddles[i].paddleHeight));
}
}
}
@ -76,28 +82,28 @@ public class GameDisplay extends JComponent {
// Balls
g2.setStroke(bt(3));
g2.setColor(Color.yellow);
for (byte i = 0; i < VectorBreakout.currentBalls.length; i++) {
if (VectorBreakout.currentBalls[i] != null) {
if (VectorBreakout.currentBalls[i].isActive) {
for (byte i = 0; i < gameState.currentBalls.length; i++) {
if (gameState.currentBalls[i] != null) {
if (gameState.currentBalls[i].isActive) {
resetBeam();
moveBeam(VectorBreakout.currentBalls[i].ballX, VectorBreakout.currentBalls[i].ballY);
g2.draw(drawVec(VectorBreakout.currentBalls[i].ballWidth, 0));
g2.draw(drawVec(0, -VectorBreakout.currentBalls[i].ballHeight));
g2.draw(drawVec(-VectorBreakout.currentBalls[i].ballWidth, 0));
g2.draw(drawVec(0, VectorBreakout.currentBalls[i].ballHeight));
moveBeam(gameState.currentBalls[i].ballX, gameState.currentBalls[i].ballY);
g2.draw(drawVec(gameState.currentBalls[i].ballWidth, 0));
g2.draw(drawVec(0, -gameState.currentBalls[i].ballHeight));
g2.draw(drawVec(-gameState.currentBalls[i].ballWidth, 0));
g2.draw(drawVec(0, gameState.currentBalls[i].ballHeight));
}
}
}
// Particles
for (byte i = 0; i < VectorBreakout.currentParticles.length; i++) {
if (VectorBreakout.currentParticles[i] != null) {
if (VectorBreakout.currentParticles[i].isActive) {
for (byte i = 0; i < gameState.currentParticles.length; i++) {
if (gameState.currentParticles[i] != null) {
if (gameState.currentParticles[i].isActive) {
resetBeam();
moveBeam(VectorBreakout.currentParticles[i].particleX, VectorBreakout.currentParticles[i].particleY);
g2.setStroke(bt(VectorBreakout.currentParticles[i].vectorScale));
g2.setColor(vc(VectorBreakout.currentParticles[i].particleColor));
g2.draw(drawVec(VectorBreakout.currentParticles[i].particleX2, VectorBreakout.currentParticles[i].particleY2));
moveBeam(gameState.currentParticles[i].particleX, gameState.currentParticles[i].particleY);
g2.setStroke(bt(gameState.currentParticles[i].vectorScale));
g2.setColor(vc(gameState.currentParticles[i].particleColor));
g2.draw(drawVec(gameState.currentParticles[i].particleX2, gameState.currentParticles[i].particleY2));
}
}
}
@ -113,31 +119,110 @@ public class GameDisplay extends JComponent {
* systems, I used these goofy if/else statements so I could compile
* on the older JDKs and play on my older systems...
*/
for (byte i = 0; i < VectorBreakout.currentTextElements.length; i++) {
if (VectorBreakout.currentTextElements[i] != null) {
if (VectorBreakout.currentTextElements[i].active) {
for (byte i = 0; i < gameState.currentTextElements.length; i++) {
if (gameState.currentTextElements[i] != null) {
if (gameState.currentTextElements[i].active) {
resetBeam();
moveBeam(VectorBreakout.currentTextElements[i].x, VectorBreakout.currentTextElements[i].y);
moveBeam(gameState.currentTextElements[i].x, gameState.currentTextElements[i].y);
// Save the current beam scale to revert once TextElement is done rendering
float oldBeamScaleX = beamScaleX;
float oldBeamScaleY = beamScaleY;
beamScaleX = beamScaleX * VectorBreakout.currentTextElements[i].textScale;
beamScaleY = beamScaleY * VectorBreakout.currentTextElements[i].textScale;
g2.setColor(vc(VectorBreakout.currentTextElements[i].textColor));
g2.setStroke(bt(VectorBreakout.currentTextElements[i].vectorScale));
String stringToSplit = String.valueOf(VectorBreakout.currentTextElements[i].text);
// Adjust the beam scale to accomodate the scale of the TextElement
beamScaleX = beamScaleX * gameState.currentTextElements[i].textScale;
beamScaleY = beamScaleY * gameState.currentTextElements[i].textScale;
// Render the TextElement
g2.setColor(vc(gameState.currentTextElements[i].textColor));
g2.setStroke(bt(gameState.currentTextElements[i].vectorScale));
String stringToSplit = String.valueOf(gameState.currentTextElements[i].text);
String[] stringToRender = stringToSplit.split("");
//<editor-fold defaultstate="collapsed" desc=" Beam routines for letters/numbers ">
for (short ii = iStart; ii < stringToRender.length; ii++) {
if ("1".equals(stringToRender[ii])) {moveBeam(7, 0);g2.draw(drawVec(0, -24));moveBeam(11, 24);}
else if ("2".equals(stringToRender[ii])) {moveBeam(0, -24);g2.draw(drawVec(14, 0));g2.draw(drawVec(0, 12));g2.draw(drawVec(-14, 0));g2.draw(drawVec(0, 12));g2.draw(drawVec(14, 0));moveBeam(4, 0);}
else if ("3".equals(stringToRender[ii])) {moveBeam(0, -24);g2.draw(drawVec(14, 0));g2.draw(drawVec(0, 12));g2.draw(drawVec(-14, 0));moveBeam(14, 0);g2.draw(drawVec(0, 12));g2.draw(drawVec(-14, 0));moveBeam(18, 0);}
else if ("4".equals(stringToRender[ii])) {moveBeam(0, -24);g2.draw(drawVec(0, 12));g2.draw(drawVec(14, 0));moveBeam(0, -12);g2.draw(drawVec(0, 24));moveBeam(4, 0);}
else if ("5".equals(stringToRender[ii]) || "S".equals(stringToRender[ii])) {moveBeam(14, -24);g2.draw(drawVec(-14, 0));g2.draw(drawVec(0, 12));g2.draw(drawVec(14, 0));g2.draw(drawVec(0, 12));g2.draw(drawVec(-14, 0));moveBeam(18, 0);}
else if ("6".equals(stringToRender[ii])) {moveBeam(0, -24);g2.draw(drawVec(0, 24));g2.draw(drawVec(14, 0));g2.draw(drawVec(0, -12));g2.draw(drawVec(-14, 0));moveBeam(18, 12);}
else if ("7".equals(stringToRender[ii])) {moveBeam(0, -24);g2.draw(drawVec(14, 0));g2.draw(drawVec(0, 24));moveBeam(4, 0);}
else if ("8".equals(stringToRender[ii])) {g2.draw(drawVec(0, -24));g2.draw(drawVec(14, 0));g2.draw(drawVec(0, 24));g2.draw(drawVec(-14, 0));moveBeam(0, -12);g2.draw(drawVec(14, 0));moveBeam(4, 12);}
else if ("9".equals(stringToRender[ii])) {moveBeam(14, 0);g2.draw(drawVec(0, -24));g2.draw(drawVec(-14, 0));g2.draw(drawVec(0, 12));g2.draw(drawVec(14, 0));moveBeam(4, 12);}
else if ("0".equals(stringToRender[ii]) || "O".equals(stringToRender[ii])) {g2.draw(drawVec(14, 0));g2.draw(drawVec(0, -24));g2.draw(drawVec(-14, 0));g2.draw(drawVec(0, 24));moveBeam(18, 0);}
else if ("\\".equals(stringToRender[ii])) {moveBeam(-(beamX - VectorBreakout.currentTextElements[i].x), 30);} // Newline
if ("1".equals(stringToRender[ii])) {
moveBeam(7, 0);
g2.draw(drawVec(0, -24));
moveBeam(11, 24);
}
else if ("2".equals(stringToRender[ii])) {
moveBeam(0, -24);
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, 12));
g2.draw(drawVec(-14, 0));
g2.draw(drawVec(0, 12));
g2.draw(drawVec(14, 0));
moveBeam(4, 0);
}
else if ("3".equals(stringToRender[ii])) {
moveBeam(0, -24);
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, 12));
g2.draw(drawVec(-14, 0));
moveBeam(14, 0);
g2.draw(drawVec(0, 12));
g2.draw(drawVec(-14, 0));
moveBeam(18, 0);
}
else if ("4".equals(stringToRender[ii])) {
moveBeam(0, -24);
g2.draw(drawVec(0, 12));
g2.draw(drawVec(14, 0));
moveBeam(0, -12);
g2.draw(drawVec(0, 24));
moveBeam(4, 0);
}
else if ("5".equals(stringToRender[ii]) || "S".equals(stringToRender[ii])) {
moveBeam(14, -24);
g2.draw(drawVec(-14, 0));
g2.draw(drawVec(0, 12));
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, 12));
g2.draw(drawVec(-14, 0));
moveBeam(18, 0);
}
else if ("6".equals(stringToRender[ii])) {
moveBeam(0, -24);
g2.draw(drawVec(0, 24));
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, -12));
g2.draw(drawVec(-14, 0));
moveBeam(18, 12);
}
else if ("7".equals(stringToRender[ii])) {
moveBeam(0, -24);
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, 24));
moveBeam(4, 0);
}
else if ("8".equals(stringToRender[ii])) {
g2.draw(drawVec(0, -24));
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, 24));
g2.draw(drawVec(-14, 0));
moveBeam(0, -12);
g2.draw(drawVec(14, 0));
moveBeam(4, 12);
}
else if ("9".equals(stringToRender[ii])) {
moveBeam(14, 0);
g2.draw(drawVec(0, -24));
g2.draw(drawVec(-14, 0));
g2.draw(drawVec(0, 12));
g2.draw(drawVec(14, 0));
moveBeam(4, 12);
}
else if ("0".equals(stringToRender[ii]) || "O".equals(stringToRender[ii])) {
g2.draw(drawVec(14, 0));
g2.draw(drawVec(0, -24));
g2.draw(drawVec(-14, 0));
g2.draw(drawVec(0, 24));
moveBeam(18, 0);
}
// Simulates a newline in a TextElement
else if ("\\".equals(stringToRender[ii])) {
moveBeam(-(beamX - gameState.currentTextElements[i].x), 30);
}
else if ("A".equals(stringToRender[ii])) {
g2.draw(drawVec(0, -17));
g2.draw(drawVec(7, -7));
@ -359,100 +444,91 @@ public class GameDisplay extends JComponent {
g2.draw(drawVec(0, -12));
moveBeam(11, 24);
}
else if ("(".equals(stringToRender[ii])) {
moveBeam(10, 0);
g2.draw(drawVec(-6, -6));
g2.draw(drawVec(0, -12));
g2.draw(drawVec(6, -6));
moveBeam(8, 24);
}
else if (")".equals(stringToRender[ii])) {
moveBeam(10, 0);
g2.draw(drawVec(6, -6));
g2.draw(drawVec(0, -12));
g2.draw(drawVec(-6, -6));
moveBeam(8, 24);
}
else { // Blank space
moveBeam(18, 0);
}
}
//</editor-fold>
// Revert back to the previous beam scale
beamScaleX = oldBeamScaleX;
beamScaleY = oldBeamScaleY;
}
}
}
// Paused
g2.setStroke(bt(3));
if (VectorBreakout.isPaused) {
g2.setColor(Color.white);
resetBeam();
moveBeam(110, 260);
// P
g2.draw(drawVec(0, -110));g2.draw(drawVec(80, 0));g2.draw(drawVec(0, 50));g2.draw(drawVec(-80, 0));
moveBeam(100, 60);
// A
g2.draw(drawVec(0, -70));g2.draw(drawVec(40, -40));g2.draw(drawVec(40, 40));g2.draw(drawVec(0, 70));g2.draw(drawVec(0, -40));g2.draw(drawVec(-80, 0));
moveBeam(100, 40);
// U
moveBeam(0, -110);g2.draw(drawVec(0, 110));g2.draw(drawVec(80, 0));g2.draw(drawVec(0, -110));
moveBeam(20, 110);
// S
g2.draw(drawVec(80, 0));g2.draw(drawVec(0, -55));g2.draw(drawVec(-80, 0));g2.draw(drawVec(0, -55));g2.draw(drawVec(80, 0));
moveBeam(20, 110);
// E
moveBeam(80, 0);g2.draw(drawVec(-80, 0));g2.draw(drawVec(0, -55));g2.draw(drawVec(80, 0));moveBeam(-80, 0);g2.draw(drawVec(0, -55));g2.draw(drawVec(80, 0));
moveBeam(20, 110);
// D
g2.draw(drawVec(40, 0));g2.draw(drawVec(40, -40));g2.draw(drawVec(0, -30));g2.draw(drawVec(-40, -40));g2.draw(drawVec(-40, 0));g2.draw(drawVec(0, 110));
moveBeam(100, 110);
}
VectorBreakout.actualFrames++; // Count up actual frames rendered
gameState.actualFrames++; // Count up actual frames rendered
// Debug Menu
if (VectorBreakout.debugMenuEnabled) {
if (gameState.debugMenuEnabled) {
g2.setColor(Color.white);
g2.drawString("Quajra Debug", 1, 12);
g2.drawString("frame: " + VectorBreakout.frameCounter, 1, 24);
g2.drawString(gameState.gameName + " v" + gameState.gameVersion, 1, 12);
g2.drawString("frame: " + gameState.frameCounter, 1, 24);
g2.drawString("beamScaleX: " + beamScaleX, 1, 36);
g2.drawString("beamScaleY: " + beamScaleY, 1, 48);
g2.drawString("isPaused: " + VectorBreakout.isPaused, 1, 60);
g2.drawString("targetFrameRate: " + VectorBreakout.targetFrameRate, 150, 24);
g2.drawString("actualFrameRate: " + VectorBreakout.actualFrameRate, 150, 36);
g2.drawString("actualFrames: " + VectorBreakout.actualFrames, 150, 48);
g2.drawString("chancey: " + VectorBreakout.chancey, 150, 60);
g2.drawString("ballsOnScreen: " + VectorBreakout.ballsOnScreen, 300, 24);
g2.drawString("isPaused: " + gameState.isPaused, 1, 60);
g2.drawString("targetFrameRate: " + gameState.targetFrameRate, 150, 24);
g2.drawString("actualFrameRate: " + gameState.actualFrameRate, 150, 36);
g2.drawString("actualFrames: " + gameState.actualFrames, 150, 48);
g2.drawString("chancey: " + gameState.chancey, 150, 60);
g2.drawString("ballsOnScreen: " + gameState.ballsOnScreen, 300, 24);
short padBoxX, padBoxY, padBoxX2, padBoxY2;
g2.setStroke(new BasicStroke(1));
// Paddles
g2.setColor(vc(10, 0.5f));
for (byte i = 0; i < VectorBreakout.currentPaddles.length; i++) {
if (VectorBreakout.currentPaddles[i] != null) {
padBoxX = (short) VectorBreakout.currentPaddles[i].hitBox.bounds.getBounds2D().getMinX();
padBoxY = (short) VectorBreakout.currentPaddles[i].hitBox.bounds.getBounds2D().getMinY();
padBoxX2 = (short) VectorBreakout.currentPaddles[i].hitBox.bounds.getBounds2D().getWidth();
padBoxY2 = (short) VectorBreakout.currentPaddles[i].hitBox.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - VectorBreakout.currentPaddles[i].paddleHeight), padBoxX2, padBoxY2);
padBoxX = (short) VectorBreakout.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getMinX();
padBoxY = (short) VectorBreakout.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getMinY();
padBoxX2 = (short) VectorBreakout.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getWidth();
padBoxY2 = (short) VectorBreakout.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - VectorBreakout.currentPaddles[i].paddleHeight), padBoxX2, padBoxY2);
padBoxX = (short) VectorBreakout.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getMinX();
padBoxY = (short) VectorBreakout.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getMinY();
padBoxX2 = (short) VectorBreakout.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getWidth();
padBoxY2 = (short) VectorBreakout.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - VectorBreakout.currentPaddles[i].paddleHeight), padBoxX2, padBoxY2);
for (byte i = 0; i < gameState.currentPaddles.length; i++) {
if (gameState.currentPaddles[i] != null) {
padBoxX = (short) gameState.currentPaddles[i].hitBox.bounds.getBounds2D().getMinX();
padBoxY = (short) gameState.currentPaddles[i].hitBox.bounds.getBounds2D().getMinY();
padBoxX2 = (short) gameState.currentPaddles[i].hitBox.bounds.getBounds2D().getWidth();
padBoxY2 = (short) gameState.currentPaddles[i].hitBox.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - gameState.currentPaddles[i].paddleHeight), padBoxX2, padBoxY2);
padBoxX = (short) gameState.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getMinX();
padBoxY = (short) gameState.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getMinY();
padBoxX2 = (short) gameState.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getWidth();
padBoxY2 = (short) gameState.currentPaddles[i].hitBoxLeft.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - gameState.currentPaddles[i].paddleHeight), padBoxX2, padBoxY2);
padBoxX = (short) gameState.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getMinX();
padBoxY = (short) gameState.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getMinY();
padBoxX2 = (short) gameState.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getWidth();
padBoxY2 = (short) gameState.currentPaddles[i].hitBoxRight.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - gameState.currentPaddles[i].paddleHeight), padBoxX2, padBoxY2);
}
}
// Balls
g2.setColor(vc(11, 1.0f));
for (byte i = 0; i < VectorBreakout.currentBalls.length; i++) {
if (VectorBreakout.currentBalls[i] != null) {
padBoxX = (short) VectorBreakout.currentBalls[i].hitBox.bounds.getBounds2D().getMinX();
padBoxY = (short) VectorBreakout.currentBalls[i].hitBox.bounds.getBounds2D().getMinY();
padBoxX2 = (short) VectorBreakout.currentBalls[i].hitBox.bounds.getBounds2D().getWidth();
padBoxY2 = (short) VectorBreakout.currentBalls[i].hitBox.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - VectorBreakout.currentBalls[i].ballHeight), padBoxX2, padBoxY2);
for (byte i = 0; i < gameState.currentBalls.length; i++) {
if (gameState.currentBalls[i] != null) {
padBoxX = (short) gameState.currentBalls[i].hitBox.bounds.getBounds2D().getMinX();
padBoxY = (short) gameState.currentBalls[i].hitBox.bounds.getBounds2D().getMinY();
padBoxX2 = (short) gameState.currentBalls[i].hitBox.bounds.getBounds2D().getWidth();
padBoxY2 = (short) gameState.currentBalls[i].hitBox.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - gameState.currentBalls[i].ballHeight), padBoxX2, padBoxY2);
}
}
// Bricks
g2.setColor(vc(12, 0.5f));
for (short i = 0; i < VectorBreakout.currentLevel.levelBricks.length; i++) {
if (VectorBreakout.currentLevel.levelBricks[i] != null) {
padBoxX = (short) VectorBreakout.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getMinX();
padBoxY = (short) VectorBreakout.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getMinY();
padBoxX2 = (short) VectorBreakout.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getWidth();
padBoxY2 = (short) VectorBreakout.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - VectorBreakout.currentLevel.levelBricks[i].brickHeight), padBoxX2, padBoxY2);
for (short i = 0; i < gameState.currentLevel.levelBricks.length; i++) {
if (gameState.currentLevel.levelBricks[i] != null) {
padBoxX = (short) gameState.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getMinX();
padBoxY = (short) gameState.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getMinY();
padBoxX2 = (short) gameState.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getWidth();
padBoxY2 = (short) gameState.currentLevel.levelBricks[i].hitBox.bounds.getBounds2D().getHeight();
g2.fillRect(padBoxX, padBoxY + (40 - gameState.currentLevel.levelBricks[i].brickHeight), padBoxX2, padBoxY2);
}
}
}
@ -492,6 +568,8 @@ public class GameDisplay extends JComponent {
case 16: return new Color(0, 1, 1, alpha); // aqua
case 17: return new Color(0.66f, 0, 0.66f, alpha); // purple
case 18: return new Color(1, 0, 1, alpha); // magenta
case 19: return new Color(1, 0.5f, 0.75f, alpha); // pastel pink
case 20: return new Color(0.5f, 0.66f, 1, alpha); // pastel blue
default: return new Color(1, 1, 1, alpha); // white
}
}
@ -510,7 +588,4 @@ public class GameDisplay extends JComponent {
beamY = 40 * beamScaleY;
}
public GameDisplay() {
}
}

View file

@ -0,0 +1,283 @@
package dev.boyfailure.quajra.vectorbreakout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class GameState {
public String gameName = "Vector Breakout";
public String gameVersion = "20250511";
public boolean isGameStarted = false;
public boolean isPaused = false;
public boolean debugMenuEnabled = false;
public boolean isLost = false;
public boolean movingLeft = false;
public boolean movingRight = false;
public boolean confettiMode = false;
public byte lives = 5;
public byte chancey = 0;
public byte ballsOnScreen = 0;
public byte targetFrameRate = 60;
public byte actualFrames = 0;
public byte actualFrameRate = 0;
public byte gameTickRate = 60;
public short gameResX = 800;
public short gameResY = 600;
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];
public Level currentLevel;
// Debug stuffs
public boolean debugSpawnAllBalls = false;
public boolean debugUseGiantPaddle = false;
public short debugStartLevel = 1;
public GameState() {
this.showTitleScreen();
}
public KeyListener getKeyListener() {
return new GameKeyListener();
}
public byte getGameTickRate() {
return gameTickRate;
}
public byte getTargetFrameRate() {
return targetFrameRate;
}
public ActionListener getGameStateUpdateActionListener() {
return new GameStateUpdateListener();
}
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;
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;
}
}
}
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;
}
}
}
}
break;
case 35: // End
if (isLost || !isGameStarted) {isGameStarted = true;newGame(true);return;}
break;
case 32: // Space
if (isLost || !isGameStarted) {isGameStarted = true;newGame();return;}
if (!isPaused) {
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;}
}
}
}
}
break;
case 37: // Left
if (isGameStarted) {movingLeft = true;}
break;
case 39: // Right
if (isGameStarted) {movingRight = true;}
break;
}
}
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case 37: // Left
movingLeft = false;
break;
case 39: // Right
movingRight = false;
break;
}
}
public void keyTyped(KeyEvent e) {}
}
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();
}
}
}
public void incrementFrameCounter() {
this.frameCounter++;
}
public void onGameTick() {
// i will implement something better than "chancey" eventually
chancey++;
if (chancey >= 16) {
chancey = 0;
}
if (isPaused) {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;
}
}
}
// Ball logic (movement, collision checks)
for (byte i = 0; i < currentBalls.length; i++) {
if (currentBalls[i] != null) {
if (currentBalls[i].isActive) {
currentBalls[i].moveBall();
}
}
}
// Particles
for (byte i = 0; i < currentParticles.length; i++) {
if (currentParticles[i] != null) {
if (currentParticles[i].isActive) {
currentParticles[i].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();
}
public void gameLose() {
if (currentLevel != null) {
for (short i = 0; i < currentLevel.levelBricks.length; i++) {
currentLevel.levelBricks[i] = null;
}
}
for (byte i = 0; i < currentBalls.length; i++) {
currentBalls[i] = null;
}
isLost = true;
ballsOnScreen = 0;
}
public void newGame() {
newGame(false);
}
public void newGame(boolean debugLevel) {
for (byte i = 0; i < currentTextElements.length; i++) {
currentTextElements[i] = null;
}
lives = 5;
isLost = false;
score = 0;
if (debugLevel) {level = 32767;}
else {level = 1;}
frameCounter = 0;
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 (debugStartLevel > 1) {level = debugStartLevel;}
currentLevel = new Level(this, level);
currentLevel.startLevel();
}
}

View file

@ -1,8 +1,5 @@
package dev.boyfailure.quajra.vectorbreakout;
import java.util.Timer;
import java.util.TimerTask;
public class Level {
short levelID;
@ -12,7 +9,10 @@ public class Level {
byte[] colorMap;
Brick[] levelBricks;
public Level(int id) {
private GameState gameState;
public Level(GameState gameState, int id) {
this.gameState = gameState;
this.levelID = (short) id;
switch(id) {
@ -33,39 +33,125 @@ public class Level {
this.levelName = "DOUBLE TROUBLE";
this.levelLayout = new byte[]
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
3,3,3,3,3,5,3,3,3,3,3,3,3,5,3,3,3,3,3,
3,3,3,3,3,16,3,3,3,3,3,3,3,16,3,3,3,3,3,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
this.colorMap = new byte[]
{10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,18,13,13,13,13,13,13,13,18,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12};
break;
case 3:
this.levelName = "THINKY THINKY...";
this.levelName = "THE GAP";
this.levelLayout = new byte[]
{4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,
3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,
2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,
1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3};
{5,5,5,5,5,5,5,5,0,0,0,5,5,5,5,5,5,5,5,
4,4,4,4,4,4,4,4,0,0,0,4,4,4,4,4,4,4,4,
3,3,3,3,3,16,3,3,0,0,0,3,3,16,3,3,3,3,3,
2,2,2,2,2,2,2,2,0,0,0,2,2,2,2,2,2,2,2,
1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1};
this.colorMap = new byte[]
{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,18,13,13,13,13,13,13,13,18,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12};
break;
case 4:
this.levelName = "HOLES!!";
this.levelName = "HOLE IN THE WALL";
this.levelLayout = new byte[]
{4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
3,3,0,0,3,3,3,3,0,0,0,3,3,3,3,0,0,3,3,
2,2,0,0,2,2,2,2,0,0,0,2,2,2,2,0,0,2,2,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
this.colorMap = new byte[]
{10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12};
break;
case 5:
this.levelName = "A SECOND OPINION";
this.levelLayout = new byte[]
{0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,0,
0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,
0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0};
this.colorMap = new byte[]
{10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12};
break;
case 6:
this.levelName = "SLICES";
this.levelLayout = new byte[]
{5,5,0,5,5,0,5,5,0,5,5,0,5,5,0,5,5,0,5,
4,0,4,4,0,4,4,0,4,4,0,4,4,0,4,4,0,4,4,
0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,
2,2,0,2,2,0,2,2,0,2,2,0,2,2,0,2,2,0,2,
1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,
0,4,4,0,4,4,0,4,4,0,4,4,0,4,4,0,4,4,0,
3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,3,0,3,
2,0,2,2,0,2,2,0,2,2,0,2,2,0,2,2,0,2,2,
0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0};
this.colorMap = new byte[]
{14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12};
break;
case 1001:
this.levelName = "TRANS RIGHTS";
this.levelLayout = new byte[]
{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
{5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
3,3,3,3,3,3,3,3,3,3,3,3,3,5,3,3,3,3,3,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
this.colorMap = new byte[]
{20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20};
break;
case 1002:
this.levelName = "I USE ARCH BTW";
this.levelLayout = new byte[]
//1 2 3 4 5 6 7 8 9 0
{0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,5,5,5,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,4,4,0,4,4,0,0,0,0,0,0,0,
0,0,0,0,0,0,3,3,0,0,0,3,3,0,0,0,0,0,0,
0,0,0,0,0,2,2,2,0,0,0,2,2,2,0,0,0,0,0,
0,0,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,0,0};
this.colorMap = new byte[]
{16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16};
break;
case 32767:
this.levelName = "DEBUG.LEVEL;";
@ -89,12 +175,17 @@ public class Level {
7,8,9,10,11,12,13,14,15,16,17,18,0,1,2,3,4,5,6};
break;
default:
this.levelName = "LEVEL " + levelID;
this.levelName = "LEVEL 404: NOT FOUND (" + levelID + ")";
this.levelLayout = new byte[]
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
this.colorMap = new byte[]
{2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
break;
}
@ -108,25 +199,28 @@ public class Level {
for (int i = 0; i < this.levelLayout.length; i++) {
switch (this.levelLayout[i]) {
case 1:
this.levelBricks[i] = new Brick(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 4, 0);
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(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0);
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(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 16, 0);
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(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 32, 0);
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(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 2);
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(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0);
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(brickLeftPlacement, (((int) (i / 19)) * this.rowHeight) + 50, false, this.colorMap[i], 8, 0);
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;
@ -136,17 +230,10 @@ public class Level {
if (brickLeftPlacement >= 760) {brickLeftPlacement = 20;}
}
}
VectorBreakout.bricksOnScreen = (short) this.levelBricks.length;
VectorBreakout.currentTextElements[2].setText(String.valueOf(this.levelID));
VectorBreakout.currentTextElements[3] = new TextElement("", 1, 24, 480, 15, 2);
VectorBreakout.currentTextElements[3].setText("LEVEL " + String.valueOf(this.levelID) + ": " + this.levelName);
VectorBreakout.currentTextElements[3].activate();
Timer levelTitleGTFO = new Timer();
levelTitleGTFO.schedule(new TimerTask() {
public void run() {
VectorBreakout.currentTextElements[3].cull();
}
}, 3000);
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();
}
}

View file

@ -0,0 +1,14 @@
package dev.boyfailure.quajra.vectorbreakout;
public class Menu {
public String menuTitle = "Menu";
public byte index = 0;
private GameState gameState;
public Menu(GameState gameState) {
this.gameState = gameState;
}
}

View file

@ -14,7 +14,10 @@ public class Paddle {
Hitbox hitBoxLeft;
Hitbox hitBoxRight;
public Paddle(int x, int y, int width, int height, int paddleColor) {
private GameState gameState;
public Paddle(GameState gameState, int x, int y, int width, int height, int paddleColor) {
this.gameState = gameState;
this.paddleX = (short) x;
this.paddleY = (short) y;
this.paddleWidth = (short) width;
@ -30,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 >= (VectorBreakout.gameResX - this.paddleWidth - 20)) {this.paddleX = (short) (VectorBreakout.gameResX - this.paddleWidth - 20);}
else if (this.paddleX >= (gameState.gameResX - this.paddleWidth - 20)) {this.paddleX = (short) (gameState.gameResX - 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);

View file

@ -15,7 +15,10 @@ public class Particle {
byte particleDirection;
byte particleSpeed = 2;
public Particle(int particleID, int x, int y, int x2, int y2, int particleColor, float vectorScale, int direction, int speed) {
private GameState gameState;
public Particle(GameState gameState, int particleID, int x, int y, int x2, int y2, int particleColor, float vectorScale, int direction, int speed) {
this.gameState = gameState;
this.particleID = (byte) particleID;
this.particleX = (short) x;
this.particleY = (short) y;
@ -29,7 +32,7 @@ public class Particle {
public void spawn(int lifetime) {
this.isActive = true;
if (VectorBreakout.confettiMode) {this.particleLifetime = 400;}
if (gameState.confettiMode) {this.particleLifetime = 400;}
else {this.particleLifetime = (short) lifetime;}
}

View file

@ -1,5 +1,8 @@
package dev.boyfailure.quajra.vectorbreakout;
import java.util.Timer;
import java.util.TimerTask;
public class TextElement {
String text;
@ -9,16 +12,22 @@ public class TextElement {
byte textColor;
short x;
short y;
short duration = 0;
long creationTime;
private GameState gameState;
/**
* Text elements.
* @param gameState The GameState in which the TextElement will reside.
* @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.
*/
public TextElement(String text, float textScale, int x, int y, int textColor, float vectorScale) {
public TextElement(GameState gameState, String text, float textScale, int x, int y, int textColor, float vectorScale) {
this.gameState = gameState;
this.text = text;
this.textScale = textScale;
this.x = (short) x;
@ -27,11 +36,48 @@ public class TextElement {
this.vectorScale = vectorScale;
}
/**
* Text elements with a fadeout timer.
* @param gameState The GameState in which the TextElement will reside.
* @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 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) {
this.gameState = gameState;
this.text = text;
this.textScale = textScale;
this.x = (short) x;
this.y = (short) y;
this.textColor = (byte) textColor;
this.vectorScale = vectorScale;
this.duration = (short) duration;
this.creationTime = System.currentTimeMillis();
}
/**
* Prepares the TextElement for rendering.
*/
public void activate() {
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();
}
}
}
}
}, this.duration);
}
}
/**
@ -63,7 +109,7 @@ public class TextElement {
/**
* Changes the color of the text.
* @param textColor The color of the text.
* @param textColor The color code of the text.
*/
public void setColor(int textColor) {
this.textColor = (byte) textColor;

View file

@ -3,8 +3,6 @@ package dev.boyfailure.quajra.vectorbreakout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
@ -12,260 +10,53 @@ import javax.swing.Timer;
public class VectorBreakout {
public static String gameName = "Vector Breakout";
public static boolean isGameStarted = false;
public static boolean isPaused = false;
public static boolean debugMenuEnabled = false;
public static boolean isLost = false;
public static boolean movingLeft = false;
public static boolean movingRight = false;
public static boolean confettiMode = false;
public static byte lives = 5;
public static byte chancey = 0;
public static byte ballsOnScreen = 0;
public static byte targetFrameRate = 60;
public static byte actualFrames = 0;
public static byte actualFrameRate = 0;
public static byte gameTickRate = 60;
public static short gameResX = 800;
public static short gameResY = 600;
public static short level = 1;
public static short bricksOnScreen = 0;
public static int score = 0;
public static long frameCounter = 0;
public static Ball[] currentBalls = new Ball[10];
public static Particle[] currentParticles = new Particle[127];
public static Paddle[] currentPaddles = new Paddle[2];
public static TextElement[] currentTextElements = new TextElement[63];
public static Level currentLevel;
// The embeddable game
public static GameState gameState = new GameState();
// The window for the game
public static JFrame gameFrame = new JFrame();
public static GameDisplay gameCanvas = new GameDisplay(gameState);
public VectorBreakout() {
}
public static void main(String[] args) {
// Enable OpenGL for hardware acceleration
System.setProperty("sun.java2d.opengl", "true");
final JFrame gameFrame = new JFrame();
// Set the game window's properties
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gameFrame.setTitle(gameName);
gameFrame.setSize(gameResX, gameResY);
gameFrame.setTitle(gameState.gameName);
gameFrame.setSize(gameState.gameResX, gameState.gameResY);
gameFrame.getContentPane().setBackground(Color.black);
final GameDisplay gameCanvas = new GameDisplay();
gameFrame.getContentPane().add(gameCanvas);
gameFrame.setVisible(true);
gameFrame.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case 27: // Escape
debugMenuEnabled = !debugMenuEnabled;
break;
case 10: // Enter
if (isGameStarted) {isPaused = !isPaused;}
break;
case 35: // End
if (isLost || !isGameStarted) {isGameStarted = true;newGame(true);return;}
break;
case 32: // Space
if (isLost || !isGameStarted) {isGameStarted = true;newGame();return;}
if (!isPaused) {
if (ballsOnScreen < 1) {
for (byte i = 0; i < currentBalls.length; i++) {
if (currentBalls[i] == null) {
currentBalls[i] = new Ball(200, 300, 7, 7, 0, true);
currentBalls[i].spawnBall(true);
return;
}
}
}
}
break;
case 37: // Left
if (isGameStarted) {movingLeft = true;}
break;
case 39: // Right
if (isGameStarted) {movingRight = true;}
break;
}
}
public void keyReleased(KeyEvent e) {
switch(e.getKeyCode()) {
case 37: // Left
movingLeft = false;
break;
case 39: // Right
movingRight = false;
break;
}
}
public void keyTyped(KeyEvent e) {}
});
gameFrame.addKeyListener(gameState.getKeyListener());
// Adapts vector drawing scale when the window is resized
gameFrame.addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent componentEvent) {
// Experiment for ensuring scaling at a 4:3 ratio gameFrame.setSize((int) Math.abs(gameFrame.getSize().height * 1.333), gameFrame.getSize().height);
gameCanvas.beamScaleX = gameFrame.getBounds().width / 800f;
gameCanvas.beamScaleY = gameFrame.getBounds().height / 600f;
if (gameCanvas.beamScaleX <= gameCanvas.beamScaleY) {gameCanvas.beamThicknessScale = gameCanvas.beamScaleX;}
else {gameCanvas.beamThicknessScale = gameCanvas.beamScaleY;}
}
});
Timer gameTick = new Timer((1000 / gameTickRate), new ActionListener(){
public void actionPerformed(ActionEvent e) {
onGameTick();
GameDisplay.beamScaleX = gameFrame.getBounds().width / 800f;
GameDisplay.beamScaleY = gameFrame.getBounds().height / 600f;
}
});
Timer gameTick = new Timer((1000 / gameState.getGameTickRate()), gameState.getGameTickActionListener());
gameTick.start();
Timer frameDisplay = new Timer((1000 / targetFrameRate), new ActionListener(){
Timer frameDisplay = new Timer((1000 / gameState.getTargetFrameRate()), new ActionListener() {
public void actionPerformed(ActionEvent e) {
frameCounter++;
gameState.incrementFrameCounter();
gameFrame.repaint();
}
});
frameDisplay.start();
Timer gameCuller = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent e) {
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;
}
}
}
}
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) {
level++;
currentLevel = new Level(level);
currentLevel.startLevel();
}
}
});
Timer gameCuller = new Timer(1000, gameState.getGameStateUpdateActionListener());
gameCuller.start();
currentTextElements[0] = new TextElement("VECTOR BREAKOUT", 2.5f, 67, 280, 15, 2);
currentTextElements[1] = new TextElement("MMXXV BOYFAILURE.DEV", 0.75f, 259, 315, 15, 1);
currentTextElements[2] = new TextElement("PRESS SPACE TO BEGIN", 1, 215, 345, 15, 2);
currentTextElements[0].activate();
currentTextElements[1].activate();
currentTextElements[2].activate();
}
public static void onGameTick() {
// i will implement something better than "chancey" eventually
chancey++;
if (chancey >= 16) {
chancey = 0;
}
if (isPaused) {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;
}
}
}
// Ball logic (movement, collision checks)
for (byte i = 0; i < currentBalls.length; i++) {
if (currentBalls[i] != null) {
if (currentBalls[i].isActive) {
currentBalls[i].moveBall();
}
}
}
// Particles
for (byte i = 0; i < currentParticles.length; i++) {
if (currentParticles[i] != null) {
if (currentParticles[i].isActive) {
currentParticles[i].update();
}
}
}
}
public static void gameLose() {
if (currentLevel != null) {
for (short i = 0; i < currentLevel.levelBricks.length; i++) {
currentLevel.levelBricks[i] = null;
}
}
for (byte i = 0; i < currentBalls.length; i++) {
currentBalls[i] = null;
}
isLost = true;
ballsOnScreen = 0;
}
public static void newGame() {
newGame(false);
}
public static void newGame(boolean debugLevel) {
for (byte i = 0; i < currentTextElements.length; i++) {
currentTextElements[i] = null;
}
lives = 5;
isLost = false;
score = 0;
if (debugLevel) {level = 32767;}
else {level = 1;}
frameCounter = 0;
ballsOnScreen = 0;
movingLeft = false;
movingRight = false;
currentPaddles[0] = new Paddle(350, 500, 100, 15, 0);
//test currentPaddles[0] = new Paddle(0, 500, 800, 60, 0);
currentTextElements[0] = new TextElement(String.valueOf(score), 1, 20, -13, 1, 2);
currentTextElements[1] = new TextElement(String.valueOf(lives), 1, 200, -13, 1, 2);
currentTextElements[2] = new TextElement(String.valueOf(level), 1, 380, -13, 1, 2);
currentTextElements[0].activate();
currentTextElements[1].activate();
currentTextElements[2].activate();
currentLevel = new Level(level);
currentLevel.startLevel();
}
}