/
spirzen
/
it-code-examples
Обзор
Документация
Войти
/
spirzen
/
it-code-examples
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
examples/java/java-503-18-031/main.java
482 строки
16 KB
Spirzen
Code migration pack
09 июн 2026, 01:41
09 июн 2026, 01:41
cebc284
Код
Авторство
О чём код?
package com.test; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.util.*; import java.util.List; import java.util.Timer; import java.util.TimerTask; public class Match3Game extends JPanel { // Размеры игрового поля private static final int ROWS = 8; private static final int COLS = 8; private static final int TILE_SIZE = 70; private static final int TYPES_COUNT = 7; // Цвета фишек с градиентом private static final Color[] COLORS = { new Color(255, 100, 100), // Красный new Color(100, 150, 255), // Синий new Color(100, 255, 100), // Зеленый new Color(255, 255, 100), // Желтый new Color(255, 150, 100), // Оранжевый new Color(200, 100, 255), // Фиолетовый new Color(100, 255, 200) // Бирюзовый }; private int[][] board; private int score; private int combo; private int selectedX = -1, selectedY = -1; private boolean isAnimating = false; private List<Animation> animations; private List<Particle> particles; private javax.swing.Timer gameTimer; private float timeOfDay = 0; // Эффекты private static class Animation { int x, y; float progress; int type; // 0 - падение, 1 - исчезновение, 2 - замена int startValue, endValue; Animation(int x, int y, int type) { this.x = x; this.y = y; this.type = type; this.progress = 0; } } private static class Particle { float x, y; float vx, vy; int life; Color color; Particle(float x, float y, Color color) { this.x = x; this.y = y; this.vx = (float)(Math.random() - 0.5) * 8; this.vy = (float)(Math.random() - 0.5) * 8 - 5; this.life = 30; this.color = color; } void update() { x += vx; y += vy; vy += 0.3; life--; } } public Match3Game() { setPreferredSize(new Dimension(COLS * TILE_SIZE, ROWS * TILE_SIZE + 80)); setBackground(new Color(20, 30, 45)); board = new int[ROWS][COLS]; score = 0; combo = 0; animations = new ArrayList<>(); particles = new ArrayList<>(); initBoard(); removeAllMatches(); // Обработка мыши с визуальной обратной связью addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (!isAnimating) { int x = e.getX() / TILE_SIZE; int y = e.getY() / TILE_SIZE; if (x >= 0 && x < COLS && y >= 0 && y < ROWS) { if (selectedX == -1) { selectedX = x; selectedY = y; repaint(); } else { trySwap(selectedX, selectedY, x, y); selectedX = -1; selectedY = -1; } } else { selectedX = -1; selectedY = -1; repaint(); } } } }); // Таймер для анимации и эффектов gameTimer = new javax.swing.Timer(16, e -> { updateAnimations(); updateParticles(); timeOfDay += 0.02; repaint(); }); gameTimer.start(); } private void initBoard() { Random rand = new Random(); for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { board[i][j] = rand.nextInt(TYPES_COUNT); } } } private void removeAllMatches() { boolean hasMatches; do { hasMatches = false; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { if (isMatchAt(i, j)) { board[i][j] = (board[i][j] + 1) % TYPES_COUNT; hasMatches = true; } } } } while (hasMatches); } private boolean isMatchAt(int row, int col) { int value = board[row][col]; if (value == -1) return false; int count = 1; for (int j = col - 1; j >= 0 && board[row][j] == value; j--) count++; for (int j = col + 1; j < COLS && board[row][j] == value; j++) count++; if (count >= 3) return true; count = 1; for (int i = row - 1; i >= 0 && board[i][col] == value; i--) count++; for (int i = row + 1; i < ROWS && board[i][col] == value; i++) count++; return count >= 3; } private List<Point> findAllMatches() { List<Point> matches = new ArrayList<>(); boolean[][] marked = new boolean[ROWS][COLS]; for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { int value = board[i][j]; if (value == -1) continue; int hCount = 1; for (int k = j + 1; k < COLS && board[i][k] == value; k++) hCount++; if (hCount >= 3) { for (int k = 0; k < hCount; k++) { marked[i][j + k] = true; } } int vCount = 1; for (int k = i + 1; k < ROWS && board[k][j] == value; k++) vCount++; if (vCount >= 3) { for (int k = 0; k < vCount; k++) { marked[i + k][j] = true; } } } } for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { if (marked[i][j]) { matches.add(new Point(j, i)); // Добавляем частицы для эффекта взрыва addExplosionParticles(j * TILE_SIZE + TILE_SIZE/2, i * TILE_SIZE + TILE_SIZE/2, COLORS[board[i][j]]); } } } return matches; } private void addExplosionParticles(float x, float y, Color color) { for (int i = 0; i < 15; i++) { particles.add(new Particle(x, y, color)); } } private int removeMatches() { List<Point> matches = findAllMatches(); if (matches.isEmpty()) return 0; int points = matches.size() * 10; combo++; points *= (1 + combo / 10); score += points; // Добавляем эффект комбо if (combo > 1) { addComboEffect(points); } for (Point p : matches) { board[p.y][p.x] = -1; animations.add(new Animation(p.x, p.y, 1)); } return points; } private void addComboEffect(int points) { // Эффект комбо будет отображаться при отрисовке } private void applyGravity() { for (int j = 0; j < COLS; j++) { int writeRow = ROWS - 1; for (int i = ROWS - 1; i >= 0; i--) { if (board[i][j] != -1) { if (writeRow != i) { animations.add(new Animation(j, i, 0)); } board[writeRow--][j] = board[i][j]; } } for (int i = writeRow; i >= 0; i--) { board[i][j] = -1; } } } private void refillBoard() { Random rand = new Random(); for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { if (board[i][j] == -1) { board[i][j] = rand.nextInt(TYPES_COUNT); animations.add(new Animation(j, i, 2)); } } } } private boolean processMatches() { int points = removeMatches(); if (points > 0) { applyGravity(); refillBoard(); return true; } return false; } private void processAllMatches() { isAnimating = true; new Thread(() -> { while (processMatches()) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } isAnimating = false; combo = 0; }).start(); } private void trySwap(int x1, int y1, int x2, int y2) { if (Math.abs(x1 - x2) + Math.abs(y1 - y2) != 1) return; int temp = board[y1][x1]; board[y1][x1] = board[y2][x2]; board[y2][x2] = temp; List<Point> matches = findAllMatches(); if (!matches.isEmpty()) { processAllMatches(); } else { temp = board[y1][x1]; board[y1][x1] = board[y2][x2]; board[y2][x2] = temp; // Анимация ошибки shakeTile(x1, y1); shakeTile(x2, y2); } repaint(); } private void shakeTile(int x, int y) { animations.add(new Animation(x, y, 3)); } private void updateAnimations() { animations.removeIf(anim -> { anim.progress += 0.1; return anim.progress >= 1; }); } private void updateParticles() { particles.removeIf(p -> p.life <= 0); particles.forEach(p -> p.update()); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // Градиентный фон GradientPaint gradient = new GradientPaint(0, 0, new Color(20, 30, 45), getWidth(), getHeight(), new Color(35, 45, 65)); g2d.setPaint(gradient); g2d.fillRect(0, 0, getWidth(), getHeight()); // Рисуем сетку и фишки for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { int x = j * TILE_SIZE; int y = i * TILE_SIZE; if (board[i][j] != -1) { // Проверяем анимацию для этой позиции boolean isAnimating = false; for (Animation anim : animations) { if (anim.x == j && anim.y == i) { isAnimating = true; break; } } // Рисуем фишку с эффектом drawTile(g2d, x, y, board[i][j], isAnimating); } else { // Пустая клетка g2d.setColor(new Color(45, 55, 75)); g2d.fillRoundRect(x + 2, y + 2, TILE_SIZE - 4, TILE_SIZE - 4, 10, 10); } // Рисуем рамку g2d.setColor(new Color(100, 120, 150, 100)); g2d.drawRoundRect(x + 1, y + 1, TILE_SIZE - 2, TILE_SIZE - 2, 12, 12); } } // Рисуем выделение выбранной фишки if (selectedX != -1 && selectedY != -1 && !isAnimating) { int x = selectedX * TILE_SIZE; int y = selectedY * TILE_SIZE; g2d.setColor(new Color(255, 255, 100, 150)); g2d.setStroke(new BasicStroke(3)); g2d.drawRoundRect(x + 3, y + 3, TILE_SIZE - 6, TILE_SIZE - 6, 12, 12); // Пульсирующий эффект float pulse = (float)(Math.sin(System.currentTimeMillis() / 100.0) * 0.3 + 0.7); g2d.setColor(new Color(255, 255, 200, (int)(50 * pulse))); g2d.fillRoundRect(x + 3, y + 3, TILE_SIZE - 6, TILE_SIZE - 6, 12, 12); } // Рисуем частицы for (Particle p : particles) { float alpha = p.life / 30f; g2d.setColor(new Color(p.color.getRed(), p.color.getGreen(), p.color.getBlue(), (int)(alpha * 255))); g2d.fillOval((int)p.x - 3, (int)p.y - 3, 6, 6); } // Рисуем интерфейс drawUI(g2d); } private void drawTile(Graphics2D g2d, int x, int y, int type, boolean animating) { Color baseColor = COLORS[type]; Color lightColor = baseColor.brighter(); Color darkColor = baseColor.darker(); // Градиентная заливка GradientPaint gradient = new GradientPaint(x, y, lightColor, x + TILE_SIZE, y + TILE_SIZE, darkColor); g2d.setPaint(gradient); // Анимация для падающих/исчезающих фишек if (animating) { g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); } g2d.fillRoundRect(x + 2, y + 2, TILE_SIZE - 4, TILE_SIZE - 4, 15, 15); // Блик g2d.setColor(new Color(255, 255, 255, 100)); g2d.fillRoundRect(x + 4, y + 4, TILE_SIZE - 8, TILE_SIZE / 3, 10, 10); // Узор на фишке g2d.setColor(new Color(255, 255, 255, 80)); g2d.setStroke(new BasicStroke(2)); g2d.drawRoundRect(x + 5, y + 5, TILE_SIZE - 10, TILE_SIZE - 10, 10, 10); // Центральная точка g2d.fillOval(x + TILE_SIZE/2 - 3, y + TILE_SIZE/2 - 3, 6, 6); if (animating) { g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f)); } } private void drawUI(Graphics2D g2d) { int uiY = ROWS * TILE_SIZE + 20; // Фон для счета g2d.setColor(new Color(0, 0, 0, 150)); g2d.fillRoundRect(10, uiY - 10, 250, 60, 15, 15); // Счет g2d.setColor(Color.WHITE); g2d.setFont(new Font("Arial", Font.BOLD, 28)); g2d.drawString("Score: " + score, 20, uiY + 25); // Комбо if (combo > 1) { g2d.setFont(new Font("Arial", Font.BOLD, 24)); g2d.setColor(new Color(255, 200, 0)); String comboText = "COMBO x" + combo + "!"; FontMetrics fm = g2d.getFontMetrics(); int textWidth = fm.stringWidth(comboText); g2d.drawString(comboText, getWidth() - textWidth - 20, uiY + 25); } // Подсказка g2d.setFont(new Font("Arial", Font.PLAIN, 14)); g2d.setColor(new Color(200, 200, 200)); g2d.drawString("Click on a tile to select, then click on adjacent tile to swap", 20, uiY + 55); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("✨ Match3 - Три в ряд ✨"); Match3Game game = new Match3Game(); frame.add(game); frame.pack(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setResizable(false); frame.setLocationRelativeTo(null); // Красивая иконка (опционально) try { frame.setIconImage(Toolkit.getDefaultToolkit().getImage( Match3Game.class.getResource("/icon.png"))); } catch (Exception e) { // Игнорируем, если нет иконки } frame.setVisible(true); }); } }