import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JumpingJackTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BodyPart root = buildBody();
JumpingJackPanel panel = new JumpingJackPanel(root);
createMovement(panel, root);
f.getContentPane().add(panel);
f.setSize(800,800);
f.setVisible(true);
}
});
}
private static BufferedImage createImage(int w, int h, Color color)
{
BufferedImage image = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
g.setColor(color);
g.fillRect(0,0,w,h);
g.dispose();
return image;
}
private static BodyPart buildBody()
{
BodyPart torso = new BodyPart(400,400, 25,10, createImage(50,100, Color.RED));
BodyPart leftUpperLeg = new BodyPart(10,90, 10,10, createImage(20,100, Color.GREEN));
torso.addChild(leftUpperLeg);
BodyPart rightUpperLeg = new BodyPart(40,90, 10,10, createImage(20,100, Color.GREEN));
torso.addChild(rightUpperLeg);
BodyPart leftLowerLeg = new BodyPart(10,90, 10,10, createImage(20,100, Color.YELLOW));
leftUpperLeg.addChild(leftLowerLeg);
BodyPart rightLowerLeg = new BodyPart(10,90, 10,10, createImage(20,100, Color.YELLOW));
rightUpperLeg.addChild(rightLowerLeg);
return torso;
}
static void createMovement(final JComponent component, final BodyPart root)
{
Thread t = new Thread(new Runnable(){
@Override
public void run()
{
while (true)
{
increaseRotation(root,3);
component.repaint();
try
{
Thread.sleep(20);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
private void increaseRotation(BodyPart bodyPart, int counter)
{
double rotationDeg = bodyPart.getRotation();
rotationDeg += counter;
bodyPart.setRotation(rotationDeg);
for (BodyPart child : bodyPart.getChildren())
{
increaseRotation(child, counter+3);
}
}
});
t.start();
}
}
class JumpingJackPanel extends JPanel
{
private BodyPart root;
public JumpingJackPanel(BodyPart root)
{
this.root = root;
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
root.paint(g);
}
}
class BodyPart
{
// The image to be painted
private BufferedImage image;
// The position of this body part relative to its parent
private Point2D anchor;
// The position of the anchor point in the local coordinate
// system (i.e. the point that the image is rotated about)
private Point2D localAnchor;
// The body parts attached to this one
private List<BodyPart> children;
// The current rotation angle of this body part
private double rotationAngleDeg;
public BodyPart(int anchorX, int anchorY, int localAnchorX, int localAnchorY, BufferedImage image)
{
this.anchor = new Point2D.Float(anchorX, anchorY);
this.localAnchor = new Point2D.Float(localAnchorX, localAnchorY);
this.image = image;
this.children = new ArrayList<BodyPart>();
}
public void addChild(BodyPart child)
{
this.children.add(child);
}
public List<BodyPart> getChildren()
{
return Collections.unmodifiableList(children);
}
public void setRotation(double angleDeg)
{
this.rotationAngleDeg = angleDeg;
}
public double getRotation()
{
return rotationAngleDeg;
}
public void paint(Graphics2D g)
{
AffineTransform oldAT = g.getTransform();
g.translate(anchor.getX(), anchor.getY());
g.translate(-localAnchor.getX(), -localAnchor.getY());
g.transform(AffineTransform.getRotateInstance(
Math.toRadians(rotationAngleDeg),
localAnchor.getX(),
localAnchor.getY()));
g.drawImage(image, 0, 0, null);
g.setColor(Color.BLACK);
g.fillOval((int)localAnchor.getX()-2, (int)localAnchor.getY()-2, 4, 4);
for (BodyPart child : children)
{
child.paint(g);
}
g.setTransform(oldAT);
}
}