Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PlayState.java 9.63 KiB
package states;

import javafx.scene.canvas.GraphicsContext;
import javafx.scene.input.KeyEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import java.util.concurrent.ThreadLocalRandom;
import constants.Constants;

/**
 * @author oscarwiberg, filipyhde
 * hanterar självaste spelflödet. renderar alla karaktärer och objekt under spelets gång och uppdaterar alla positioner.
 */
public class PlayState extends GameState {

	private String informationText;
	private String livesleft;
	private String gameOverText;
	private Color bgColor;
	private Color lineColor;
	private Color fontColor;
	private Player player;
	private Enemy enemy;
	private boolean collided = false;
	private boolean up = false;
	private boolean gameOver = false;
	private HighScore score = new HighScore();
	private String scoreText;
	private ExtraLifePowerUp extraLife;
	private FlyingEnemy flyingEnemy;
	private int movingSpeed = 10;
	private Enemy bomb;
	private boolean isFlyingEnemyActive = false;
	private String currScore;
	private double collisionX = -1.00;
	private SpeedPowerUp speedUp;
	private boolean isPowerUpActive;
	private int num;
	private String bombImg;
	private PowerUp last = null;
	private boolean speedActive;




	public PlayState(GameModel model, boolean mode) {
		super(model);
		informationText = "Press Escape \nTo Return To The Menu";
		livesleft = "Lives left: ";
		gameOverText = "GAMEOVER\n" + informationText;
		fontColor = Color.BLACK;
		scoreText = "Highscore: " + Integer.toString(score.getHighScore());

		if (mode) {
			mode1();
		} else {
			mode2();
		}

	}

	public void mode1() {
		player = new Player(Constants.playerImg);
		enemy = new Enemy(Constants.enemyImg, 900.00, 270.00, Constants.enemyHeight, Constants.enemyWidth);
		extraLife = new ExtraLifePowerUp(Constants.lifeImg, 1200.00, 170, Constants.powerHeight, Constants.powerWidth);
		speedUp = new SpeedPowerUp(Constants.powerImg, 1200.00, 265.00, Constants.powerHeight, Constants.powerWidth);
		flyingEnemy = new FlyingEnemy(Constants.flyingEnemyImg, 900.00, 20.00, Constants.enemyHeight, Constants.enemyWidth);
		bombImg = Constants.bombImg;
		bgColor = Color.ROYALBLUE;
		lineColor = Color.WHITE;

	}

	public void mode2() {
		player = new Player(Constants.playerImg2);
		enemy = new Enemy(Constants.enemyImg2, 900.00, 270.00, Constants.enemyHeight, Constants.enemyWidth);
		extraLife = new ExtraLifePowerUp(Constants.lifeImg, -100.00, 270, Constants.powerHeight, Constants.powerWidth);
		speedUp = new SpeedPowerUp(Constants.powerImg, -100.00, 265.00, Constants.powerHeight, Constants.powerWidth);
		flyingEnemy = new FlyingEnemy(Constants.flyingEnemyImg2, 900.00, 20.00, Constants.enemyHeight, Constants.enemyWidth);
		bombImg = Constants.bombImg2;
		bgColor = Color.BEIGE;
		lineColor = Color.BLACK;


	}

	/**
	 * Draws information text to the screen.
	 */
	@Override
	public void draw(GraphicsContext g) {
		drawBackground(g);
		drawGameStats(g);
		drawPlayer(g);
		drawEnemies(g);
		drawPowerUps(g);
	}

	private void drawPlayer(GraphicsContext g) {
		g.drawImage(player.getImage(), player.getPlayerX(), player.getPlayerY(), Constants.playerWidth, Constants.playerHeight);		
	}

	private void drawGameStats(GraphicsContext g) {
		currScore = "Currently: " + Integer.toString(player.getPasses());


		g.setFill(fontColor);
		g.setFont(new Font(30)); // Big letters
		//		ritar liv kvar + nuvarande highscore om det inte är gameover, annars ritar den bara gemaovertexten

		if (!gameOver) {
			g.fillText(livesleft+player.getLives(), 0, 30);
			g.fillText(informationText, Constants.screenWidth - 300, 30);
			g.fillText(scoreText, 0, 60);
			g.fillText(currScore, 0, 90);
		} else {
			g.fillText(gameOverText, Constants.screenWidth/2, 200);
			score.saveScore(player.getPasses());
		}

	}

	private void drawBackground(GraphicsContext g) {
		drawBg(g, bgColor);
		g.setStroke(lineColor);
		g.setLineWidth(1);
		g.setLineDashes(2);
		g.strokeLine(Constants.screenWidth, 350, 0, 350);

	}

	private void drawPowerUps(GraphicsContext g) {

		if (isPowerUpActive && !speedActive) {

			if (last == speedUp) {
				num = 1;
			}
			if (num == 0) {
				drawSpeedUp(g);
				last = null;

			} else if (num == 1){
				drawExtraLife(g);
				last = null;
			}
		}
	}

	public void drawSpeedUp(GraphicsContext g) {
		if(speedUp.getX() < 0 - Constants.playerWidth) {
			speedUp.setX(Constants.screenWidth);
			isPowerUpActive = false;
		}

		g.drawImage(speedUp.getImage(), speedUp.getX(), speedUp.getY(), Constants.powerWidth, Constants.powerHeight);

		last = speedUp;
	}

	public void drawExtraLife(GraphicsContext g) {
		if(extraLife.getX() < 0 - Constants.playerWidth) {
			extraLife.setX(Constants.screenWidth);
			isPowerUpActive = false;
		}
		g.drawImage(extraLife.getImage(), extraLife.getX(), extraLife.getY(), Constants.powerWidth, Constants.powerHeight);

		last = extraLife;
	}

	public void drawEnemies(GraphicsContext g) {

		if (!isFlyingEnemyActive) {	
			drawGroundEnemy(g);
		} else {
			drawFlyingEnemy(g);	
		}

		// Render the bomb if it exists
		if (bomb != null) {
			g.drawImage(bomb.getImage(), bomb.getX(), bomb.getY(), Constants.bombWidth, Constants.bombHeight);
		}
	}




	private void drawFlyingEnemy(GraphicsContext g) {
		g.drawImage(flyingEnemy.getImage(), flyingEnemy.getX(), flyingEnemy.getY(), Constants.enemyWidth, Constants.enemyHeight);

		if (flyingEnemy.getX() < 0 - Constants.enemyWidth) {
			flyingEnemy.setX(Constants.screenWidth);
			player.updatePasses(1);
			// Reset bomb drop flag to allow the next bomb drop
			flyingEnemy.resetBombDrop();
			speedCheck();

			int r = getRandom();

			if(r == 1) {
				isFlyingEnemyActive = false;
			}


		}		
	}

	private void drawGroundEnemy(GraphicsContext g) {

		g.drawImage(enemy.getImage(), enemy.getX(), enemy.getY(), Constants.enemyWidth, Constants.enemyHeight);

		if (enemy.getX() < 0 - Constants.enemyWidth) {
			enemy.setX(Constants.screenWidth);
			collided = false;
			collisionX = -1.00;
			player.updatePasses(1);

			speedCheck();


			if (player.getPasses() > 4 && getRandom() == 0) {  // 50% chance after player hase passed 
				isFlyingEnemyActive = true;
				// Reset position
				System.out.println("Stage one activated, flyingenemy added to the mix");
			}
		}		
	}

	//TODO om score är större än visst antal --> lotta mellan flying och vanlig, vi kan göra en random med 2 int, ochberoende på vad den blir kan vi rita en
	//TODO göra en variabel för y positionen som hämtas om vi ritar flygande, för att den ska behålla samma position på hela y axeln

	public void speedCheck() {
		if (player.getPasses() % 5 == 0) {
			movingSpeed += 1;
			System.out.println("speed set to: " + Integer.toString(movingSpeed));
		} else if (player.getPasses() > 10 && player.getPasses() % 2 == 0) {
//			if (movingSpeed < 100) {
				isPowerUpActive = true;			
				num = getRandom();
//			}
		}
	}

	public int getSpeed() {
		return movingSpeed;
	}

	public void setSpeed(int s) {
		
		if (s == 100) {
			speedActive = true;
		} else {
			speedActive = false;
		}
		
		movingSpeed = s;
		
	}


	public int getRandom() {
		return ThreadLocalRandom.current().nextInt(2);
	}








	@Override
	public void keyPressed(KeyEvent key) {


		switch (key.getCode()) {

		case ESCAPE:
			model.switchState(new MenuState(model));
			break;

		case UP:
			//		Om spelaren duckar kan den inte hoppa, då ställer sig spelaren upp istället
			up = true;
			break;

		case LEFT:
			player.moveLeft(movingSpeed);

			break;

		case RIGHT:
			player.moveRight(movingSpeed);

			break;

		default:
			break;
		}
	}


	@Override
	public void update() {

		if (!gameOver) {
			moveEnemies();
			movePowerUps();
			checkGroundCollision();
			checkBombCollision();
			movePlayer();
		}
	}


	private void movePowerUps() {
		if (isPowerUpActive) {

			if (num == 0) {

				speedUp.setX(speedUp.getX() - movingSpeed);
				speedUp.handle(player, this);

			} else if (num == 1) {

				extraLife.setX(extraLife.getX() - movingSpeed);
				extraLife.checkCollision(player, this);

			}
		}

	}


	private void movePlayer() {
		if (up) {

			player.jump(movingSpeed);
		}

		if (player.getPlayerY() == 265) {
			up = false;
		}		
	}


	private void checkGroundCollision() {
		if (!collided && enemy.playerObjectCollision(player)) {
			collided = true;

			if (collisionX == -1.00) {
				collisionX = enemy.getX();
				System.out.println("Player-Enemy Collision X Coordinate: " + collisionX);
			}

			player.decreaseLives();

		}

		if (Integer.valueOf(player.getLives()) == 0) {
			gameOver = true;
		} 		
	}


	private void checkBombCollision() {
		if (bomb != null) {
			bomb.setY(bomb.getY() + movingSpeed);

			if (bomb.playerObjectCollision(player)) {
				System.out.println("Bomb hit the player!");
				player.decreaseLives();  // Assume there's a method to decrement player lives
				bomb = null;  // Destroy the bomb after collision

			}	else if (bomb.getY() > Constants.screenHeight) {
				bomb = null;  // Destroy the bomb if it goes off-screen
				System.out.println("Bomb went off-screen and was destroyed");
			}
		}
	}


	private void moveEnemies() {
		if (isFlyingEnemyActive) {

			flyingEnemy.setX(flyingEnemy.getX() -movingSpeed);

			Enemy droppedBomb = flyingEnemy.dropBomb(player, bombImg);

			if (droppedBomb != null) {
				bomb = droppedBomb;
			}
		} else {
			enemy.setX(enemy.getX() - movingSpeed);
		}
	}

	// Here one would probably instead move the player and any
	// enemies / moving obstacles currently active.

	/**
	 * We currently don't have anything to activate in the PlayState so we leave
	 * this method empty in this case.
	 */
	@Override
	public void activate() {

	}

	/**
	 * We currently don't have anything to deactivate in the PlayState so we leave
	 * this method empty in this case.
	 */
	@Override
	public void deactivate() {

	}
}