// 振り子運動をするボール // <applet code="pendulum.class" width="220" height="510"></applet> import java.applet.* ; import java.awt.* ; import java.awt.event.* ; public class pendulum extends Applet implements Runnable, ActionListener { // 共通変数を定義 Thread th = null ; // スレッド Button bt_start_stop = new Button("開始") ; // 開始/停止ボタン TextField tf1 = new TextField(15), tf2 = new TextField(15) ; double a, v ; // 現在の角度,角速度 boolean isRunning = false ; // 動作中かどうかを示すフラグ Image backIMG = null ; // 裏画面 Graphics backG = null ; Image graphIMG = null ; // グラフ描画 Graphics graphG = null ; int gx=0, gy=0 ; final private int szApp = 200 ; final private int szImg = szApp*8/10 ; final private int szRad = szApp*3/10 ; // 振り始めの角度 final private double a0 = Math.PI/3.0 ; // 振り始めの速度 final private double v0 = 0.0 ; final private double h = 0.01 ; final private int offsL = szApp/10 ; // GUI 部品の配置と初期値の設定 public void init() { add(tf1) ; add(new Label("rad.")) ; add(tf2) ; add(new Label("rad./sec.")) ; add(bt_start_stop) ; tf1.setEditable(false) ; tf2.setEditable(false) ; bt_start_stop.addActionListener( this ) ; } private void nextPos() { double y1, y2, df1, df2 ; y1 = h*v ; y2 = h*(-980.0/(double)szRad*Math.sin(a)) ; df1 = h*(v+y2*0.5) ; df2 = h*(-980.0/(double)szRad*Math.sin(a+y1*0.5)) ; a += df1 ; v += df2 ; } // 中心からの角度 t によるボールの描画 private void paintBack() { if( graphG==null || backG==null ) return ; int x, y ; x = (int)((double)szRad*Math.sin(a)) ; y = (int)((double)szRad*Math.cos(a)) ; gx = (int)(a*50.0)+100 ; graphG.drawOval( gx, gy, 1, 1 ) ; if( gy == 190 ) { graphG.copyArea(0,100,200,100,0,-100) ; graphG.setColor(Color.white) ; graphG.fillRect(0,100,200,100) ; graphG.setColor(Color.black) ; graphG.drawLine(100,100,100,200) ; gy = 90 ; graphG.setColor(Color.green) ; graphG.drawOval( gx, gy, 1, 1 ) ; } gy++ ; // 裏画面を白で塗りつぶし backG.setColor(Color.white) ; backG.fillRect(0,0,szImg,szImg) ; backG.setColor(Color.black) ; backG.drawLine(szImg/2,szImg/2,szImg/2+x,szImg/2+y) ; // 画面内に収めるため,平行移動させてボールを描画 backG.setColor(Color.blue) ; backG.fillOval(szImg/2+x-5,szImg/2+y-5, 11, 11) ; tf1.setText(Double.toString(v)) ; tf1.repaint() ; tf2.setText(Double.toString(a)) ; tf2.repaint() ; } public void start() { backIMG = createImage(szImg,szImg) ; backG = backIMG.getGraphics() ; a = a0 ; v = v0 ; graphIMG = createImage(200,200) ; // グラフを初期化 graphG = graphIMG.getGraphics() ; graphG.setColor(Color.white) ; graphG.fillRect(0,0,200,200) ; gx = 0 ; graphG.setColor(Color.black) ; graphG.drawLine(100,0,100,200) ; graphG.setColor(Color.green) ; paintBack() ; th = new Thread(this) ; th.start() ; } public void run() { // アニメーション全体のコントロール while( th!=null ) { if( isRunning ) { nextPos() ; // 位置・速度を更新 paintBack() ; // 裏画面にボールを描く repaint() ; } try { th.sleep(10) ; // 0.01秒休止 } catch( InterruptedException e ) { } } } public void actionPerformed( ActionEvent ev ) { if( ev.getSource() == bt_start_stop ) { isRunning = !isRunning ; if( !isRunning ) { // 停止中であれば bt_start_stop.setLabel("開始") ; bt_start_stop.repaint() ; } else { bt_start_stop.setLabel("停止") ; bt_start_stop.repaint() ; } } } public void update(Graphics g) { paint(g) ; } public void paint(Graphics g) { if( backIMG != null && graphIMG != null ) { // 裏画面に描かれた絵を表示画面に転送 g.drawImage(backIMG,10+offsL,100,this) ; g.drawImage(graphIMG,10,szApp+100,this) ; } } }