プロ2 > 資料 > 第9章

第9回:コンポジションとクラス構造

目標

9.1 コンポジションで絵を動かす

import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.util.*; public class Sample91 extends JPanel { ArrayList<Figure> figs = new ArrayList<Figure>(); ArrayList<Animation> anim = new ArrayList<Animation>(); public Sample91() { Color col1 = Color.BLACK, col2 = Color.RED; Circle c1 = new Circle(col1, 100, 200, 20); figs.add(c1); //Circleクラスのc1をLinearMoveクラスのコンストラクタの引数にしている. anim.add(new LinearMove(c1, 3, 100, 200, 5, 200, 60)); //Circleクラスのc1をColorTransクラスのコンストラクタの引数にしている. anim.add(new ColorTrans(c1, 4, col1, 5, col2)); setOpaque(false); final long tm0 = System.currentTimeMillis(); new javax.swing.Timer(30, new ActionListener() { public void actionPerformed(ActionEvent evt) { float tm = 0.001f * (System.currentTimeMillis() - tm0); //一定時間ごとにArrayList Animationの要素を動作させる for (Animation a : anim) { a.setTime(tm); } repaint(); } }).start(); } public void paintComponent(Graphics g) { for (Figure f : figs) { f.draw(g); } } public static void main(String[] args) { JFrame app = new JFrame(); app.add(new Sample91()); app.setSize(400, 240); app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); app.setVisible(true); } interface Figure { public void draw(Graphics g); public void moveTo(float x, float y); public void setColor(Color c); } interface Animation { public void setTime(float dt); } static abstract class SimpleFigure implements Figure { Color col; float xpos, ypos; public SimpleFigure(Color c, float x, float y) { col = c; xpos = x; ypos = y; } public void moveTo(float x, float y) { xpos = x; ypos = y; } public void setColor(Color c) { col = c; } public void draw(Graphics g) { g.setColor(col); } } static class Circle extends SimpleFigure { float rad; public Circle(Color c, float x, float y, float r) { super(c, x, y); rad = r; } public void draw(Graphics g) { int x = (int) (xpos - rad), y = (int) (ypos - rad); super.draw(g); g.fillOval(x, y, (int) rad * 2, (int) rad * 2); } } static class LinearMove implements Animation { Figure fig; float time1, xpos1, ypos1, time2, xpos2, ypos2; //Figure figを時刻time1に(xpos1,ypos1)の位置から,時刻time2に(xpos2,ypos2)の位置まで移動させる. public LinearMove(Figure f, float t1, float x1, float y1, float t2, float x2, float y2) { time1 = t1; xpos1 = x1; ypos1 = y1; time2 = t2; xpos2 = x2; ypos2 = y2; fig = f; } public void setTime(float t) { //時刻tがtime1とtime2の間でなければ何もしない. if (t < time1 || time2 < t) { return; } //経過時間に応じて図形の位置を変化させる. float p = (time2 - t) / (time2 - time1), q = 1.0f - p; fig.moveTo(p * xpos1 + q * xpos2, p * ypos1 + q * ypos2); } } static class ColorTrans implements Animation { Figure fig; float time1, time2; int r1, g1, b1, a1, r2, g2, b2, a2; //Figure figを時刻time1に(r1,g1,b1)の色から,時刻time2に(r2,g2,b2)の色まで変化させる. public ColorTrans(Figure f, float t1, Color c1, float t2, Color c2) { fig = f; time1 = t1; time2 = t2; r1 = c1.getRed();//c1の赤色成分を取り出す. g1 = c1.getGreen();//c1の緑色成分を取り出す. b1 = c1.getBlue();//c1の青色成分を取り出す. a1 = c1.getAlpha();//c1の透明度を取り出す. r2 = c2.getRed(); g2 = c2.getGreen(); b2 = c2.getBlue(); a2 = c2.getAlpha(); } public void setTime(float t) { //時刻tがtime1とtime2の間でなければ何もしない. if (t < time1 || time2 < t) { return; } //経過時間に応じて図形の色を変化させる. float p = (time2 - t) / (time2 - time1), q = 1.0f - p; fig.setColor(new Color((int) (p * r1 + q * r2), (int) (p * g1 + q * g2), (int) (p * b1 + q * b2), (int) (p * a1 + q * a2))); } } }

9.2 状態遷移を実現する

import java.awt.*; import java.awt.event.*; import java.awt.image.*; import java.io.*; import java.util.*; import javax.imageio.*; import javax.swing.*; public class Sample92 extends JPanel { Scene cur = new Scene1();// 初期場面をScene1にする. long tm0 = System.currentTimeMillis(); public Sample92() { setOpaque(false); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { cur.press(evt.getX(), evt.getY()); } }); new javax.swing.Timer(30, new ActionListener() { public void actionPerformed(ActionEvent evt) { float tm = 0.001f * (System.currentTimeMillis() - tm0); cur.setTime(tm); repaint(); // 場面が終了すれば次の場面にする if (cur.isEnded()) { cur = cur.getNext(); tm0 = System.currentTimeMillis(); } } }).start(); } public void paintComponent(Graphics g) { cur.draw(g); } public static void main(String[] args) { JFrame app = new JFrame(); app.add(new Sample92()); app.setSize(400, 240); app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); app.setVisible(true); } // 場面の定義 static class Scene { ArrayList<Figure> figs = new ArrayList<Figure>(); ArrayList<Animation> anim = new ArrayList<Animation>(); boolean ended = false;// 終了のフラグ Scene next = null;// 次の場面を示す変数 public void draw(Graphics g) { for (Figure f : figs) { f.draw(g); } } public void setTime(float t) { for (Animation a : anim) { a.setTime(t); } } public void press(int x, int y) { } public boolean isEnded() { return ended; } public Scene getNext() { return next; } } // Scene1の定義 static class Scene1 extends Scene { Rect r1 = new Rect(Color.YELLOW, 100, 100, 100, 100); Rect r2 = new Rect(Color.YELLOW, 250, 100, 100, 100); public Scene1() { Picture p1 = new Picture("kuno1.png", 0, 0); Picture p2 = new Picture("sun1.png", 0, 0); figs.add(r1); figs.add(r2); figs.add(p1); figs.add(p2); anim.add(new ZigzagMove(p1, 1f, 95, 100, 105, 100)); anim.add(new ZigzagMove(p2, 1f, 250, 95, 250, 105)); figs.add(new Text(20, 25, "お好きな方をクリック", new Font("serif", Font.BOLD, 18))); } public void press(int x, int y) { // r1をクリックすれば終了して,Scene2へ if (r1.hit(x, y)) { next = new Scene2(); ended = true; // r2をクリックすれば終了して,Scene4へ } else if (r2.hit(x, y)) { next = new Scene4(); ended = true; } } } // Scene2の定義 static class Scene2 extends Scene { public Scene2() { next = new Scene3(); figs.add(new Text(20, 90, "動画作品、見て下さい。", new Font("serif", Font.BOLD, 18))); } public void press(int x, int y) { ended = true; } public void setTime(float t) { ended |= (t > 5);// endがtrueであるか,30*5ミリ秒経過すると終了 } } // Scene3の定義 static class Scene3 extends Scene { public Scene3() { next = new Scene1();// 次の場面はScene1 Color s1 = new Color(50, 50, 100), s2 = new Color(220, 220, 250); Rect sky = new Rect(s1, 200, 100, 400, 210); Circle c1 = new Circle(Color.YELLOW, 200, 60, 20); Color pc1 = new Color(180, 110, 60), pc2 = new Color(150, 80, 30); Color pc3 = new Color(160, 100, 40, 0); Triangle p1 = new Triangle(pc1, 260, 110, 180, 180, 290, 180); Triangle p2 = new Triangle(pc2, 260, 110, 290, 180, 350, 180); Rect grnd = new Rect(new Color(100, 40, 40), 200, 220, 400, 80); figs.add(sky); figs.add(c1); figs.add(p1); figs.add(p2); figs.add(grnd); anim.add(new LinearMove(c1, 3, 200, 60, 5, 20, 220)); anim.add(new ColorTrans(c1, 5, Color.YELLOW, 6, Color.RED)); anim.add(new LinearMove(c1, 6, 20, 220, 8, 200, 60)); anim.add(new ColorTrans(sky, 6, s1, 8, s2)); anim.add(new ColorTrans(p1, 10, pc1, 12, pc3)); anim.add(new ColorTrans(p2, 10, pc2, 12, pc3)); } public void setTime(float t) { super.setTime(t); ended |= (t > 14);// 30*14ミリ秒で終了 } } // Scene4の定義 static class Scene4 extends Scene { Font fn = new Font("serif", Font.BOLD, 18); Text t1 = new Text(20, 25, "円をクリックしてください", fn); Text t2 = new Text(20, 55, "0.00", fn); Circle c1 = new Circle(Color.BLUE, 60, 200, 20); boolean ok = false; float curtime = 0f, endtime = 60f; public Scene4() { next = new Scene1(); figs.add(t1); figs.add(t2); figs.add(c1); anim.add(new ZigzagMove(c1, 0.7f, 60, 200, 340, 40)); } public void press(int x, int y) { if (!c1.hit(x, y)) { return; } ok = true; c1.setColor(Color.RED); endtime = curtime + 5; t1.setText((curtime < 3f) ? "Good Job!" : "So-so"); } public void setTime(float t) { super.setTime(t); curtime = t; ended |= (t > endtime); if (!ok) { t2.setText(String.format("%4.2f", t)); } } } interface Figure { public void draw(Graphics g); public void moveTo(float x, float y); public void setColor(Color c); } interface Animation { public void setTime(float dt); } static abstract class SimpleFigure implements Figure { Color col; float xpos, ypos; public SimpleFigure(Color c, float x, float y) { col = c; xpos = x; ypos = y; } public void moveTo(float x, float y) { xpos = x; ypos = y; } public void setColor(Color c) { col = c; } public void draw(Graphics g) { g.setColor(col); } } static class Circle extends SimpleFigure { float rad; public Circle(Color c, float x, float y, float r) { super(c, x, y); rad = r; } public boolean hit(float x, float y) { return (xpos - x) * (xpos - x) + (ypos - y) * (ypos - y) <= rad * rad; } public void draw(Graphics g) { int x = (int) (xpos - rad), y = (int) (ypos - rad); super.draw(g); g.fillOval(x, y, (int) rad * 2, (int) rad * 2); } } static class Rect extends SimpleFigure { float width, height; public Rect(Color c, float x, float y, float w, float h) { super(c, x, y); width = w; height = h; } public boolean hit(float x, float y) { return xpos - width / 2 <= x && x <= xpos + width / 2 && ypos - height / 2 <= y && y <= ypos + height / 2; } public void draw(Graphics g) { int x = (int) (xpos - width / 2), y = (int) (ypos - height / 2); super.draw(g); g.fillRect(x, y, (int) width, (int) height); } } static class Triangle extends SimpleFigure { float dx1, dy1, dx2, dy2; public Triangle(Color c, float x, float y, float x1, float y1, float x2, float y2) { super(c, x, y); dx1 = x1 - x; dy1 = y1 - y; dx2 = x2 - x; dy2 = y2 - y; } public void draw(Graphics g) { int[] xs = { (int) xpos, (int) (xpos + dx1), (int) (xpos + dx2) }; int[] ys = { (int) ypos, (int) (ypos + dy1), (int) (ypos + dy2) }; super.draw(g); g.fillPolygon(xs, ys, 3); } } static class Text extends SimpleFigure { String txt; Font fn; public Text(int x, int y, String t, Font f) { super(Color.BLACK, x, y); txt = t; fn = f; } public void setText(String t) { txt = t; } public void draw(Graphics g) { super.draw(g); g.setFont(fn); g.drawString(txt, (int) xpos, (int) ypos); } } static class Picture extends SimpleFigure { BufferedImage img; int width, height; public Picture(String fname, int x, int y) { super(Color.WHITE, x, y); try { img = ImageIO.read(new File(fname)); } catch (Exception ex) { } xpos = x; ypos = y; width = img.getWidth(); height = img.getHeight(); } public void draw(Graphics g) { int x = (int) xpos - width / 2, y = (int) ypos - height / 2; g.drawImage(img, x, y, null); } } static class LinearMove implements Animation { Figure fig; float time1, xpos1, ypos1, time2, xpos2, ypos2; public LinearMove(Figure f, float t1, float x1, float y1, float t2, float x2, float y2) { time1 = t1; xpos1 = x1; ypos1 = y1; time2 = t2; xpos2 = x2; ypos2 = y2; fig = f; } public void setTime(float t) { if (t < time1 || time2 < t) { return; } float p = (time2 - t) / (time2 - time1), q = 1.0f - p; fig.moveTo(p * xpos1 + q * xpos2, p * ypos1 + q * ypos2); } } static class ColorTrans implements Animation { Figure fig; float time1, time2; int r1, g1, b1, a1, r2, g2, b2, a2; public ColorTrans(Figure f, float t1, Color c1, float t2, Color c2) { fig = f; time1 = t1; time2 = t2; r1 = c1.getRed(); g1 = c1.getGreen(); b1 = c1.getBlue(); a1 = c1.getAlpha(); r2 = c2.getRed(); g2 = c2.getGreen(); b2 = c2.getBlue(); a2 = c2.getAlpha(); } public void setTime(float t) { if (t < time1 || time2 < t) { return; } float p = (time2 - t) / (time2 - time1), q = 1.0f - p; fig.setColor(new Color((int) (p * r1 + q * r2), (int) (p * g1 + q * g2), (int) (p * b1 + q * b2), (int) (p * a1 + q * a2))); } } static class ZigzagMove implements Animation { Figure fig; float time1, xpos1, ypos1, xpos2, ypos2; public ZigzagMove(Figure f, float t1, float x1, float y1, float x2, float y2) { time1 = t1; xpos1 = x1; ypos1 = y1; xpos2 = x2; ypos2 = y2; fig = f; } public void setTime(float t) { float q = (t % time1) / time1, p = 1.0f - q; fig.moveTo(p * xpos1 + q * xpos2, p * ypos1 + q * ypos2); } } }


ykitamura@kwansei.ac.jp