diff --git a/README.md b/README.md index 409928494..2386a67f8 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,15 @@ # Games in Java - Object-Oriented Programming with JavaFX -This repository is designed to demonstrate core **Object-Oriented Programming (OOP)** concepts in Java using JavaFX through a series of popular game examples. The goal is to help developers learn and visualize OOP principles in action, from basic class structure to advanced inheritance and encapsulation. - -## About This Project - -Dive into the code for classic games like **Snake, Chess, Tic-Tac-Toe,** and **Pac-Man** to explore JavaFX's capabilities and understand how OOP principles can structure games effectively. Each game has been carefully crafted to illustrate specific OOP concepts, making it ideal for anyone wanting to learn Java through hands-on projects. - -If you have suggestions or encounter issues with this project, please [create a new GitHub issue](https://github.com/peterarsentev/games_oop_javafx/issues). - -If you’re looking to deepen your understanding of OOP in Java, -consider joining the course Mastering Object-Oriented Programming in Java. -This comprehensive, 104-lesson course is designed to build both a theoretical foundation -and practical skills essential for applying OOP in real-world scenarios. - -## Join for Free! ## - -**Contact me on Telegram:** [@parsentev](https://t.me/parsentev) - -Let me know if you'd like any further adjustments! - -## About the Course: *Mastering Object-Oriented Programming in Java* +Hi, I'm Peter. I created this project +to show my idea about +how to use **Object-Oriented Programming (OOP)** concepts +in Java using JavaFX through a series of popular game examples. ### Course Overview -This course, *Mastering Object-Oriented Programming in Java*, is designed to teach and reinforce the foundational concepts of **OOP in Java**. Through 104 structured lessons, you’ll gain both theoretical and practical skills essential for real-world applications. +This course, *Mastering Object-Oriented Programming in Java*, +is designed to teach and reinforce the foundational concepts of **OOP in Java**. +Through 104 structured lessons, you’ll gain both theoretical and practical skills essential for real-world applications. ### Course Structure @@ -36,13 +22,14 @@ Each lesson is organized into three main sections: Every solution you submit receives detailed, personalized feedback. This focuses on best practices and areas for improvement, ensuring continuous growth and a deep understanding of Java's OOP principles. -### Ideal for +### Join for free -This course is perfect for students and developers looking to build a strong OOP foundation in Java, supported by structured lessons and expert feedback. +In order to promote my course I have decided to start it for free, +so if you want to join my course contact me on email: parsentev@yandex.ru ---- +How it will work. I will send you one lesson by email. Each lesson contains: theory, exercises and task. +You have to solve the task and send it back to me so I can check it and give you feedback. -Enhance your understanding of **Java OOP** with these interactive projects, and if you're interested, dive deeper with our course to truly master object-oriented programming. ## Game Examples diff --git a/packman/src/main/java/ru/job4j/packman/Enemies.java b/packman/src/main/java/ru/job4j/packman/Enemies.java index 117b9605e..09d138d7f 100644 --- a/packman/src/main/java/ru/job4j/packman/Enemies.java +++ b/packman/src/main/java/ru/job4j/packman/Enemies.java @@ -10,17 +10,15 @@ public class Enemies { record Enemy(int x, int y) { } - public GraphicsContext gc; - private final int width; - private final int height; + private final GraphicsContext gc; private final int playerSize; private final int enemySize; private final int enemySpeed; private final Set enemies = new HashSet<>(); - public Enemies(int width, int height, int playerSize, int enemySize, int enemySpeed) { - this.width = width; - this.height = height; + public Enemies(GraphicsContext gc, + int playerSize, int enemySize, int enemySpeed) { + this.gc = gc; this.playerSize = playerSize; this.enemySize = enemySize; this.enemySpeed = enemySpeed; @@ -42,8 +40,8 @@ public void update(Pacman pacman, Walls walls) { Set updatedEnemies = new HashSet<>(); for (var enemy : enemies) { - double diffX = pacman.playerX - enemy.x(); - double diffY = pacman.playerY - enemy.y(); + double diffX = pacman.getPlayerX() - enemy.x(); + double diffY = pacman.getPlayerY() - enemy.y(); int newX = enemy.x(); int newY = enemy.y(); @@ -51,14 +49,14 @@ public void update(Pacman pacman, Walls walls) { boolean moved = false; // Prioritize movement based on same position on one axis - if (enemy.x() == pacman.playerX) { + if (enemy.x() == pacman.getPlayerX()) { // Same x position, move by y coordinate double nextY = enemy.y() + Math.signum(diffY) * enemySpeed; if (!isCollision(enemy.x(), nextY, walls) && !isEnemyCollision(newX, (int) nextY)) { newY = (int) nextY; moved = true; } - } else if (enemy.y() == pacman.playerY) { + } else if (enemy.y() == pacman.getPlayerY()) { // Same y position, move by x coordinate double nextX = enemy.x() + Math.signum(diffX) * enemySpeed; if (!isCollision(nextX, enemy.y(), walls) && !isEnemyCollision((int) nextX, newY)) { @@ -70,14 +68,16 @@ public void update(Pacman pacman, Walls walls) { if (Math.abs(diffX) <= Math.abs(diffY)) { // Move by x coordinate double nextX = enemy.x() + Math.signum(diffX) * enemySpeed; - if (!isCollision(nextX, enemy.y(), walls) && !isEnemyCollision((int) nextX, newY)) { + if (!isCollision(nextX, enemy.y(), walls) + && !isEnemyCollision((int) nextX, newY)) { newX = (int) nextX; moved = true; } } else { // Move by y coordinate double nextY = enemy.y() + Math.signum(diffY) * enemySpeed; - if (!isCollision(enemy.x(), nextY, walls) && !isEnemyCollision(newX, (int) nextY)) { + if (!isCollision(enemy.x(), nextY, walls) + && !isEnemyCollision(newX, (int) nextY)) { newY = (int) nextY; moved = true; } @@ -117,11 +117,14 @@ private boolean isCollision(double x, double y, Walls walls) { int gridYStart = (int) (y / playerSize); int gridXEnd = (int) ((x + enemySize - 1) / playerSize); int gridYEnd = (int) ((y + enemySize - 1) / playerSize); - - if (gridXStart < 0 || gridXEnd >= maze.length || gridYStart < 0 || gridYEnd >= maze[0].length) { + if (gridXStart < 0 || gridXEnd >= maze.length + || gridYStart < 0 || gridYEnd >= maze[0].length) { return true; } - return maze[gridXStart][gridYStart] || maze[gridXEnd][gridYStart] || maze[gridXStart][gridYEnd] || maze[gridXEnd][gridYEnd]; + return maze[gridXStart][gridYStart] + || maze[gridXEnd][gridYStart] + || maze[gridXStart][gridYEnd] + || maze[gridXEnd][gridYEnd]; } public void draw() { @@ -130,8 +133,10 @@ public void draw() { gc.fillArc(enemy.x(), enemy.y(), enemySize, enemySize, 0, 180, ArcType.ROUND); gc.fillRect(enemy.x(), enemy.y() + enemySize / 2, enemySize, enemySize / 2); gc.setFill(Color.WHITE); - gc.fillOval(enemy.x() + enemySize * 0.2, enemy.y() + enemySize * 0.2, enemySize * 0.2, enemySize * 0.2); - gc.fillOval(enemy.x() + enemySize * 0.6, enemy.y() + enemySize * 0.2, enemySize * 0.2, enemySize * 0.2); + gc.fillOval(enemy.x() + enemySize * 0.2, + enemy.y() + enemySize * 0.2, enemySize * 0.2, enemySize * 0.2); + gc.fillOval(enemy.x() + enemySize * 0.6, + enemy.y() + enemySize * 0.2, enemySize * 0.2, enemySize * 0.2); gc.setFill(Color.RED); } } diff --git a/packman/src/main/java/ru/job4j/packman/Pacman.java b/packman/src/main/java/ru/job4j/packman/Pacman.java index f5ddc24ce..e7c310e59 100644 --- a/packman/src/main/java/ru/job4j/packman/Pacman.java +++ b/packman/src/main/java/ru/job4j/packman/Pacman.java @@ -9,13 +9,19 @@ public class Pacman { private static final int PLAYER_SIZE = 40; - public GraphicsContext gc; - public double playerX; - public double playerY; - public double playerSpeed = 5; - public double mouthAngle = 45; - public boolean mouthOpening = true; - public double mouthDirection = 90; + private final GraphicsContext gc; + private double playerX; + private double playerY; + private final double playerSpeed = 5; + private double mouthAngle = 45; + private boolean mouthOpening = true; + private double mouthDirection = 90; + + public Pacman(GraphicsContext gc, double playerX, double playerY) { + this.playerX = playerX; + this.playerY = playerY; + this.gc = gc; + } public void draw() { gc.setFill(Color.YELLOW); @@ -71,9 +77,19 @@ private boolean isCollision(double x, double y, Walls walls) { int gridXEnd = (int) ((x + PLAYER_SIZE - 1) / PLAYER_SIZE); int gridYEnd = (int) ((y + PLAYER_SIZE - 1) / PLAYER_SIZE); - if (gridXStart < 0 || gridXEnd >= maze.length || gridYStart < 0 || gridYEnd >= maze[0].length) { + if (gridXStart < 0 || gridXEnd >= maze.length + || gridYStart < 0 || gridYEnd >= maze[0].length) { return true; } - return maze[gridXStart][gridYStart] || maze[gridXEnd][gridYStart] || maze[gridXStart][gridYEnd] || maze[gridXEnd][gridYEnd]; + return maze[gridXStart][gridYStart] || maze[gridXEnd][gridYStart] + || maze[gridXStart][gridYEnd] || maze[gridXEnd][gridYEnd]; + } + + public double getPlayerX() { + return playerX; + } + + public double getPlayerY() { + return playerY; } } \ No newline at end of file diff --git a/packman/src/main/java/ru/job4j/packman/PacmanGame.java b/packman/src/main/java/ru/job4j/packman/PacmanGame.java index fa32cbecf..d46a88834 100644 --- a/packman/src/main/java/ru/job4j/packman/PacmanGame.java +++ b/packman/src/main/java/ru/job4j/packman/PacmanGame.java @@ -41,20 +41,16 @@ public void start(Stage primaryStage) { primaryStage.setScene(scene); primaryStage.show(); - walls = new Walls(WIDTH, HEIGHT, PLAYER_SIZE); + walls = new Walls(gc, WIDTH, HEIGHT, PLAYER_SIZE); walls.initializeMaze(); - walls.gc = gc; - pellets = new Pellets(WIDTH, HEIGHT, PLAYER_SIZE, PELLET_SIZE); + pellets = new Pellets(gc, WIDTH, HEIGHT, PLAYER_SIZE, PELLET_SIZE); pellets.initializePellets(walls); - pellets.gc = gc; - enemies = new Enemies(WIDTH, HEIGHT, PLAYER_SIZE, ENEMY_SIZE, ENEMY_SPEED); + enemies = new Enemies(gc, PLAYER_SIZE, ENEMY_SIZE, ENEMY_SPEED); enemies.initializeEnemies(walls); - enemies.gc = gc; - pacman = initializePlayerPosition(); - pacman.gc = gc; + pacman = initializePlayerPosition(gc); scene.setOnKeyPressed(event -> pressedKeys.add(event.getCode())); scene.setOnKeyReleased(event -> pressedKeys.remove(event.getCode())); @@ -69,14 +65,14 @@ public void handle(long now) { timer.start(); } - private Pacman initializePlayerPosition() { + private Pacman initializePlayerPosition(GraphicsContext gc) { for (int i = 0; i < walls.getMaze().length; i++) { for (int j = 0; j < walls.getMaze()[i].length; j++) { if (!walls.getMaze()[i][j]) { - var pacman = new Pacman(); - pacman.playerX = i * PLAYER_SIZE; - pacman.playerY = j * PLAYER_SIZE; - return pacman; + return new Pacman(gc, + i * PLAYER_SIZE, + j * PLAYER_SIZE + ); } } } diff --git a/packman/src/main/java/ru/job4j/packman/Pellets.java b/packman/src/main/java/ru/job4j/packman/Pellets.java index 0a17eefde..10ef90b00 100644 --- a/packman/src/main/java/ru/job4j/packman/Pellets.java +++ b/packman/src/main/java/ru/job4j/packman/Pellets.java @@ -7,33 +7,40 @@ import java.util.Set; public class Pellets { + private final GraphicsContext gc; private final int width; private final int height; private final int playerSize; private final int pelletSize; private final Set pellets = new HashSet<>(); - public GraphicsContext gc; - public Pellets(int width, int height, int playerSize, int pelletSize) { + public Pellets(GraphicsContext gc, int width, int height, int playerSize, int pelletSize) { this.width = width; this.height = height; this.playerSize = playerSize; this.pelletSize = pelletSize; + this.gc = gc; } public void initializePellets(Walls walls) { for (int i = 0; i < width; i += playerSize) { for (int j = 0; j < height; j += playerSize) { if (!walls.getMaze()[i / playerSize][j / playerSize]) { - pellets.add(new double[]{i + playerSize / 2.0 - pelletSize / 2.0, j + playerSize / 2.0 - pelletSize / 2.0}); + pellets.add(new double[] { + i + playerSize / 2.0 - pelletSize / 2.0, + j + playerSize / 2.0 - pelletSize / 2.0 + }); } } } } public void checkCollision(Pacman pacman) { - pellets.removeIf(pellet -> pacman.playerX < pellet[0] + pelletSize && pacman.playerX + playerSize > pellet[0] && - pacman.playerY < pellet[1] + pelletSize && pacman.playerY + playerSize > pellet[1]); + pellets.removeIf( + pellet -> pacman.getPlayerX() < pellet[0] + pelletSize + && pacman.getPlayerX() + playerSize > pellet[0] + && pacman.getPlayerY() < pellet[1] + pelletSize + && pacman.getPlayerY() + playerSize > pellet[1]); } public void draw() { diff --git a/packman/src/main/java/ru/job4j/packman/Walls.java b/packman/src/main/java/ru/job4j/packman/Walls.java index ff9dfdab6..3916b47d9 100644 --- a/packman/src/main/java/ru/job4j/packman/Walls.java +++ b/packman/src/main/java/ru/job4j/packman/Walls.java @@ -5,16 +5,11 @@ public class Walls { private static final int PLAYER_SIZE = 40; - public GraphicsContext gc; + private final GraphicsContext gc; private final boolean[][] maze; - private final int width; - private final int height; - private final int playerSize; - public Walls(int width, int height, int playerSize) { - this.width = width; - this.height = height; - this.playerSize = playerSize; + public Walls(GraphicsContext gc, int width, int height, int playerSize) { + this.gc = gc; this.maze = new boolean[width / playerSize][height / playerSize]; } @@ -23,10 +18,10 @@ public void initializeMaze() { for (int j = 0; j < maze[i].length; j++) { if (i == 0 || i == maze.length - 1 || j == 0 || j == maze[i].length - 1) { maze[i][j] = true; - } else if (i % 2 == 0 && j % 2 == 0 && i != maze.length - 2 && j != maze[i].length - 2) { - maze[i][j] = true; } else { - maze[i][j] = false; + maze[i][j] = i % 2 == 0 && j % 2 == 0 + && i != maze.length - 2 + && j != maze[i].length - 2; } } } diff --git a/snake/src/main/java/ru/job4j/tetris/Main.java b/snake/src/main/java/ru/job4j/tetris/Main.java index 638c357cf..90f25f4fa 100644 --- a/snake/src/main/java/ru/job4j/tetris/Main.java +++ b/snake/src/main/java/ru/job4j/tetris/Main.java @@ -16,7 +16,7 @@ public class Main extends Application { private static final String JOB4J = "Snake"; - private final int size = 10; + private static final int SIZE = 10; private final Snake snake = new Snake(List.of( new Cell(0, 0), new Cell(1, 0), new Cell(2, 0)) ); @@ -46,8 +46,8 @@ private Rectangle block(Cell cell, Color color) { private Group buildGrid() { Group panel = new Group(); - for (int y = 0; y != this.size; y++) { - for (int x = 0; x != this.size; x++) { + for (int y = 0; y != this.SIZE; y++) { + for (int x = 0; x != this.SIZE; x++) { panel.getChildren().add( this.buildRectangle(x, y, 40) ); @@ -127,7 +127,6 @@ private void redrawSnake(Group group) { drawSnake(group); } - public static void main(String[] args) { Main.launch(args); } diff --git a/tetris/src/main/java/ru/job4j/tetris/Figure.java b/tetris/src/main/java/ru/job4j/tetris/Figure.java index bf0a72b47..4b6ceecc2 100644 --- a/tetris/src/main/java/ru/job4j/tetris/Figure.java +++ b/tetris/src/main/java/ru/job4j/tetris/Figure.java @@ -1,9 +1,7 @@ package ru.job4j.tetris; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; public class Figure { private List body; @@ -24,7 +22,6 @@ public void move() { body = newBody; } - List asCells() { return body; }