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