Zielony Smok - logo witryny

Animacja “Rój owadów” podążających za kursorem myszy

Pomysł tej animacji nie był moim pomysłem. Inspiracją był rój owadów przedstawiony w książce: Bhangal S., 2000. Flash 5. ActionScript. Podstawy, Helion, rozdz. 10. Animacja w ActionScript różni się tak bardzo od animacji w języku Java, że aplikacja została (oczywiście) napisana od nowa.

Uwagi do wykonania

Ciało owada Body implementuje Shape.

Klasa Insect wykorzystuje klasę Body do stworzenia całego owada i określenia parametrów jego ruchu. Każdy owad jest obiektem implementującym Runnable. Jednym słowem żyje na swój własny sposób, w swoim własnym wątku.

Klasa Swarm tworzy rój owadów i środowisko życia dla nich.

Klasa Util zawiera parę potrzebnych metod.

Klasa Main uruchamia aplikację.

Klasy

Klasa Body
package swarm;

import java.awt.*;
import java.awt.geom.*;

public class Body implements Shape {

    private final GeneralPath path;

    public Body(float x, float y, float w, float h) {
        path = new GeneralPath();
        path.moveTo(x, y);
        path.lineTo(x + w / 2f, y + 2f * h / 3f);
        path.lineTo(x + w, y);
        path.moveTo(x + w / 4f, y + h);
        path.lineTo(x + w / 2f, y + 2f * h / 3f);
        path.lineTo(x + 3f / 4f * w, y + h);
    }

    @Override
    public boolean contains(Point2D p) {
        return path.contains(p);
    }

    @Override
    public boolean contains(Rectangle2D r) {
        return path.contains(r);
    }

    @Override
    public boolean contains(double x, double y) {
        return path.contains(x, y);
    }

    @Override
    public boolean contains(double x, double y, double w, double h) {
        return path.contains(x, y, w, h);
    }

    @Override
    public Rectangle getBounds() {
        return path.getBounds();
    }

    @Override
    public Rectangle2D getBounds2D() {
        return path.getBounds2D();
    }

    @Override
    public PathIterator getPathIterator(AffineTransform at) {
        return path.getPathIterator(at);
    }

    @Override
    public PathIterator getPathIterator(AffineTransform at, double flatness) {
        return path.getPathIterator(at, flatness);
    }

    @Override
    public boolean intersects(Rectangle2D r) {
        return path.intersects(r);
    }

    @Override
    public boolean intersects(double x, double y, double w, double h) {
        return path.intersects(x, y, w, h);
    }
}
Klasa Insect
package swarm;

import java.awt.*;
import javax.swing.*;

public class Insect extends JComponent implements Runnable {
    private static final long serialVersionUID = -1022417174863360222L;
    private static final double a = 20.0;
    private static final double b = 50;
    private static final double c = 2 * b;
    private static final double d = 4 * b;
    private static final double e = 8 * b;
    private static final double f = 12 * b;
    private static final double p1 = 0.8;
    private static final double p2 = 0.9;
    private Body body;
    private double x;
    private double y;
    private double dx = 0;
    private double dy = 0;
    private double tX = 0;
    private double tY = 0;
    private double oTX = 0;
    private double oTY = 0;
    private double rX = (Math.random() * d) - c;
    private double rY = (Math.random() * d) - c;
    private Color color;

    public Insect() {
        this(Color.BLACK);
    }

    public Insect(Color color) {
        this.color = color;
        body = new Body(1, 1, 4, 3);
        x = Util.randomInRange(d, f);
        y = Util.randomInRange(d, f);
        setBounds(0, 0, 6, 5);
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        g2.setColor(color);
        g2.draw(body);
    }

    @Override
    public void run() {
        while (true) {
            move(Insect.this.getParent());
            this.setLocation((int) x, (int) y);
            Insect.this.getParent().repaint();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void move(Container panel) {
        Point cursor = Insect.this.getParent().getMousePosition();
        if (cursor != null) {
            tX = cursor.getX();
            tY = cursor.getY();
            if ((tX == oTX) && (Math.random() > p2)) {
                rX = (Math.random() * c) - b;
                rY = (Math.random() * c) - b;
            } else if ((tX != oTX) && (Math.random() > p1)) {
                rX = (Math.random() * e) - c;
                rY = (Math.random() * e) - c;
            }
            dx = tX - x + rX;
            dy = tY - y + rY;
            x = Math.round(x + dx / a);
            y = Math.round(y + dy / a);
            oTX = tX;
            oTY = tY;
        } else {
            tX = oTX;
            tY = oTY;
            if ((tX == oTX) && (Math.random() > p2)) {
                rX = (Math.random() * c) - b;
                rY = (Math.random() * c) - b;
            } else if ((tX != oTX) && (Math.random() > p1)) {
                rX = (Math.random() * e) - d;
                rY = (Math.random() * e) - d;
            }
            dx = tX - x + rX;
            dy = tY - y + rY;
            x = Math.round(x + dx / a);
            y = Math.round(y + dy / a);
            oTX = tX;
            oTY = tY;
        }
    }

    public Body getBody() {
        return body;
    }

    public void setBody(Body body) {
        this.body = body;
    }

    public double getThisX() {
        return x;
    }

    public void setThisX(double thisX) {
        this.x = thisX;
    }

    public double getThisY() {
        return y;
    }

    public void setThisY(double thisY) {
        this.y = thisY;
    }

    public double getDx() {
        return dx;
    }

    public void setDx(double dx) {
        this.dx = dx;
    }

    public double getDy() {
        return dy;
    }

    public void setDy(double dy) {
        this.dy = dy;
    }

    public double getTargetX() {
        return tX;
    }

    public void setTargetX(double targetX) {
        this.tX = targetX;
    }

    public double getTargetY() {
        return tY;
    }

    public void setTargetY(double targetY) {
        this.tY = targetY;
    }

    public double getOldTargetX() {
        return oTX;
    }

    public void setOldTargetX(double oldTargetX) {
        this.oTX = oldTargetX;
    }

    public double getOldTargetY() {
        return oTY;
    }

    public void setOldTargetY(double oldTargetY) {
        this.oTY = oldTargetY;
    }

    public double getRandX() {
        return rX;
    }

    public void setRandX(double randX) {
        this.rX = randX;
    }

    public double getRandY() {
        return rY;
    }

    public void setRandY(double randY) {
        this.rY = randY;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}
Klasa Swarm
package swarm;

import java.awt.*;
import javax.swing.*;

public class Swarm extends JPanel {

    private static final long serialVersionUID = 6253469964190884324L;
    private int number;

    public Swarm(int number) {
        this.number = number;
        setPreferredSize(new Dimension(Util.FRAME_SIZE, Util.FRAME_SIZE));
        setLayout(null);
        setBounds(0, 0, Util.FRAME_SIZE, Util.FRAME_SIZE);
        for (int i = 0; i < number; i++) {
            Insect insect = new Insect(Color.BLACK);
            add(insect);
            Thread t = new Thread(insect);
            t.start();
        }
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
}
Klasa Util
package swarm;

public class Util {

    private Util() {
    }

    public static final int FRAME_SIZE = 800;

    public static int randomInRange(int min, int max) {
        int random = -1;
        if (min > max) {
            System.out.println("pierwsza liczba musi byc mniejsza od drugiej");
        } else {
            random = (int) (Math.floor(Math.random() * (max - min + 1)) + min);
        }
        return random;
    }

    public static double randomInRange(double min, double max) {
        double rR = -1;
        if (min > max) {
            System.out.println("pierwsza liczba musi byc mniejsza od drugiej");
        } else {
            rR = Math.floor(Math.random() * (max - min + 1)) + min;
        }
        return rR;
    }
}
Klasa Main
package swarm;

import java.awt.*;
import javax.swing.*;

public class Main extends JFrame {

    private static final long serialVersionUID = -4401137932946724934L;

    public Main() {
        Swarm swarm = new Swarm(25);
        setLayout(null);
        setPreferredSize(new Dimension(Util.FRAME_SIZE, Util.FRAME_SIZE));
        setBounds((Toolkit.getDefaultToolkit().getScreenSize().width / 2)
                - (Util.FRAME_SIZE / 2), (Toolkit.getDefaultToolkit()
                .getScreenSize().height / 2)
                - (Util.FRAME_SIZE / 2), Util.FRAME_SIZE, Util.FRAME_SIZE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Swarm");
        setResizable(false);
        add(swarm);
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Main());
    }
}

Wynik