import javax.swing.*; import java.awt.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Comparator; public class CarAnimation extends JFrame { public CarAnimation() { setTitle("Анимация с машинкой"); setSize(1280, 720); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); // панель анимации AnimationPanel panel = new AnimationPanel(); JMenuBar menuBar = new JMenuBar(); // меню файл JMenu fileMenu = new JMenu("Файл"); JMenuItem useFolderItem = new JMenuItem("Использовать картинки из папки"); JMenuItem exitItem = new JMenuItem("Выход"); useFolderItem.addActionListener(e -> { JFileChooser chooser = new JFileChooser(); // только папки chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); chooser.setDialogTitle("Выберите папку с изображениями машинок"); int returnVal = chooser.showOpenDialog(CarAnimation.this); if (returnVal == JFileChooser.APPROVE_OPTION) { // выбранная папка в панель panel.loadImagesFromFolder(chooser.getSelectedFile()); } }); exitItem.addActionListener(e -> System.exit(0)); fileMenu.add(useFolderItem); fileMenu.add(exitItem); // меню скорость JMenu speedMenu = new JMenu("Скорость машинки"); JMenuItem slowSpeed = new JMenuItem("Медленно"); JMenuItem normalSpeed = new JMenuItem("Нормально"); JMenuItem fastSpeed = new JMenuItem("Быстро"); slowSpeed.addActionListener(e -> panel.setSpeed(100)); normalSpeed.addActionListener(e -> panel.setSpeed(50)); fastSpeed.addActionListener(e -> panel.setSpeed(20)); speedMenu.add(slowSpeed); speedMenu.add(normalSpeed); speedMenu.add(fastSpeed); // меню справка JMenu helpMenu = new JMenu("Справка"); JMenuItem aboutItem = new JMenuItem("О программе"); aboutItem.addActionListener(e -> JOptionPane.showMessageDialog(this, "Анимация машинки\nУправление: наведите мышь на окно.")); helpMenu.add(aboutItem); // сборка менюбара menuBar.add(fileMenu); menuBar.add(speedMenu); menuBar.add(helpMenu); setJMenuBar(menuBar); add(panel); } public static void main(String[] args) { SwingUtilities.invokeLater(() -> { CarAnimation app = new CarAnimation(); app.setVisible(true); }); } } class AnimationPanel extends JPanel implements MouseListener, java.awt.event.MouseMotionListener { private final BufferedImage[] frames; private int currentFrameIndex = 0; private volatile boolean isMouseInside = false; // флаг для управления потоком private final Thread animationThread; private volatile int speedDelay = 100; // переменная для скорости private BufferedImage[] currentFrames; // чтобы можно было менять массив картинок private volatile boolean isFolderMode = false; // true, если загружены файлы из папки // метод для изменения скорости public void setSpeed(int newSpeed) { this.speedDelay = newSpeed; } // метод для загрузки картинок из папки public void loadImagesFromFolder(File folder) { // список всех файлов в папке File[] files = folder.listFiles(); if (files == null || files.length == 0) { JOptionPane.showMessageDialog(this, "Папка пуста!"); return; } // только картинки (png, jpg, gif) File[] imageFiles = Arrays.stream(files) .filter(f -> f.getName().toLowerCase().endsWith(".png") || f.getName().toLowerCase().endsWith(".jpg") || f.getName().toLowerCase().endsWith(".jpeg") || f.getName().toLowerCase().endsWith(".gif")) .sorted(Comparator.comparing(File::getName)) // сортировка по имени .toArray(File[]::new); if (imageFiles.length == 0) { JOptionPane.showMessageDialog(this, "В выбранной папке нет подходящих изображений!"); return; } // найденные файлы в массив BufferedImage BufferedImage[] newFrames = new BufferedImage[imageFiles.length]; try { for (int i = 0; i < imageFiles.length; i++) { newFrames[i] = ImageIO.read(imageFiles[i]); } // обновляем массив в панели this.currentFrames = newFrames; this.isFolderMode = true; this.currentFrameIndex = 0; // Сбрасываем кадр на первый this.repaint(); JOptionPane.showMessageDialog(this, "Загружено кадров: " + newFrames.length); } catch (IOException e) { JOptionPane.showMessageDialog(this, "Ошибка при чтении файлов: " + e.getMessage()); e.printStackTrace(); } } private int carX = 0; public AnimationPanel() { // подготовка изображений frames = prepareImages(); this.currentFrames = prepareImages(); // создание и запуск потока анимации animationThread = new Thread(new Runnable() { @Override public void run() { while (true) { try { if (carX > getWidth()) { carX = -200; // Сбрасываем на ширину новой машинки, чтобы она выезжала плавно } if (isMouseInside) { // Двигаем машинку вправо carX += 15; // Если машинка уехала за правый край, возвращаем её за левый край if (carX > getWidth()) { carX = -100; } // Если нужны еще и смены кадров (анимация колес и т.д.) currentFrameIndex = (currentFrameIndex + 1) % frames.length; repaint(); Thread.sleep(speedDelay); } else { Thread.sleep(50); } } catch (InterruptedException e) { break; } } } }); animationThread.start(); addMouseListener(this); addMouseMotionListener(this); } private BufferedImage createDummyCar(int frame, int total) { BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); Graphics2D g = img.createGraphics(); // 1. Рисуем корпус машинки g.setColor(Color.RED); g.fillRect(0, 40, 100, 40); // крыша g.setColor(Color.RED); g.fillRect(20, 20, 60, 20); // 2. Рисуем окна // Цвет стекла (светло-голубой) g.setColor(new Color(173, 216, 230)); // Переднее окно g.fillRect(30, 25, 15, 15); // Заднее окно g.fillRect(55, 25, 15, 15); // // Добавляем черную обводку для окон, чтобы они были четкими // g.setColor(Color.BLACK); // g.drawRect(20, 45, 25, 15); // g.drawRect(50, 45, 25, 15); // 3. Рисуем колеса g.setColor(Color.BLACK); g.fillOval(10, 70, 20, 20); g.fillOval(70, 70, 20, 20); g.dispose(); return img; } private BufferedImage[] prepareImages() { int frameCount = 1; // количество кадров this.isFolderMode = false; BufferedImage[] imgArray = new BufferedImage[frameCount]; // создание болванок for (int i = 0; i < frameCount; i++) { imgArray[i] = createDummyCar(i, frameCount); } return imgArray; } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); if (frames.length > 0) { // 1. Параметры машинки int originalWidth = frames[0].getWidth(); int originalHeight = frames[0].getHeight(); int newWidth = originalWidth * 2; int newHeight = originalHeight * 2; int x = carX; int y = (getHeight() - newHeight) / 2; // 2. Параметры дороги int roadHeight = 80; int roadY = y + newHeight - 90; // Дорога под колесами // --- ОТРИСОВКА ФОНА (СЛОИ) --- // Слой 1: Небо (голубое) // Рисуем на весь экран g.setColor(new Color(135, 206, 235)); // Цвет SkyBlue g.fillRect(0, 0, getWidth(), getHeight()); // Слой 2: Трава (темно-зеленая) // Рисуем от нижней границы дороги до самого низа экрана g.setColor(new Color(34, 139, 34)); // Цвет ForestGreen int grassStartY = roadY + roadHeight; int grassHeight = getHeight() - grassStartY; if (grassHeight > 0) { g.fillRect(0, grassStartY, getWidth(), grassHeight); } // Слой 3: Дорога (темно-серая) g.setColor(Color.DARK_GRAY); g.fillRect(0, roadY, getWidth(), roadHeight); // Слой 4: Разметка (белая) g.setColor(Color.WHITE); for (int i = 0; i < getWidth(); i += 60) { g.fillRect(i, roadY + (roadHeight / 2) - 3, 30, 6); } // --- ОТРИСОВКА ОБЪЕКТОВ --- // Слой 5: Машинка (поверх всего) g.drawImage(currentFrames[currentFrameIndex], x, y, newWidth, newHeight, this); } if (isFolderMode) { g.setColor(Color.BLUE); g.drawString("Кадров в папке: " + currentFrames.length, 10, 40); } // подсказка g.setColor(Color.GRAY); g.drawString(isMouseInside ? "Статус: Анимация работает" : "Статус: Пауза (мышь снаружи)", 10, 20); } // Реализация методов MouseListener @Override public void mouseEntered(MouseEvent e) { isMouseInside = true; // запуск } @Override public void mouseExited(MouseEvent e) { isMouseInside = false; // остановка } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseMoved(MouseEvent e) {} @Override public void mouseDragged(MouseEvent e) {} }