307 lines
12 KiB
Java
307 lines
12 KiB
Java
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) {}
|
||
} |