This commit is contained in:
Andreas Greiner 2021-06-28 21:45:53 +02:00
parent b0d8b5806f
commit 572fc7b439
54 changed files with 340 additions and 266 deletions

View File

@ -2,7 +2,9 @@ package de.thdeg.greiner.superpangworld.game.managers;
import de.thdeg.greiner.superpangworld.gameview.GameView;
/** This class manages the main game loop of the game. */
/**
* This class manages the main game loop of the game.
*/
public class GameLoopManager {
private final GameView gameView;
private final InputManager inputManager;

View File

@ -2,12 +2,16 @@ package de.thdeg.greiner.superpangworld.game.managers;
import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.base.Bubble;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import de.thdeg.greiner.superpangworld.graphics.base.GameObject;
import de.thdeg.greiner.superpangworld.graphics.immovable.*;
import de.thdeg.greiner.superpangworld.graphics.moveable.*;
import java.awt.*;
import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
/**
* The manager handling the display and passive movement of the game objects.
@ -23,17 +27,22 @@ class GameObjectManager {
private final LivesLabel livesLabel;
private final Background background;
private final GameFrame frame;
private final GameOverlay gameOverlay;
private final Overlay overlay;
private final PlayerObject playerObject;
private final LinkedList<GameObject> gameObjects;
private final Random random;
/**
* Create a manager handling the display and passive movement of the game objects.
* Create a manager handling the game objects.
*
* @param gameView the GameView
*/
public GameObjectManager(GameView gameView){
random = new Random();
gameView.setColorForBlockImage('k', Color.LIGHT_GRAY);
bubbles = new LinkedList<>();
@ -47,18 +56,72 @@ class GameObjectManager {
background = new Background(gameView);
frame = new GameFrame(gameView);
playerObject = new PlayerObject(gameView);
gameOverlay = new GameOverlay(gameView);
overlay = new Overlay(gameView);
}
/**
* Clear all game object lists.
* Clear all game object lists and stops any sounds.
*/
public void clearAll(){
gameObjects.clear();
bubbles.clear();
harpoons.forEach(Harpoon::stopSound);
harpoons.clear();
}
/**
* Get all collideable game objects a bubble can collide with.
*
* @return the game objects
*/
public List<CollidableGameObject> getBubblesCollideables(){
List<CollidableGameObject> collidableGameObjects = new ArrayList<>();
collidableGameObjects.add(playerObject);
collidableGameObjects.addAll(harpoons);
return collidableGameObjects;
}
/**
* Add bubbles to the game.
*
* @param newBubbles the list of new bubbles
* @param gamePlayManager the associated game play manager
*/
public void addBubbles(List<Bubble> newBubbles,GamePlayManager gamePlayManager){
List<CollidableGameObject> collidableGameObjects = getBubblesCollideables();
newBubbles.forEach(bubble->{
bubble.setGamePlayManager(gamePlayManager);
bubble.addCollidableGameObject(collidableGameObjects);
bubbles.add(bubble);
});
}
/**
* Add a random bubble to the game.
*
* @param specialBubblePresent flag, if a special bubble is already present in the game
* @param gameView the game view for the bubble
* @param gamePlayManager the game play manager for the bubble
* @return <code>true</code> if a special bubble was added, otherwise <code>false</code>
*/
public boolean addRandomBubble(boolean specialBubblePresent, GameView gameView, GamePlayManager gamePlayManager){
boolean specialBubbleAdded = false;
int randomNumber = specialBubblePresent ? random.nextInt(90) : random.nextInt(100);
List<CollidableGameObject> collidableGameObjects = getBubblesCollideables();
Bubble newBubble;
if(randomNumber<60){
newBubble = new RoundBubble(gameView, collidableGameObjects);
}else if(randomNumber<90){
newBubble = new HexagonalBubble(gameView, collidableGameObjects);
}else{
newBubble = new SpecialBubble(gameView, collidableGameObjects);
specialBubbleAdded = true;
}
newBubble.setGamePlayManager(gamePlayManager);
bubbles.add(newBubble);
return specialBubbleAdded;
}
/**
* Add the objects to the canvas and handle update their positions.
*/
@ -73,7 +136,7 @@ class GameObjectManager {
gameObjects.add(livesLabel);
gameObjects.add(playerObject);
gameObjects.addAll(bubbles);
gameObjects.add(gameOverlay);
gameObjects.add(overlay);
gameObjects.forEach(gameObject ->{
gameObject.update();
@ -149,8 +212,8 @@ class GameObjectManager {
*
* @return the game overlay
*/
public GameOverlay getGameOverlay(){
return gameOverlay;
public Overlay getGameOverlay(){
return overlay;
}
/**

View File

@ -2,45 +2,28 @@ package de.thdeg.greiner.superpangworld.game.managers;
import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.base.Bubble;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import de.thdeg.greiner.superpangworld.graphics.base.Position;
import de.thdeg.greiner.superpangworld.graphics.helper.Level;
import de.thdeg.greiner.superpangworld.graphics.helper.Player;
import de.thdeg.greiner.superpangworld.graphics.helper.*;
import de.thdeg.greiner.superpangworld.graphics.moveable.Harpoon;
import de.thdeg.greiner.superpangworld.graphics.moveable.HexagonalBubble;
import de.thdeg.greiner.superpangworld.graphics.moveable.RoundBubble;
import de.thdeg.greiner.superpangworld.graphics.moveable.SpecialBubble;
import java.awt.*;
import java.awt.Color;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* The manager which handles the gameplay.
*/
public class GamePlayManager {
/** The GameView on which the game is displayed */
private final GameView gameView;
/** The manager, which handles the game objects */
private final GameObjectManager gameObjectManager;
/** Generator for random values */
private final Random random;
/** The current level */
private Level level;
/** The player */
private Player player;
/** The level manager */
private LevelManager levelManager;
/** Flag, if bubbles should be spawned */
private boolean spawnBubbles;
/** Flag, if all bubbles should be destroyed */
private boolean destroyAllBubbles;
/** Flag, is a special bubble is currently present */
/** Flag, if a special bubble is present */
public boolean specialBubblePresent;
/** Flag, if the bubble movement is froze */
/** Flag, if the bubble movement is frozen */
public boolean movementFroze;
private final GameView gameView;
private final GameObjectManager gameObjectManager;
private Level level;
private Player player;
private LevelManager levelManager;
private boolean spawnBubbles;
private boolean destroyAllBubbles;
/**
* Create the manager handling the gameplay.
@ -49,39 +32,47 @@ public class GamePlayManager {
* @param gameObjectManager the manager handling the game objects
*/
public GamePlayManager(GameView gameView, GameObjectManager gameObjectManager) {
random = new Random();
this.gameView = gameView;
this.gameObjectManager = gameObjectManager;
boolean easyDifficulty = gameView.showSimpleStartScreen("Super Pang World","Start the game");
initializeGame(easyDifficulty);
initializeLevel();
initializeGame();
}
/**
* Initialize the game.
*
* @param easyDifficulty the game difficulty
*/
private void initializeGame(boolean easyDifficulty){
private void initializeGame(){
StartScreen startScreen = new StartScreen(gameView);
startScreen.showStartScreen();
boolean difficultySetToEasy = startScreen.isDifficultySetToEasy();
gameView.playSound("backgroundMusic.wav", true);
gameObjectManager.clearAll();
levelManager = new LevelManager(easyDifficulty);
levelManager = new LevelManager(difficultySetToEasy);
try {
level = levelManager.getNextLevel();
} catch (LevelManager.NoMoreLevelsAvailableException e) {
System.out.println("No levels were generated, exiting program");
System.exit(-1);
}
player = new Player(level);
gameObjectManager.getPlayerObject().setGamePlayManager(this);
gameObjectManager.getPlayerObject().setPosition(GameView.WIDTH/2.0, 360);
initializeLevel();
}
/**
* Start the next game or quit the game entirely.
*/
private void nextGame(){
gameView.stopAllSounds();
gameObjectManager.clearAll();
EndScreen endScreen = new EndScreen(gameView);
String message = player.lives<0 ? "You lost the game.\n Your score: "+player.score : "You won the game.\n Your score: "+player.score;
endScreen.showEndScreen(message);
initializeGame();
}
/**
* Initialize the level.
*/
private void initializeLevel(){
// Set Gameplay variables
spawnBubbles = true;
destroyAllBubbles = false;
specialBubblePresent = false;
@ -90,24 +81,6 @@ public class GamePlayManager {
gameObjectManager.getBackground().setBackgroundImage(level.backgroundImage);
}
/**
* Loose a life and remove all bubbles
*/
public void looseLife(){
if(player.lives==0){
handleGameEnded("You lost the game.\nYour score: "+player.score);
}else {
player.lives--;
gameObjectManager.getLivesLabel().setLifeCount(player.lives);
gameObjectManager.getBubbles().clear();
gameObjectManager.getHarpoons().forEach(h -> h.stopSound());
gameObjectManager.getHarpoons().clear();
specialBubblePresent = false;
spawnBubbles = true;
gameObjectManager.getGameOverlay().flashScreen(Color.red, 100);
}
}
/**
* Switch to the next level or end the game if every level was played.
*/
@ -116,25 +89,27 @@ public class GamePlayManager {
level = levelManager.getNextLevel();
initializeLevel();
} catch (LevelManager.NoMoreLevelsAvailableException e) {
handleGameEnded("You won the game.\nYour score: "+player.score);
nextGame();
}
}
/**
* End the game and show exit/restart screen.
*
* @param text text to display
* Loose a life and remove all bubbles.
*/
private void handleGameEnded(String text){
gameView.stopAllSounds();
gameView.showEndScreen(text);
boolean easyDifficulty = gameView.showSimpleStartScreen("Super Pang World","Start the game");
initializeGame(easyDifficulty);
initializeLevel();
public void looseLife(){
player.lives--;
if(player.lives<0){
nextGame();
}else {
gameObjectManager.clearAll();
specialBubblePresent = false;
spawnBubbles = true;
gameObjectManager.getGameOverlay().flashScreen(Color.red, 100);
}
}
/**
* Update all HUD elements
* Update all HUD elements.
*/
private void updateHUD(){
gameObjectManager.getLevelLabel().setLevel(level.number);
@ -149,26 +124,20 @@ public class GamePlayManager {
*/
public void updateGamePlay(){
updateHUD();
if(!destroyAllBubbles && player.score>=level.neededOverallScore){
nextLevel();
}
if(gameView.timerExpired("SpawnBubble","GamePlayManager" ) && spawnBubbles && !movementFroze){
if(spawnBubbles && !movementFroze && gameView.timerExpired("SpawnBubble","GamePlayManager" )){
addRandomBubble();
gameView.setTimer("SpawnBubble","GamePlayManager",3000);
}
if(movementFroze && gameView.timerExpired("MovementFroze","GamePlayManager")){
movementFroze = false;
}
if(destroyAllBubbles && gameView.timerExpired("DestroyAllBubbles","GamePlayManager")){
List<Bubble> bubblesCopy = new ArrayList<>(gameObjectManager.getBubbles());
if(bubblesCopy.size()>0) {
for (Bubble bubble : bubblesCopy) {
destroy(bubble);
}
bubblesCopy.forEach(this::destroy);
gameView.setTimer("DestroyAllBubbles", "GamePlayManager", 300);
}else{
destroyAllBubbles = false;
@ -195,7 +164,7 @@ public class GamePlayManager {
movementFroze = true;
gameView.playSound("freeze.wav",false);
gameView.setTimer("MovementFroze","GamePlayManager",freezeTime);
gameObjectManager.getGameOverlay().showMessage("Freeze "+ TimeUnit.MILLISECONDS.toSeconds(freezeTime)+" sec",freezeTime);
gameObjectManager.getGameOverlay().showMessage("Freeze "+ (freezeTime/1000)+" sec",freezeTime);
}
/**
@ -233,31 +202,11 @@ public class GamePlayManager {
}
/**
* Add a random bubble with given values to the game. Percentages:
* - 60% normal bubble
* - 30% hexagonal bubble
* - 10% special bubble
* Spawn a random bubble into the game.
*/
private void addRandomBubble(){
int randomNumber = specialBubblePresent ? random.nextInt(90) : random.nextInt(10000);
ArrayList<CollidableGameObject> collidableGameObjects = new ArrayList<>();
collidableGameObjects.add(gameObjectManager.getPlayerObject());
collidableGameObjects.addAll(gameObjectManager.getHarpoons());
if(randomNumber<10){
RoundBubble roundBubble = new RoundBubble(gameView, collidableGameObjects);
roundBubble.setGamePlayManager(this);
gameObjectManager.getBubbles().add(roundBubble);
}else if(randomNumber<90){
HexagonalBubble hexagonalBubble = new HexagonalBubble(gameView, collidableGameObjects);
hexagonalBubble.setGamePlayManager(this);
gameObjectManager.getBubbles().add(hexagonalBubble);
}else{
SpecialBubble specialBubble = new SpecialBubble(gameView, collidableGameObjects);
specialBubble.setGamePlayManager(this);
gameObjectManager.getBubbles().add(specialBubble);
specialBubblePresent = true;
}
boolean specialBubbleAdded = gameObjectManager.addRandomBubble(specialBubblePresent, gameView, this);
specialBubblePresent = specialBubblePresent || specialBubbleAdded;
}
/**
@ -265,27 +214,19 @@ public class GamePlayManager {
*
* @param bubbles the bubbles
*/
public void addBubbles(Bubble... bubbles){
ArrayList<CollidableGameObject> collidableGameObjects = new ArrayList<>();
collidableGameObjects.add(gameObjectManager.getPlayerObject());
collidableGameObjects.addAll(gameObjectManager.getHarpoons());
for(Bubble bubble: bubbles){
bubble.setGamePlayManager(this);
bubble.addCollidableGameObject(collidableGameObjects);
gameObjectManager.getBubbles().add(bubble);
}
public void addBubbles(List<Bubble> bubbles){
gameObjectManager.addBubbles(bubbles, this);
}
/**
* Shoot a harpoon starting at a given position.
*
* @param startPosition the start position
* @param playerPosition the player position
* @return if a harpoon was shot or not
*/
public boolean shootHarpoon(Position startPosition){
public boolean shootHarpoon(Position playerPosition){
if(gameView.timerExpired("ShootHarpoon","GamePlayManager") && gameObjectManager.getHarpoons().size()<2){
Harpoon harpoon = new Harpoon(gameView,new ArrayList<>());
harpoon.getPosition().setTo(startPosition.x+6, startPosition.y-15);
Harpoon harpoon = new Harpoon(gameView,new ArrayList<>(), new Position(playerPosition.x+6, playerPosition.y-15));
harpoon.setGamePlayManager(this);
gameObjectManager.getHarpoons().add(harpoon);
gameObjectManager.getBubbles().forEach(b -> b.addCollidableGameObject(Collections.singletonList(harpoon)));

View File

@ -15,8 +15,6 @@ class InputManager {
private final GameView gameView;
/** The player object */
private final PlayerObject playerObject;
/** Flag, if diagonal movement is allowed */
private static final boolean DIAGONAL_MOVEMENT_ALLOWED = false;
/**
* Create a manager handling the user input.
@ -48,12 +46,6 @@ class InputManager {
default:
continue;
}
if(!DIAGONAL_MOVEMENT_ALLOWED){
return;
}
}
}
}

View File

@ -2,7 +2,6 @@ package de.thdeg.greiner.superpangworld.game.managers;
import de.thdeg.greiner.superpangworld.graphics.helper.Level;
import java.sql.Array;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
@ -13,22 +12,22 @@ import java.util.Queue;
*/
public class LevelManager {
/** The amount of background images */
private static final int BACKGROUND_IMAGE_COUNT = 9;
/** The queue to store the generated levels */
private final Queue<Level> levels;
private List<String> backgroundImages;
/** The list with all the background image names */
private final List<String> backgroundImages;
/**
* Create a level manager.
*
* @param easyDifficulty the difficulty
* @param difficultyIsSetToEasy flag if easy difficulty is set
*/
public LevelManager(boolean easyDifficulty){
public LevelManager(boolean difficultyIsSetToEasy){
levels = new ArrayDeque<>();
backgroundImages = loadBackgroundImages();
generateLevels(easyDifficulty);
generateLevels(difficultyIsSetToEasy);
}
/**
@ -48,7 +47,7 @@ public class LevelManager {
/**
* Generate the levels according to the difficulty.
*
* @param easyDifficulty the difficulty
* @param easyDifficulty flag if easy difficulty is set
*/
private void generateLevels(boolean easyDifficulty){
int overallScoreNeeded = 0;
@ -66,6 +65,11 @@ public class LevelManager {
}
}
/**
* Create the background image name list.
*
* @return the list with the background image names
*/
private List<String> loadBackgroundImages(){
List<String> images = new ArrayList<>();
for(int i=1;i<=BACKGROUND_IMAGE_COUNT;i++){

View File

@ -14,10 +14,6 @@ import java.util.*;
*/
public abstract class Bubble extends CollidingGameObject implements MovingGameObject{
/** The velocity of a normal right movement */
public static final Point2D VELOCITY_RIGHT = new Point2D.Double(3,1);
/** The velocity of a normal left movement */
public static final Point2D VELOCITY_LEFT = new Point2D.Double(-3,1);
/** The random generator */
protected final Random random;
/** Flag, if the bubble is in the spawning phase */
@ -35,7 +31,7 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
*/
public Bubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith){
public Bubble(GameView gameView, List<CollidableGameObject> objectsToCollideWith){
super(gameView,objectsToCollideWith);
random = new Random();
rotation = 90;
@ -45,13 +41,17 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
speedInPixel = 1;
spawnID = UUID.randomUUID().getLeastSignificantBits();
position.setTo(HelperValues.FRAME_BORDER_WIDTH + random.nextInt((int)(GameView.WIDTH-width - (2*HelperValues.FRAME_BORDER_WIDTH))), -width);
position.x = 2*HelperValues.FRAME_BORDER_WIDTH + random.nextInt((int)(GameView.WIDTH-width - (2*HelperValues.FRAME_BORDER_WIDTH))-(int)(2*HelperValues.FRAME_BORDER_WIDTH));
position.y = -width;
spawning = true;
spawnSpeed = 500;
gameView.setTimer("spawn"+spawnID,"bubble"+spawnID,spawnSpeed);
velocity = random.nextBoolean() ? VELOCITY_LEFT : VELOCITY_RIGHT;
if(random.nextBoolean()){
velocity = new Point2D.Double(1 + random.nextInt(501)/100.0, 1 + random.nextInt(10));
}else{
velocity = new Point2D.Double((1 + random.nextInt(501)/100.0) * -1.0, 1+ random.nextInt(10));
}
}
/**
@ -60,18 +60,16 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
* @param size the object size
* @param speedInPixel the speed in pixel per tick
* @param position the position
* @param spawning flag, if the bubble is in the spawning phase
* @param velocity the initial velocity of the bubble
*/
public Bubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith, double size, double speedInPixel, Position position, boolean spawning, Point2D velocity){
public Bubble(GameView gameView, List<CollidableGameObject> objectsToCollideWith, double size, Position position, boolean spawning, Point2D velocity){
super(gameView,objectsToCollideWith);
random = new Random();
rotation = 90;
this.size = size;
this.speedInPixel = speedInPixel;
this.position.setTo(position.x,position.y);
setPosition(position.x, position.y);
this.spawning = spawning;
this.velocity = velocity;
spawnID = UUID.randomUUID().getLeastSignificantBits();
@ -87,9 +85,6 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
}
/**
* Moves the bubble a tick further.
*/
@Override
public void updatePosition(){
if(spawning){
@ -100,19 +95,19 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
gameView.setTimer("spawn"+spawnID,"bubble"+spawnID,spawnSpeed);
}
}else{
Point2D newLocation = new Point2D.Double(position.x,position.y);
double speedFactor = 0.2;
Point2D bubbleGravity = new Point2D.Double(0,0.1);
newLocation = new Point2D.Double(newLocation.getX() + (velocity.getX() * speedFactor), newLocation.getY() + (velocity.getY() * speedFactor));
velocity = new Point2D.Double(velocity.getX() + HelperValues.BUBBLE_GRAVITY.getX(), velocity.getY() + HelperValues.BUBBLE_GRAVITY.getY());
velocity = new Point2D.Double(velocity.getX() + bubbleGravity.getX(), velocity.getY() + bubbleGravity.getY());
// Wall bounce
if((newLocation.getX() >= GameView.WIDTH - width - HelperValues.FRAME_BORDER_WIDTH) || newLocation.getX() <= HelperValues.FRAME_BORDER_WIDTH){
velocity = new Point2D.Double(velocity.getX() * -1.0, velocity.getY());
}
// Floor bounce
// Floor/roof bounce
if(newLocation.getY() >= HelperValues.FRAME_WINDOW_HEIGHT + HelperValues.FRAME_BORDER_WIDTH - width){
velocity = new Point2D.Double(velocity.getX(), velocity.getY() * -0.95);
newLocation = new Point2D.Double(newLocation.getX(), HelperValues.FRAME_WINDOW_HEIGHT + HelperValues.FRAME_BORDER_WIDTH - width);
@ -121,9 +116,12 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
specialBubble.freezeState = !specialBubble.freezeState;
gameView.playSound("specialBounce.wav",false);
}
}else if(newLocation.getY() <= HelperValues.FRAME_BORDER_WIDTH){
velocity = new Point2D.Double(velocity.getX(), velocity.getY() * -0.95);
newLocation = new Point2D.Double(newLocation.getX(), HelperValues.FRAME_BORDER_WIDTH);
}
position.setTo(newLocation.getX(), newLocation.getY());
setPosition(newLocation.getX(),newLocation.getY());
}
}
@ -146,7 +144,7 @@ public abstract class Bubble extends CollidingGameObject implements MovingGameOb
@Override
public void reactToCollision(CollidableGameObject otherObject) {
if (otherObject instanceof PlayerObject && !gamePlayManager.movementFroze) {
//gamePlayManager.looseLife();
gamePlayManager.looseLife();
} else if (otherObject instanceof Harpoon && !spawning) {
gamePlayManager.destroy((Harpoon) otherObject,this);
}

View File

@ -10,8 +10,14 @@ import java.util.Objects;
*/
public abstract class CollidableGameObject extends GameObject {
/** The hitbox of the game object */
protected Rectangle hitBox;
/**
* Create a collidable game object.
*
* @param gameView the game view
*/
protected CollidableGameObject(GameView gameView) {
super(gameView);
this.hitBox = new Rectangle(-100_000, -100_000, 0, 0);

View File

@ -2,7 +2,6 @@ package de.thdeg.greiner.superpangworld.graphics.base;
import de.thdeg.greiner.superpangworld.gameview.GameView;
import java.util.ArrayList;
import java.util.List;
/**
@ -10,9 +9,16 @@ import java.util.List;
*/
public abstract class CollidingGameObject extends CollidableGameObject {
protected final ArrayList<CollidableGameObject> objectsToCollideWith;
/** The list of game objects that this object may collide with */
protected final List<CollidableGameObject> objectsToCollideWith;
protected CollidingGameObject(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith) {
/**
* Create a colliding game object.
*
* @param gameView the game view
* @param objectsToCollideWith the objects that this object can collide with
*/
protected CollidingGameObject(GameView gameView, List<CollidableGameObject> objectsToCollideWith) {
super(gameView);
this.objectsToCollideWith = objectsToCollideWith;
}
@ -46,6 +52,11 @@ public abstract class CollidingGameObject extends CollidableGameObject {
return this.hitBox.intersects(other.hitBox);
}
/**
* Add collideable game objects to the list.
*
* @param objects the collideable game objects
*/
public void addCollidableGameObject(List<CollidableGameObject> objects){
objectsToCollideWith.addAll(objects);
}

View File

@ -77,6 +77,17 @@ public abstract class GameObject implements Cloneable{
return position;
}
/**
* Set the position with x and y coordinates.
*
* @param x the new x coordinate
* @param y the new y coordinate
*/
public void setPosition(double x, double y){
position.x = x;
position.y = y;
}
/**
* Adapts the position of this game object, in case the whole game world is moved.
*

View File

@ -3,20 +3,20 @@ package de.thdeg.greiner.superpangworld.graphics.base;
import java.util.Objects;
/**
* Die Position eines Objekts auf einem Fenster anhand zweidimensionaler Koordinaten.
* The position of an object on the game window represented by 2 dimensional coordinates.
*/
public class Position implements Cloneable, Comparable<Position>{
/** Die x-Koordinate */
/** The x-coordinate */
public double x;
/** Die y-Koordinate */
/** The y-coordinate */
public double y;
/**
* Erzeugt eine Position mit den übergebenen Koordinaten.
* Create a position.
*
* @param x die x-Koordinate des Objekts
* @param y die y-Koordinate des Objekts
* @param x the x-coordinate of the position
* @param y the y-coordinate of the position
*/
public Position(double x, double y) {
this.x = x;
@ -24,80 +24,41 @@ public class Position implements Cloneable, Comparable<Position>{
}
/**
* Veränderung der Position um einen Pixel nach links.
*/
public void left() {
x--;
}
/**
* Veränderung der Position nach links.
* Move the position to the left.
*
* @param pixel die Anzahl der Pixel
* @param pixel the amount of pixels to move
*/
public void left(double pixel){
x -= pixel;
}
/**
* Veränderung der Position um einen Pixel nach rechts.
*/
public void right() {
x++;
}
/**
* Veränderung der Position nach rechts.
* Move the position to the right.
*
* @param pixel die Anzahl der Pixel
* @param pixel the amount of pixels to move
*/
public void right(double pixel){
x += pixel;
}
/**
* Veränderung der Position um einen Pixel nach oben.
*/
public void up() {
y--;
}
/**
* Veränderung der Position nach oben.
* Move the position upwards.
*
* @param pixel die Anzahl der Pixel
* @param pixel the amount of pixels to move
*/
public void up(double pixel){
y -= pixel;
}
/**
* Veränderung der Position um einen Pixel nach unten.
*/
public void down() {
y++;
}
/**
* Veränderung der Position nach unten.
* Move the position downwards.
*
* @param pixel die Anzahl der Pixel
* @param pixel the amount of pixels to move
*/
public void down(double pixel){
y += pixel;
}
/**
* Set the position to given x and y coordinates.
*
* @param x the x coordinate
* @param y the y coordinate
*/
public void setTo(double x, double y){
this.x = x;
this.y = y;
}
/**
* Calculates the distance to any other position.
*

View File

@ -0,0 +1,31 @@
package de.thdeg.greiner.superpangworld.graphics.helper;
import de.thdeg.greiner.superpangworld.gameview.GameView;
/**
* The class handling the end screen of the game.
*/
public class EndScreen {
/**
* The game view to display the end screen on
*/
private GameView gameView;
/**
* Create an end screen which can be displayed onto the game view.
*
* @param gameView the game view
*/
public EndScreen(GameView gameView){
this.gameView = gameView;
}
/**
* Show the game end screen.
*/
public void showEndScreen(String message){
gameView.showEndScreen(message);
}
}

View File

@ -11,7 +11,5 @@ public class HelperValues {
public static final double FRAME_BORDER_WIDTH = 8;
/** The height of the main game window */
public static final double FRAME_WINDOW_HEIGHT = 432;
/** The games gravity */
public static Point2D BUBBLE_GRAVITY = new Point2D.Double(0,0.2);
}

View File

@ -11,7 +11,7 @@ public class Level {
public int neededLevelScore;
/** The overall needed score to surpass this level */
public int neededOverallScore;
/** The background image name */
public String backgroundImage;
/**
@ -20,6 +20,7 @@ public class Level {
* @param number the level number
* @param neededLevelScore the needed score to surpass this level
* @param neededOverallScore the overall needed score to surpass this level
* @param backgroundImage the background image
*/
public Level(int number, int neededLevelScore, int neededOverallScore, String backgroundImage){
this.number = number;

View File

@ -0,0 +1,40 @@
package de.thdeg.greiner.superpangworld.graphics.helper;
import de.thdeg.greiner.superpangworld.gameview.GameView;
/**
* The class handling the start screen of the game.
*/
public class StartScreen {
/** The game view to display the start screen on */
private GameView gameView;
/** The flag, if the user chose the easy difficulty */
private boolean difficultySetToEasy;
/**
* Create a start screen which can be displayed onto the game view.
*
* @param gameView the game view
*/
public StartScreen(GameView gameView){
this.gameView = gameView;
}
/**
* Show the game start screen.
*/
public void showStartScreen(){
difficultySetToEasy = gameView.showSimpleStartScreen("Super Pang World","Start the game");
}
/**
* Check if the user chose the easy difficulty.
*
* @return <code>true</code> if the easy difficulty was chosen, else <code>false</code>
*/
public boolean isDifficultySetToEasy(){
return difficultySetToEasy;
}
}

View File

@ -17,7 +17,7 @@ public class Background extends GameObject {
*/
public Background(GameView gameView) {
super(gameView);
this.position.setTo(0,0);
setPosition(0,0);
size = 1;
rotation = 0;
backgroundImage = "background_1.png";

View File

@ -15,7 +15,7 @@ public class GameFrame extends GameObject {
*/
public GameFrame(GameView gameView) {
super(gameView);
this.position.setTo(0,0);
setPosition(0,0);
size = 1;
rotation = 0;
}

View File

@ -24,7 +24,7 @@ public class LevelLabel extends GameObject {
width = 109;
height = 8;
level = 1;
getPosition().setTo(GameView.WIDTH/2.0 - width,GameView.HEIGHT-height-60);
setPosition(GameView.WIDTH/2.0 - width,GameView.HEIGHT-height-60);
}
/**

View File

@ -24,7 +24,7 @@ public class LevelProgressBar extends GameObject {
width = 101;
height = 8;
levelProgress = 0;
getPosition().setTo(GameView.WIDTH/2.0 - width,GameView.HEIGHT-(height*size));
setPosition(GameView.WIDTH/2.0 - width,GameView.HEIGHT-(height*size));
}
/**

View File

@ -25,7 +25,7 @@ public class LivesLabel extends GameObject {
this.lifeCount = 0;
position.setTo(10,GameView.HEIGHT - height - 5);
setPosition(10,GameView.HEIGHT - height - 5);
}
@Override

View File

@ -9,7 +9,7 @@ import java.awt.*;
/**
* The game overlay for display text or color on the screen.
*/
public class GameOverlay extends GameObject {
public class Overlay extends GameObject {
/** The message to display */
private String message;
@ -21,7 +21,7 @@ public class GameOverlay extends GameObject {
*
* @param gameView the game view to display the elements on
*/
public GameOverlay(GameView gameView){
public Overlay(GameView gameView){
super(gameView);
}
@ -29,6 +29,7 @@ public class GameOverlay extends GameObject {
* Show a message on the screen.
*
* @param message the message to display
* @param duration the display duration
*/
public void showMessage(String message, long duration){
gameView.setTimer("DisplayMessage","Overlay",duration);

View File

@ -25,7 +25,7 @@ public class ScoreLabel extends GameObject {
width = (int) size * 100;
height = (int) size * 8;
position.setTo(0,GameView.HEIGHT-height-60);
setPosition(0,GameView.HEIGHT-height-60);
}
@Override

View File

@ -4,7 +4,6 @@ import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.base.*;
import de.thdeg.greiner.superpangworld.graphics.helper.HelperValues;
import java.awt.*;
import java.util.ArrayList;
/**
@ -19,9 +18,9 @@ public class Harpoon extends CollidingGameObject implements MovingGameObject {
" kkkkk \n"+
"k kkk k\n"+
"k kkk k\n";
/** The pixel string representing the harpoon rope */
private final String harpoonRope;
/** The identifier for the sound timer */
private int sound;
/**
@ -29,15 +28,16 @@ public class Harpoon extends CollidingGameObject implements MovingGameObject {
*
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the harpoon can collide with
* @param position the position
*/
public Harpoon(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith){
public Harpoon(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith, Position position){
super(gameView, objectsToCollideWith);
this.position = position;
speedInPixel = 2;
size = 3;
width = (int) (7 * size);
height = (int) (5 * size);
rotation = 0;
getPosition().setTo(300,300);
this.hitBox.width = width - 2;
this.hitBox.height = (int) (440 - position.y);
sound = gameView.playSound("harpoon.wav",true);
@ -45,15 +45,19 @@ public class Harpoon extends CollidingGameObject implements MovingGameObject {
harpoonRope = generateRope();
}
/**
* Generate the rope's pixel string.
*
* @return the pixel representation of the harpoon rope
*/
private String generateRope(){
int pre = 3;
int post = 3;
boolean right = true;
String rope = "";
StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i< HelperValues.FRAME_WINDOW_HEIGHT; i++){
rope += " ".repeat(pre) + "k" + " ".repeat(post)+"\n";
stringBuilder.append(" ".repeat(pre) + "k" + " ".repeat(post)+"\n");
if(right){
pre++;
post--;
@ -65,7 +69,7 @@ public class Harpoon extends CollidingGameObject implements MovingGameObject {
right = !right;
}
}
return rope;
return stringBuilder.toString();
}
@Override
@ -76,9 +80,7 @@ public class Harpoon extends CollidingGameObject implements MovingGameObject {
}
@Override
public void reactToCollision(CollidableGameObject otherObject) {
}
public void reactToCollision(CollidableGameObject otherObject) {}
/**
* Draws the harpoon onto the {@link GameView}.
@ -108,6 +110,9 @@ public class Harpoon extends CollidingGameObject implements MovingGameObject {
public void updateStatus() {
}
/**
* Stop the sound.
*/
public void stopSound(){
gameView.stopSound(sound);
}

View File

@ -5,9 +5,10 @@ import de.thdeg.greiner.superpangworld.graphics.base.Bubble;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import de.thdeg.greiner.superpangworld.graphics.base.Position;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* The rare hexagonal bubble.
@ -20,7 +21,7 @@ public class HexagonalBubble extends Bubble {
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
*/
public HexagonalBubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith) {
public HexagonalBubble(GameView gameView, List<CollidableGameObject> objectsToCollideWith) {
super(gameView,objectsToCollideWith);
size=1;
@ -33,8 +34,18 @@ public class HexagonalBubble extends Bubble {
this.hitBox.height = (int)(width - (width*0.1) );
}
public HexagonalBubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith, double size, double speedInPixel, Position position, boolean spawning, Point2D velocity){
super(gameView, objectsToCollideWith, size, speedInPixel, position, spawning, velocity);
/**
* Create a hexagonal bubble.
*
* @param gameView the game view
* @param objectsToCollideWith the objects this bubble may collide with
* @param size the size
* @param position the position
* @param spawning if the bubble is in the spawning state
* @param velocity the velocity of the bubble
*/
public HexagonalBubble(GameView gameView, List<CollidableGameObject> objectsToCollideWith, double size, Position position, boolean spawning, Point2D velocity){
super(gameView, objectsToCollideWith, size, position, spawning, velocity);
width = (int) (128 * size);
height = (int) (128 * size);
@ -89,10 +100,10 @@ public class HexagonalBubble extends Bubble {
Point2D.Double velocityLeft = new Point2D.Double(Math.min(this.velocity.getX(),this.velocity.getX() * -1.0),Math.min(this.velocity.getY(),this.velocity.getY() * -1.0));
Point2D.Double velocityRight = new Point2D.Double(Math.max(this.velocity.getX(),this.velocity.getX() * -1.0),Math.min(this.velocity.getY(),this.velocity.getY() * -1.0));
Bubble bubbleLeft = new HexagonalBubble(gameView, new ArrayList<>(), size/2, speedInPixel, positionLeft, false, velocityLeft);
Bubble bubbleRight = new HexagonalBubble(gameView, new ArrayList<>(), size/2, speedInPixel, positionRight, false, velocityRight);
Bubble bubbleLeft = new HexagonalBubble(gameView, new ArrayList<>(), size/2, positionLeft, false, velocityLeft);
Bubble bubbleRight = new HexagonalBubble(gameView, new ArrayList<>(), size/2, positionRight, false, velocityRight);
gamePlayManager.addBubbles(bubbleLeft, bubbleRight);
gamePlayManager.addBubbles(Arrays.asList(bubbleLeft, bubbleRight));
}
}
}

View File

@ -3,7 +3,6 @@ package de.thdeg.greiner.superpangworld.graphics.moveable;
import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import java.awt.*;
import java.util.Objects;
/**
@ -27,7 +26,7 @@ public class PlayerObject extends CollidableGameObject implements Cloneable {
*/
public PlayerObject(GameView gameView){
super(gameView);
position.setTo(GameView.WIDTH/2.0, 360);
setPosition(GameView.WIDTH/2.0, 360);
shooting = false;
size = 2;
width = (int) (26 * size);

View File

@ -4,10 +4,12 @@ import de.thdeg.greiner.superpangworld.gameview.GameView;
import de.thdeg.greiner.superpangworld.graphics.base.Bubble;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import de.thdeg.greiner.superpangworld.graphics.base.Position;
import de.thdeg.greiner.superpangworld.graphics.helper.HelperValues;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -56,7 +58,7 @@ public class RoundBubble extends Bubble {
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
*/
public RoundBubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith) {
public RoundBubble(GameView gameView, List<CollidableGameObject> objectsToCollideWith) {
super(gameView,objectsToCollideWith);
this.hitBox.width = width-20;
this.hitBox.height = height-20;
@ -69,13 +71,12 @@ public class RoundBubble extends Bubble {
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
* @param size the object size
* @param speedInPixel the speed in Pixel per tick
* @param position the Position
* @param spawning flag, if the bubble is spawning or not
* @param velocity the initial velocity of the bubble
*/
public RoundBubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith, double size, double speedInPixel, Position position, boolean spawning, Point2D velocity){
super(gameView, objectsToCollideWith, size, speedInPixel, position, spawning, velocity);
public RoundBubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith, double size, Position position, boolean spawning, Point2D velocity){
super(gameView, objectsToCollideWith, size, position, spawning, velocity);
this.hitBox.width = (int) (width*0.8);
this.hitBox.height = (int) (height*0.8);
redBubble = true;
@ -90,16 +91,16 @@ public class RoundBubble extends Bubble {
public void destroy() {
gameView.playSound("burst.wav",false);
if (size > 1.25) {
Position positionLeft = new Position(position.x - (width/2.0/2.0), position.y);
Position positionRight = new Position(position.x + width - (width/2.0/2.0), position.y);
Position positionLeft = new Position(Math.max(position.x - (width/2.0/2.0), HelperValues.FRAME_BORDER_WIDTH + 2), position.y);
Position positionRight = new Position(Math.min(position.x + width - (width/2.0/2.0), GameView.WIDTH - (2*HelperValues.FRAME_BORDER_WIDTH) -width - 2), position.y);
Point2D.Double velocityLeft = new Point2D.Double(Math.min(this.velocity.getX(),this.velocity.getX() * -1.0),Math.min(this.velocity.getY(),this.velocity.getY() * -1.0));
Point2D.Double velocityRight = new Point2D.Double(Math.max(this.velocity.getX(),this.velocity.getX() * -1.0),Math.min(this.velocity.getY(),this.velocity.getY() * -1.0));
Bubble bubbleLeft = new RoundBubble(gameView, new ArrayList<>(), size/2, speedInPixel, positionLeft, false, velocityLeft);
Bubble bubbleRight = new RoundBubble(gameView, new ArrayList<>(), size/2, speedInPixel, positionRight, false, velocityRight);
Bubble bubbleLeft = new RoundBubble(gameView, new ArrayList<>(), size/2, positionLeft, false, velocityLeft);
Bubble bubbleRight = new RoundBubble(gameView, new ArrayList<>(), size/2, positionRight, false, velocityRight);
gamePlayManager.addBubbles(bubbleLeft, bubbleRight);
gamePlayManager.addBubbles(Arrays.asList(bubbleLeft, bubbleRight));
}else if(timeFreeze){
gamePlayManager.freezeMovement(1000);
}
@ -148,7 +149,5 @@ public class RoundBubble extends Bubble {
}
@Override
public void updateStatus() {
}
public void updateStatus() {}
}

View File

@ -5,8 +5,8 @@ import de.thdeg.greiner.superpangworld.graphics.base.Bubble;
import de.thdeg.greiner.superpangworld.graphics.base.CollidableGameObject;
import de.thdeg.greiner.superpangworld.graphics.base.Position;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* The green bubble with special abilities.
@ -79,7 +79,7 @@ public class SpecialBubble extends Bubble {
* @param gameView the {@link GameView} to display the bubble
* @param objectsToCollideWith the list of {@link CollidableGameObject} the bubble can collide with
*/
public SpecialBubble(GameView gameView, ArrayList<CollidableGameObject> objectsToCollideWith) {
public SpecialBubble(GameView gameView, List<CollidableGameObject> objectsToCollideWith) {
super(gameView,objectsToCollideWith);
this.freezeState = true;
this.hitBox.width = width-20;