ランダム関数を使った模様

ここで学ぶこと

コンピュータは正確な図形を描くという印象がありますが、ランダム関数を使って描くたびに違う絵、意外性のある絵を描かせることができます。

Math.random() や for の使い方。メソッドの作り方の復習もします。

色をランダムに変える

最初は色だけにして、あとで円の大きさや、描画位置もランダムに変えていくことを考えます。

プログラム名 PaintRandom.java

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

public class PaintRandom extends JFrame{
    public PaintRandom() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(400,300);
        setTitle("ランダム関数を使った模様");
        MyPanel mypnl = new MyPanel();
        mypnl.setSize(400,300);
        mypnl.setBackground(Color.white);

        setLayout(new BorderLayout());
        add(mypnl, BorderLayout.CENTER);

        setVisible(true);
    }
    public static void main(String[] args){
        PaintRandom myframe = new PaintRandom();
    }


    public class MyPanel extends JPanel{
      int w=40;     //楕円の幅
      int h=40;     //楕円の高さ
      Color c = new Color(0,0,0);  //楕円の色
      int dc = 16;  //色の変化の大きさ
      int dx = 50;  //横位置の変化の大きさ
      public void paintComponent(Graphics myg){
         super.paintComponent(myg);
         for(int x=0; 400>x ; x=x+dx){
            for(int y=0; 300>y; y=y+4){
               nextColor();
               myg.setColor(c);
               myg.fillOval(x-w/2,y-h/2,w,h);
            }
         }
       }
       public void nextColor(){
          int r=c.getRed();
          int g=c.getGreen();
          int b=c.getBlue();
          g = (int)(g + dc*Math.random());
          if (g > 255){
             g = 0;
          }
          c = new Color(r,g,b);
       }
    }
}

実行すると次のように円をたくさん表示します。場所はforによって一定の間隔でずれますが、色はだんだん明るい青になりますがその速さはランダム関数でわざとずらしています。

ランダム色塗り

フィールド

    int w=40;     //楕円の幅
    int h=40;     //楕円の高さ
    Color c = new Color(0,0,0);  //楕円の色
    int dc = 16;  //色の変化の大きさ
    int dx = 50;  //横位置の変化の大きさ

Color c に注目してください。java では色がクラスとして指定できます。ここでは、RGBの3原色の成分で表していますが、透明度を持たせることもできます。

「色の変化の大きさ」: RGBの成分は各色 0 から 255 までの 256 段階ありますが、このプログラムでは dc の値を加えていって、だんだんと色を変化させ、グラデーションを作っています。

「横位置の変化の大きさ」: このプログラムでは縦に円を少しずつずらしながら描いて柱のようにしたものを、さらに横位置を変えて繰り返して描きます。その横位置の変化の大きさです。

nextColorメソッド

色を少しずつ変化させるのは作業手順が多いのでメソッドにして独立させました。Color のインスタンス c を dc を使って変化させています。

    public void nextColor(){
        int r=c.getRed();
        int g=c.getGreen();
        int b=c.getBlue();
        g = (int)(g + dc * Math.random());
        if (g > 255){
            g = 0;
        }
        c = new Color(r,g,b);
    }

c.getRed() は Color クラスの c の赤の成分を取り出す Color のメソッドです。

ここでは色の緑成分だけを dc ずつ明るくするようにしていますが、いつもおなじ dc ずつでなくするために、Math.random() を掛けています。Math.random() は 0以上、1未満の double の値です。平均すると 16/2 ずつ明るくなるはずです。

(int) は計算の結果が double になっているので、これを int に代入する時に int の値に変換するものです。キャストといいます。他にもやり方があるのですが、この方が簡単です。

if の所では、緑の成分 g が255以上にならないように、255を越えたら 0 にもどすようにしています。

new Color(r,g,b) は前にもでていますが、r,g,b の成分の色を作っています。

paintComponentメソッド

      public void paintComponent(Graphics myg){
         super.paintComponent(myg);
         for(int x=0; 400>x ; x=x+dx){
            for(int y=0; 300>y; y=y+4){
               nextColor();
               myg.setColor(c);
               myg.fillOval(x-w/2,y-h/2,w,h);
            }
         }
       }

2つの for を使っています。for(int y=0; y<300; y=y+4) で縦に4ずつずらしながら円を描いています。

円を描くにあたり、nextColor() で色を変化させ、変化した色 c を myg.setColor(c); で描画色に設定し、 myg.fillOval(x-w/2,y-h/2,w,h); で円を描きます。

myg.fillOval(横位置,縦位置,幅,高さ) です。-w/2 などはここではいらないのですが、後で幅を変化させた時に、円の中心が縦に揃うようにしています。

w, h を同じにしているので、楕円が円になります。

横位置もランダムに変化させる

プログラム名 PaintRandom.java を書き換える

      public void paintComponent(Graphics myg){
         super.paintComponent(myg);
         for(int x=0; 400>x; x=x+dx){
             int xx = (int)(x + dx*Math.random());
             for(int y=0; 300>y; y=y+4){
                 nextColor();
                 myg.setColor(c);
                 myg.fillOval(xx-w/2,y-h/2,w,h);
               }
          }
       }

作業変数の x はさわると危険なので、別の変数 xx を定義して、現在の x より、dx*Math.random() だけ 右よりの位置にします。x の代わりに xx を x の位置とします。

Math.random()は0以上1未満のdoubleの値を返すメソッドです。fillOvalはintで指定するので(int)でdoubleをintに変換して代入しています。

dx を足してからさらに dx*Math.random() を足しているので、全体として、足しすぎなのですが、問題ありません。

ランダム色塗り+位置

dxを小さくすると重なりが多くなって壁の様になります。(たとえばdx=50をdx=25にするなど)

ランダム色塗り+位置

円の大きさもランダムに変化させる

円の大きさもランダムに変えると次のようなものになります。

ランダム色塗り+位置

この変更は、

myg.fillOval(xx-w/2,y-h/2,w,h);

を以下に変更します。(もともとw=hなので円になる。これらを両方共wwとすることで円のまま半径を変化させる)

int ww = (int)(w/2 + w*Math.random());
myg.fillOval(xx-ww/2,y-ww/2,ww,ww);

Math.random() は 0以上、1未満の double の値なので w*Math.random() は 0以上、w未満(ここでは40未満)の値です。それで平均がw/2になってしまいます。このままでもいいですが、w/2を加えれば元の40の大きさを平均にして大きかったり小さかったりとしたかったのです。

さらに円の横位置もランダムにすると

円の横位置を左から右に移していくのではなく、ランダムな位置に置くとまた違った印象になります。

ランダム色塗り+位置

この変更は、

for(int x=0; 400>x; x=x+dx){
   int xx = (int)(x + dx*Math.random());

の部分をたとえば次のようにします。

for(int i=0; 100>i; i++){
   int xx = (int)(400*Math.random());

400*Math.random() は 0以上、400未満の値です。画面の一番左が0、右が400のどこかに描かれます。(int x=0; 400>x; x=x+dx)では 400/25=16 ですので円柱が16本です。ランダムにすると偏りが出て描かれない部分も出てしまいます。そこで100本描けばだいたい全体がうまるだろうとわかりやすく i を使って100回としています。

上記の図ではint ww = (int)(w/2 + w*Math.random()); を int ww = (int)(w/4 + w*Math.random()); に変えて円をより小さい円になるように調整しました。このほうが見栄えがします。

課題

1

上記プログラムをつくりなさい。

ファイル名 PaintRandom.java

2

ファイル名 PaintRandom2.java

独自の変わった模様を描けるプログラムをつくりなさい。

もくじ

聖愛高等学校
http://www.seiai.ed.jp/
Last Modified