プログラミング雑記

プログラミングが趣味のだらだら学生。自作したプログラムの紹介やいまハマってることなんかを適当に書いていったりいかなったり

初心者でも始められるプログラミング生活:第1回目~変数とは?アニメーションで変数を理解する!~

はじめに

※前回記事はこちら

niisi.hatenablog.jp

 

今回はプログラムの中でも基本中の基本「変数」について扱っていきます。

難しいものではないですが、とても大事なところなのでしっかりおさえていきましょう!

 

 

実行の流れ

変数の内容に入っていく前にとても大事なプログラムの実行順序について。

 

ほとんどのプログラミング言語では上から下へ順番に命令が実行されます。

命令①

命令②

命令③

と並んでいたら、①→②→③と順番に実行されます。もちろんProcessingでも同じです。

 

また、Processingではsetup()とdraw()という重要なものがあります。setup()の中に書いた命令はプログラムの実行開始時に一度だけ実行され、draw()の中に書いた命令は1秒間に60回実行されます。つまり、下のようなプログラムがあった場合、 

void setup(){
  //命令1
//命令2
//命令3 }
void draw(){
//命令4
//命令5
}

①→②→③→④→⑤→④→⑤→④→⑤→……

と命令1~3まで実行し終わったあと命令4,5をひたすら実行し続けます。

プログラムの実行の流れを理解することはとても大切なので、一番基本中の基本、上から下へと実行していくということをおさえておきましょう。

 

変数

変数とは一言でいえばプログラムの中で使われるデータや値を保存しておく入れ物のようなものです。データを入れ物に入れておけばプログラム中いつでも使うことができます。

変数の宣言と代入

変数を使うためにはまず「宣言」を行い、それから値を「代入」していきます。

 

次のプログラムを見てください。

 

void setup(){
  int x = 0;
  println(x);
}

 

int x = 0;にあたる部分が変数の宣言と代入を行っている部分です。ここで、intというのはinteger(整数)の頭をとったものですがxという入れ物の中には整数の値を入れていいよということを表しています。そしてx = 0;でxの入れ物の中に0を代入しています。

次にprintln(x);についてみていきます。println()命令はかっこの中にある値をコンソールと呼ばれる場所に表示させる命令です。コンソールというのはテキストエディタの下にある黒い部分です。いまprintln()のかっこの中にxがあるのでxの値を表示させます。xの中には0が入っているためコンソールには0と表示されるはずです。

 

f:id:kirari0831:20170528230858p:plain

 

ちなみにintと宣言しているのでxの右辺には整数の値しかとってこれません

int x = 1.5;とはできないので要注意!小数の値を取りたい場合についてはもう少しあとで。

 

void setup(){
  int a = 10+20;
  int b = 10-20;
  int c = 20*10;
  int d = 20/10;
  println(a);
  println(b);
  println(c);
  println(d);

  int dd = 30/20;
  println(dd);
}

 

四則演算もできます。上から順に足し算、引き算、掛け算、割り算になっています。xやa,bといったものは変数に名付けられた名前として「変数名」と呼ばれます。変数名は数字からではなくアルファベットから始めてください。特に変数名の先頭には小文字のアルファベットを用いるようにしましょう。大文字を使ってもプログラムの実行に問題はないのですが、小文字で始めるのが一般的です。

ここで問題はint dd = 30/20;です。普通は30÷20=1.5と思ってしまうところですが、プログラムの実行結果を見てみましょう。

 

f:id:kirari0831:20170528232646p:plain

 

なんと30÷20の答えが1となっています。なぜでしょうか?

Processingでは整数同士の除算では整数の商を返すようになっています。ここでは30÷20=1あまり10なので1を返したわけです。同様に80/30なら2を返し、17/5なら3を返します。

 

では30÷20をして1.5の値を返してほしいときはどうすればよいのでしょうか。

 

ここで用いるのがdoubleです。

 

void setup(){
  double a = 1.5;
  double b = 20.3;
  println(b/a);
}

 

さきほどintと宣言してた場所をdoubleにかえると変数の中に小数値を代入することができます。double値を含んだ計算になると割り算でも小数のあたいを返してくれるようになります。

 

void setup(){
  double a = 30;
  double b = 20;
  println(a/b);
}

 

int x = 1.5とはできませんでしたが、double x = 10;のように整数値も代入することはできます。ただしxの中には10.0が入るので注意。上のプログラムでは30.0/20.0の計算が起こるので1.5が表示されます。

 

変数の更新

一度宣言した変数には何度も値を更新することができます。

 

void setup(){
  int a = 30;
  a = 10;
  println(a);
}

 

上のプログラムでは30ではなく、10が表示されます。変数の更新を行いたいときは、変数名=新しい値;で行います。すでに2行目で型の宣言はしてあるのでaが整数値をとることはわかっているため、int a = 10;とはせずにa=10;だけで構いません一度宣言した変数には型をわざわざつけなくていいことを覚えておきましょう。

 

それでは次のプログラムでは何が表示されるでしょうか?

 

void setup(){
  int x = 0;
  x = x + 1;
  println(x);
}

 

x = x +1;と言われると一瞬なんだこれは、と思うかもしれませんが、プログラムでは右辺で計算した値を左辺に代入するんでした。ここでは右辺のx + 1では0 + 1が計算され左辺のxには1が代入されます。よって最後のprintln(x);で1を表示します。

 

x = x + 1;のような変数の更新はよく使うのでどういったことをしているのかなんとなく頭の中に入れておいてください。

 

変数の宣言場所と「生きられる」範囲

一度宣言した変数はいつでもどこでも使えるわけではないのです。

 

void setup(){
  int x = 10;
}
void draw(){
  println(x);
}

 

上のプログラムでは実行する前から何やら赤線を引かれて怒られていると思います。

println(x);のxに赤線を引かれて「変数"x"は存在しません」と言われるはずです。setup()の中でxを宣言したのになぜなのでしょう?

 

f:id:kirari0831:20170529002618p:plain

 

実は、{ }の中で宣言した変数はその中でしか生きられないのです。上のプログラムではsetup() { } の中で変数xを宣言したためsetup()を抜けた先のdraw()の中では使えなかったのです。

 

ではどうやって上のプログラムのエラーを回避するか。一つの解決策はこうです。

 

void setup(){
  
}
void draw(){
  int x = 10;
  println(x);
}

 

これなら、draw() { }の中で 変数が宣言されているため、同じdraw() { } 内で使用されているprintln(x)も使えます。

 

しかし、setup()の中でもdraw()の中でも同じ変数を使いたいような場合はどうすればよいのでしょうか。次にあげるプログラムが二つ目の解決策です。

 

int x;
void setup(){
  x = 10;
}
void draw(){
  println(x);
}

 

変数の宣言はsetup()やdraw()の外側でも行えます。また外側で宣言された変数はプログラム中のどこからでも使うことができます。外側で宣言することでsetup()内でもdraw()内でも変数xが使えるため上のプログラムではエラーになりません。

どこでも使えて便利ではありますが、あまり多用はしないようにしましょう。複雑なプログラムや長いプログラムになったときに分かりづらいプログラムになってしまいます。いろんな場所で使われるような変数でなければ外側では宣言しないようにしましょう。

 

変数を使ったプログラム

コンソールを使って確認するだけじゃなにも面白くないですよね。

「変数」を使ったProcessingらしいプログラムを書いて変数が一体どういったものなのか確認していきましょう。

 

int x;
void setup(){
  size(800,600);
  x = 0;
}
void draw(){
  background(255);
  rect(x, 50, 100, 100);
}

 

rect(x, 50, 100, 100);は四角形を描画する命令です。数字を4つ与えますが左から順番に【(四角形左上の)x座標、y座標、幅、高さ】です。

ここではrect(x, 50, 100, 100)なので座標(x, 50)を開始地点にして幅が100、高さが100になるような四角形を描画します。もっと言えば、いまxの値は0になっているので(0, 50)を開始地点に四角形を描画します。

f:id:kirari0831:20170528164452p:plain

 

次にこの四角形を動かしてみましょう。1フレームごとにちょっとずつ描写位置をずらしていけばパラパラ漫画の要領で動いているように見えるため、xの値を更新していきます。

 

int x;
void setup(){
  size(800,600);
  x = 0;
}
void draw(){
  background(255);
x = x + 1; rect(x, 50, 100, 100); }

 

 

f:id:kirari0831:20170529004029g:plain

(上の動画ではx = x + 5;としています)

 

上のプログラムで四角形を右に動かすために追加したのはx = x + 1;です。最初にxには0が入っているわけですが、一度目にdraw()が実行されるときは、右辺が0+1となり新しいxの値が1に、二度目に実行されるときは右辺が1+1となって新しいxの値が2に、三度目に実行されるときは2+1となって新しいxの値が3に……とどんどん増えていくわけですね。こうすることにより、四角形を描画する位置が少しずつxの正方向、つまり右にずれていったわけです。

 

ここで大事なポイントが二つあります

一つ目は変数として大事なこと。上のプログラムではxを利用しているのが実質draw()の中だけ(setup()で行っているのは代入)なので次のようなプログラムを書きたくなります。

 

//四角形が動かないバージョン
void setup(){
  size(800,600);
}
void draw(){
  int x = 0;
  background(255);
  x = x + 1;
  rect(x, 50, 100, 100);
}

 

一か所で使用される変数はなるべく外側には書かないのが鉄則でした。上のプログラムはそれを守っているプログラムですが、四角形は動きません。

draw()は一秒間に何度も呼ばれるものです。だからこそ、x = x + 1;と書いていれば少しずつxの値が増えていき、四角形が右に移動していったわけです。しかし同じ場所にint x = 0;といった宣言、代入文を書いてしまったらどうでしょうかdraw()が実行されるたびにxは0に戻ってしまいます。そのためいくら値の更新を行っても毎回初期化されてしまうために動かなかったわけです。このように変数はどこで初期化するべきなの注意しましょう

 

二つ目はProcessingのプログラムとして大事なこと、background()命令についてです。background()はかっこ内に与えた色で背景をすべて塗りつぶすというものです。与える数が0だと真っ黒、255だと真っ白になり、その間だと灰色になります。今回はbackground(255)としているため背景を真っ白にと指定しているのですが、最初に実行されるsetup()の中だけではダメなのでしょうか。

 

//軌跡が残ってしまうバージョン
int x;
void setup(){
  size(800,600);
  background(255);
}
void draw(){
  x = x + 1;
  rect(x, 50, 100, 100);
}

 

上のプログラムを実行すると四角形が移動するには移動しますが、なぜか通り道が黒くなってしまいます。background()の働きは背景を塗りつぶすことですが、これは前のフレームで書いたものをすべてまっさらにするという役割も担っています。そのため描画部を大きく担うdraw()の先頭でbackground()を書かないと前に書いた四角形の跡が残ってしまうわけです。x = x + 1;の1の部分をほかの数字に置き換えてみると、前に書いた四角形の跡が残っていることがよくわかります(下の動画ではx = x + 5;で実行)。

 

f:id:kirari0831:20170529005103g:plain

演習問題

今回扱った変数を用いたプログラムを自分で作ってみましょう!

問題1-1

x方向とy方向両方に動く四角形を作る。右方向に動く四角形をヒントに作ってみましょう!

 

問題1-2-1

以下のような「車」を作る。

 

f:id:kirari0831:20170529005530p:plain

 

丸はellipse(x, y, w, h);で作ることができます。ellipse(100,100,200,200)とすると、座標(100,100)を中心に幅200高さ200の円を作ります。右二つの数字を同じにすれば正円に、異なる値にすれば楕円になります。

色を付けたい場合はfill(red, green, blue);で作ることができます。四角形や円を描くときの中身の色はfillで指定された色になります。red, green, blueともに0~255までの値をとることができて255に近いほどその色が強くなります。例:fill(255,0,0)→赤色、fill(0,255,0)→緑色、fill(0,0,255)→青色。fill(255,0,255)→紫(赤+青)、fill(255,255,0)→黄色(赤+緑)、fill(0,255,255)→水色(青+緑)

ちなみに、上の車の色はfill(52,152,219);で指定しています。

 

//fill()の使用例
void setup(){
  size(800,600);
}
void draw(){
  background(255);
  noStroke();   //この命令を使うと四角や円の枠線を消せる
  fill(255,0,0);  //直後の四角形の色を赤色に
  rect(50, 50, 100, 100);
  fill(0,0,255);  //直後の円の色を青色に
  ellipse(300,50,75,75);
  ellipse(400,150,75,75);
}

 

 

ヒント1:車体は二つの四角形からできている。

 

ヒント2:タイヤは黒色の大きな円の上に白色の小さな円を描くことでできる。

 

問題1-2-2

問題1-2-1で作った車を右方向に動かせるようにプログラムを変更する。

 

 

ヒント:車のx座標にあたる場所を変数を用いて書き換える

 

問題1-3

色が徐々に変わりかつ徐々に大きくなる円を作る。

 

f:id:kirari0831:20170529011152g:plain

 

ヒント1:変わっているものはなにか考えてみる。

 

ヒント2:変わっているものを変数に置き換えて、更新していけばよい。