プロデルで始める日本語プログラミング言語入門(#8)「キャンバスで図形を描こう」

連載プロデル入門の第8話目になりました。今回は、「キャンバス」で図形を描く方法をご紹介します。

キャンバス部品は、GUI部品の中でも特に図形を描くための部品です。キャンバス部品を使うと、ゲーム画面やグラフといった線や図形によるプログラムを作ることができます。

キャンバスを使ってみよう

早速キャンバス部品を使ってみましょう。新しいウィンドウを作り、左側のツールバーから「キャンバス」を選択してウィンドウに貼り付けます。

// キャンバスのひな形 //
メイン画面を表示する
待機する

メイン画面とは
	ウィンドウを継承する
	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
	終わり
	初期化する手順
		ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります
		この実質大きさを{428,394}に変える
		この内容を「メイン画面」に変える
		初期化開始する
		キャンバス1というキャンバスを作る
			その位置と大きさを{0,0,428,394}に変える
			そのドッキング方向を「全体」に変える
		初期化終了する
		この設計スケール比率を{144,144}に変える
	終わり
終わり

実行するとウィンドウいっぱいに白いキャンバスが表示されます。

キャンバスは、左上が原点{0,0}

キャンバス図形では、ピクセル単位(画面の1ドット)で座標や大きさを指定します。

キャンバスの画面左上を原点{0,0}として、左方向へ進むに従ってX軸の値が大きくなり、下方向へ進むに従ってY軸の値が大きくなります。

図形を描く

キャンバスに図形を描くには、キャンバス図形という図形の部品(オブジェクト)を作ります。作った図形をキャンバスに貼り付けることで画面に図を描きます。キャンバス図形には、直線や円,四角形などがあり、座標や大きさ、色などを指定していきます。設定項目は、図形を貼り付けた後に変えることもできます。

例えばPowerPointのように図形を貼り付けて、大きさや色などの設定項目を変えていくうな感覚でプログラムで指示しながら描きます。

直線

まず直線を描いてみましょう。直線では、始点の座標と終点の座標を指定して描きます。先ほどのひな形の「はじめの手順」を次のように書き加えてみてください。

	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		キャンバス1へ線を描く
			その始点は、{50,50}
			その終点は、{120,120}
			その線色を赤に変える
			その太さを3に変える
	終わり

線の色や太さ、線種を変える

線を作った後に、線の色と太さが設定できます。「線色」設定項目で線の色を、「太さ」で線の太さを、「筆の線種」で線の種類を変えられます。

始点と終点を指定した後に、線色などを設定してみます。

	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		キャンバス1へ線を描く
			その始点は、{50,50}
			その終点は、{120,120}
			その線色を赤に変える
			その筆の線種を「線と二点」に変える
			その太さを3に変える
	終わり

「筆の線種」には、次のものが指定できます。

{標準,点線,破線,線と点,線と二点}

色の指定

プロデルでは、次の方法で色を指定できます。

  • 色の名前(日本語,英語)
  • 16進数表記のRGB番号
  • 色合い, 明るさ, 鮮やかさの割合
その線色は「さくら」
その線色は、RGB({255,255,226})
その線色は、HLS({80,120,240})

詳しくは、色の作り方と定数表で説明しています。

また、RGB手順やHLS手順では「色情報」種類の値を返します。色情報では「アルファ」設定項目で透明度を0~255の範囲で指定できます。塗りつぶしたい背景色を半透明にする場合には、「アルファ」設定項目を指定します。

色A=HLS({180,0.7,0.7})
色Aのアルファは、50

[サンプル] マウスで線を描く

「ペイント」のようにマウスでドラッグした軌跡に線の描くプログラムを作ってみましょう。前話で紹介した他のGUI部品と同様に、キャンバスにもマウスのイベント手順が用意されているので、マウスのボタン操作に応じて図形を描くことができます。

線を描くには

ペイントなどではマウスでフリーハンドの曲線を描けますが、実際には長さが短いたくさんの直線で線を繋ぎ合わせて描いています。

具体的には、マウスのボタンを押した時(ドラッグ開始)の時の座標を始点として、マウスが少しでも動いた時にその座標までの直線を引きます。さらにマウスが動いたら、その前の座標から、その時の座標までの直線を引きます。こうしてマウスのボタンが放されるまで、短い線を描き続けることで、曲線を描けます。

これを整理すると、線を描くために必要なロジックは次の通りです。

  • マウスのボタンを押した時に線を作り始点を決める (ドラッグ開始)
  • 押されたまま、マウスカーソルが動いたときに、その位置を終点にする、さらに新しい線を作るそこを始点にする
  • マウスボタンが離された時に、最後に作った線の終点を決める (ドラッグ終了)

作業している線図形を入れておく

ドラッグ開始した時に、線を引いている最中の終点が決まっていない線図形を「作業線」という名前の変数に入れておきます。

キャンバス1へ線を描いて作業線とする

このように変数には、数値や文字列だけでなく、図形そのものを入れておくこともできます。

メイン画面を表示する
待機する

メイン画面とは
	ウィンドウを継承する
	はじめの手順
		初期化する
	終わり
	初期化する手順
	ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります
		この実質大きさを{428,394}に変える
		この内容を「マウスで直線を描く」に変える
		このドラッグドロップを○に変える
		初期化開始する
		キャンバス1というキャンバスを作る
			その位置と大きさを{0,0,428,394}に変える
			そのドッキング方向を「全体」に変える
		初期化終了する
		この設計スケール比率を{144,144}に変える
終わり

	-作業線
	キャンバス1のマウスのボタンが押された時の手順
		キャンバス1へ線を描いて作業線とする
			その始点は、この時の座標
			その線色を赤に変える
			その太さを3に変える
	終わり

	キャンバス1のマウスカーソルが移動した時の手順
		もし作業線が無なら抜け出す
		作業線の終点は、この時の座標
		キャンバス1へ線を描いて作業線とする
			その始点は、この時の座標
			その線色を赤に変える
			その太さを3に変える
	終わり

	キャンバス1のマウスのボタンが離された時の手順
		もし作業線が無なら抜け出す
		作業線の終点は、この時の座標
		作業線は、無
	終わり
終わり

実行すると、このようなドローアプリが出来上がります。

四角形

四角形を描くには、四角形図形を使います。四角形は「四角形を描く」手順で作れます。この図形では、四角形の左上座標と、その座標からの幅と高さを指定します。枠線は、直線の同じように色や太さを変えられます。

ひな形の「はじめの手順」を次のように書き加えてみてください。

	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		キャンバス1へ四角形を描く
			その位置と大きさは{20,20,100,100}
			その線色を青に変える
			その太さを3に変える
			その背景色を黄色に変える
			その筆の線種を「線と二点」に変える
	終わり

四角形図形は、次のような設定項目があります。

[サンプル] 図形をたくさん描こう

ランダムな四角形を描くアート作品プログラムを作ってみましょう。様々な色や大きさの四角形をランダムに描いてみようと思います。また、クリックすると、四角形を描き直すようにしてみます。

ロジックを考えてみましょう。何をすれば、作りたい物が出来上がるか、一つ一つ小さいことに分けて挙げながら考えてみると、プログラムを作れるようになります。

  • 四角形を100個作る
  • 色や大きさをランダムにする
    • 色を乱数で決める
    • 位置を画面の大きさの範囲で乱数で決める
    • 大きさを縦横10~200ピクセルの範囲の乱数で決める
  • クリックした時に再度色,位置,大きさをランダムに決める

図形を配列に入れる

繰り返し文を使って100個の四角形を作ります。作った図形は、大きさや色を後から変更できるように配列に入れておくことにします。

図形は、数値や文字列と同じように配列へ入れることができます。ここでは「図形リスト」という配列を作り、四角形を作ったときに一つずつ要素として入れることにします。この配列に入れた図形は、後でクリックした時に再度ランダムな図形を描画する時に使います。

なお「図形リスト」配列を宣言するために「ウィンドウを継承する」文の次の行あたりに、配列の宣言を書き加えてください。この場所に宣言すると、「メイン画面とは」から「終わり」までの間で、「図形リスト」を配列として使うことができます。

+図形リスト={}

上記のロジックをプログラムとして書いていくと、次のような感じのプログラムになるかと思います。

//たくさんの四角形を描く(完成版)
メイン画面を表示する
待機する

メイン画面とは
	ウィンドウを継承する
	-図形リスト={}
	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		100回繰り返す
			色A=HLS({(0~359)の乱数,0.7,0.7})
			色Aのアルファは、50
			キャンバス1へ四角形を描いて図形リストに追加する
				その位置と大きさは、{幅の乱数-100,高さの乱数-100,(10~200)の乱数,(10~200)の乱数}
				その背景色を色Aに変える
				その太さを0に変える
		そして
		キャンバス1を更新する
	終わり
	初期化する手順
	ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります
		この実質大きさを{400,400}に変える
		この内容を「ランダム図形」に変える
		初期化開始する
		キャンバス1というキャンバスを作る
			その位置と大きさを{0,0,428,394}に変える
			そのドッキング方向を「全体」に変える
		初期化終了する
		この設計スケール比率を{144,144}に変える
	終わり
	キャンバス1がクリックされた時の手順
		図形リストのすべての図形についてそれぞれ繰り返す
			色A=HLS({(0~359)の乱数,0.7,0.7})
			色Aのアルファは、50
			図形の位置と大きさは{(幅の乱数-100),(高さの乱数-100),(10~200)の乱数,(10~200)の乱数}
			図形の背景色を色Aに変える
		そして
		キャンバス1を更新する
	終わり
終わり

「乱数」で位置や大きさを決める時のコツ

決まりきった座標に図形を描くだけではワンパターンになってしまいます。そこで、乱数やイベント手順を使うことで飽きの来ない作品が作れます。さらに、実行するPCの画面の大きさを考慮して図形の座標や大きさを決めると、実行した人の環境に見やすい作品になります。

乱数を使うには、具体的な座標や大きさを指定していた変わりに「乱数」手順を指定します。例えば、『(10~200)の乱数』と指定すれば、10ピクセルから200ピクセルの範囲内でランダムな値を決めることができます。画面の大きさ全体を使って座標を決めたい場合には、『幅の乱数』または『高さの乱数』と指定します。

ただ、四角形の左上の座標を、幅や高さの範囲の乱数で指定してしまうと、殆ど画面の外に隠れて描かれてしまう場合があります。そこで、乱数で得られた座標から図形の概ね大きさ分だけ引いて、画面全体に偏り無く図形が配置されるようにします。

円を描くには、円図形を使います。円図形は「円を描く」手順で作れます。円図形では、四角形と同じように左上の座標と大きさを指定すると、その枠の中に丁度収まる円(楕円)を描きます。

ひな形の「はじめの手順」を次のように書き加えてみてください。

	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		キャンバス1へ円を描く
			その位置と大きさは{50,50,150,100}
			その線色を赤に変える
			その太さを3に変える
			その背景色を水色に変える
	終わり

刷毛と筆

図形を描く際に、塗りつぶす方法を表す刷毛(ブラシ)と、線を引く方法を表す筆(ペン)が用意されています。例えば、特定の模様で塗りつぶしたい場合は、色の変わりに刷毛を指定します。刷毛には、「グラデーションブラシ」「パターンブラシ」「塗りつぶしブラシ」があります。

刷毛Gというグラデーションブラシを作る
刷毛Gの色一覧は{赤,オレンジ,黄色,緑,水色,青,紫}
刷毛Gの位置一覧は{0,0.14,0.28,0.42,0.56,0.7,1}
刷毛Gのガンマ補正は、○
キャンバス1へ四角形を描く
	その位置と大きさは{100,100,100,100}
	その刷毛は、刷毛G

画像を描く

「画像図形」種類を使うと、PNGやBMPファイルなどの画像ファイルをキャンバスに描くことができます。ひな形の「はじめの手順」を次のように書き加えてみてください。

	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		キャンバス1へ画像を描く
			その位置と大きさは{20,20,100,100}
			その伸縮を○に変える
			その画像を「image.png」に変える
		キャンバス1を更新する
	終わり

文字を描く

「キャンバス文字」種類を使うと、キャンバス上に文字を描くことができます。ひな形の「はじめの手順」を次のように書き加えてみてください。

	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		キャンバス1へ「こんにちは!」という文字を描く
			その位置は、{50,100}
			そのフォントを「メイリオ」に変える
			その文字色を青色に変える
			その文字サイズを20に変える
		キャンバス1を更新する
	終わり

図形を動かす

図形は、作った後に移動したり大きさを変えたりもできます。

そこで、次のスクリーンショットのように、円図形を100個作って下から上へ動いていくアート作品を作ってみようと思います。

ロジックを考える

図形を動かすには何をプログラミングすればよいのでしょうか。次のようなことを考えれば、図形を動かせそうです。

  • 色,大きさ,位置がランダムな円図形を100個作る
    • 円図形は配列に入れておく
  • タイマーを使って一定時間おきに図形を動かす
    • 配列に入れた100個の図形のそれぞれに次のことをする
      • 下から上方向に図形を動かす
      • 上方向に図形を動かす→図形の横(Y軸)を少しずつ減らす
      • 画面から見えなくなった図形は、リセットする
  • リセットする→図形の画面よりも下へ移動する

これを一つずつプログラムとして作っていきます。

図形を動かすには、タイマーを使って少しずつ図形の位置を加減します。時間を掛けて少しずつ位置をずらすことで、図形が自然に動いているように見せることができます。ここでは図形の「縦」設定項目の値を5ピクセルずつ減らしていきます。

このロジックをひとつひとつプログラムとして書いていくと次のような感じになります。

//泡アニメーション
メイン画面を表示する
待機する

メイン画面とは
	ウィンドウを継承する
	+図形リスト={}
	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		100回繰り返す
			色A=HLS({(0~359)の乱数,0.7,0.7})
			色Aのアルファは、50
			キャンバス1へ円を描いて円とする
			風船サイズは、(50~100)の乱数
			円を図形リストに追加する
				その位置と大きさは、{(幅の乱数-200),(高さの乱数-200),風船サイズ,風船サイズ}
				その背景色を色Aに変える
				その太さを0に変える
		そして
		キャンバス1を更新する
		タイマー1というタイマーを作る
		タイマー1の時間になった時の手順は、時間になった
		タイマー1の間隔を10に変える
		タイマー1を開始する
	終わり
	初期化する手順
		ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります
		この実質大きさを{428,394}に変える
		この内容を「円図形」に変える
		初期化開始する
		キャンバス1というキャンバスを作る
			その位置と大きさを{0,0,428,394}に変える
			そのドッキング方向を「全体」に変える
		初期化終了する
		この設計スケール比率を{144,144}に変える
	終わり

	時間になった手順
		図形リストのすべての図形についてそれぞれ繰り返す
			図形の縦は、図形の縦-10
			図形の縦が-図形の高さ以下なら
				図形の縦は、高さ+高さの乱数
				図形の横は、(幅の乱数-200)
			そして
		そして
		キャンバス1を更新する
	終わり
終わり

再描画のタイミング

キャンバスでは、キャンバス図形の位置や色が変わると、キャンバスが自動的に再描画されます。ゲームのように沢山の図形を頻繁に動かすプログラムでは、自動再描画すると多少動作が遅くなります。このような場合は「自動更新」設定項目を×に設定し自動再描画を無効にして、「更新する」手順で手動で再描画するようにしましょう。

キャンバス1を更新する

自動再描画を無効にすると、図形の設定項目を変えてもキャンバスに反映されません。そのため図形に必要な設定をすべて変更した後、最後に「更新する」手順を呼び出して、キャンバスを再描画してください。この場合、設定項目を変更する度に再描画されることが無いため、動作が速くなります。

泡割りゲームを作る

図形のアニメーションを改良して、ちょっとしたゲームを作ってみようと思います。円を泡と見立てて、ゆらゆら動く泡をクリックして割る泡割りゲームを作ってみます。

ロジックを考える

それではロジックを考えてみましょう。

  • 泡をゆらゆら動かす
  • 泡をクリックしたら消す(リセットして画面の下へ移動する)

「図形を動かす」の章のプログラムで一通りできているので、上記の点をプログラミングすれば、泡割りゲームになるかと思います。

ゆらゆら動かす

円をゆらゆらと動かしてみましょう。下から上への移動に加えて、左右にも移動するようにします。このとき、一方向にだけ移動しないように、sin関数を使って波の形を縦にしたような形で移動する様に、横の加減を計算します。

図形のイベント手順

泡をクリックした時に、その泡が消えるようにします。それぞれの図形には、GUI部品のようにイベント手順を定義できますので、100個の円図形に対して、それぞれイベント手順を設定しておきます。

今回は「泡を割る」手順を定義しておき、100個の円図形の「クリックした時」のイベント手順として同じ「泡を割る」手順を設定します。イベント手順は図形を作る際に設定しておきます。図形が100個ありますが、どれも消えるときの操作は同じなので、1つの手順を定義すればOKです。

//イベント手順の設定(断片のみ)
そのクリックされた時の手順は、泡を割る

泡を割る手順
	図形は、発生元
	図形の縦は、高さ+高さの乱数
	図形の横は、(幅-200)の乱数
	キャンバス1を更新する
終わり

手順中の「発生元」変数は、イベント手順が発生した元となるオブジェクトが格納されています。つまりクリックされた泡の円図形を「発生元」で知ることができます。

実際には「泡を割る」手順では、クリックされた泡の位置を画面の下側のランダムな位置へ移動し直しているだけです。プログラムには書かれていませんが、例えば色や大きさも設定し直すと良いかと思います。

泡アニメーションにプログラムに上記のロジックを加えて改良すると、次のような感じのプログラムになります。

//泡割りゲーム(完全版)
メイン画面を表示する
待機する

メイン画面とは
	ウィンドウを継承する
	+図形リスト={}
	はじめの手順
		初期化する
		ーー貼り付けた部品に対する操作をここに書きます
		最大化する
	終わり
	初期化する手順
	ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります
		この実質大きさを{838,532}に変える
		この内容を「泡割りゲーム」に変える
		初期化開始する
		キャンバス1というキャンバスを作る
			その位置と大きさを{0,0,838,532}に変える
			その自動更新を×に変える
			そのドッキング方向を「全体」に変える
		初期化終了する
		この設計スケール比率を{144,144}に変える
終わり
	開いた時の手順
		100回繰り返す
			風船サイズは、(50~100)の乱数
			泡色=HLS({(0~359)の乱数,0.7,0.7})
			泡色のアルファは、50
			キャンバス1へ円を描いて泡とする
			泡を図形リストに追加する
				泡の位置と大きさは、{幅の乱数,高さの乱数,風船サイズ,風船サイズ}
				泡の背景色を泡色に変える
				その太さを0に変える
				そのクリックされた時の手順は、泡を割る
		そして
		キャンバス1を更新する
		タイマー1というタイマーを作る
		タイマー1の時間になった時の手順は、時間になった
		タイマー1の間隔を50に変える
		タイマー1を開始する
	終わり

	時間になった手順
		図形リストのすべての図形についてそれぞれ繰り返す
			図形の縦は、図形の縦-5
			図形の横は、図形の横-((図形の縦*360/高さ*2)度のサイン)*5
			もし図形の縦が-図形の高さ以下なら
				風船サイズは(50~100)の乱数
				図形の位置と大きさは、{幅の乱数,高さ+(高さの乱数/2),風船サイズ,風船サイズ}
				泡色=HLS({(0~359)の乱数,0.7,0.7})
				泡色のアルファは、50
				図形の背景色を泡色に変える
			そして
		そして
		キャンバス1を更新する
	終わり
	泡を割る手順
		図形は、発生元
		図形の縦は、高さ+高さの乱数
		図形の横は、(幅-200)の乱数
		キャンバス1を更新する
	終わり
終わり

子キャンバス図形

子キャンバス図形を使うと、キャンバス上に小さなキャンバスを作ることができます。子キャンバスの中に複数の図形を貼り付けることで、複雑な図形を一括して扱うことができます。複雑な図形を描いた場合、それを一つ一つ移動させる必要なく、子キャンバスの移動させるだけで、中にある図形を移動させることができます。

次の例は、子キャンバスを作り、その中に四角形と直線の図形を描き、また、マウスのイベント手順で子キャンバスをドラッグ&ドロップで移動できるプログラムです。

メイン画面を表示する
待機する

メイン画面とは
	ウィンドウを継承する
	はじめ手順
		初期化する
		選択図形は、無
		処理中は、×
		キャンバス1に子キャンバスを作って子キャンバス1とする
			その位置と大きさは、{10,10,100,100}
			その背景色を白に変える
		子キャンバス1へ四角形を描く
			その位置と大きさは、{10,10,80,50}
		子キャンバス1へ線を描く
			その位置と大きさは、{10,70,80,30}
		キャンバス1を更新する
	終わり

	初期化する手順
	ーー自動生成された手順です。ここにプログラムを書き加えても消える場合があります
		この実質大きさを{300,300}に変える
		この初期位置を「手動」に変える
		この内容を「子キャンバスの例」に変える
		初期化開始する
		キャンバス1というキャンバスを作る
			その位置と大きさを{0,0,417,366}に変える
			その背景色を「水」に変える
			そのドッキング方向を「全体」に変える
			その間隔を{4,4,4,4}に変える
		初期化終了する
		この設計スケール比率を{96,96}に変える
終わり

	-移動中
	-開始横座標
	-開始縦座標
	-処理中
	-選択図形

	キャンバス1がマウスのボタンが押された時の手順
		選択図形は、キャンバス1から{イベントの横座標,イベントの縦座標}を選択したもの
		もし選択図形が子キャンバス1でないなら 抜け出す
		移動中は、○
		開始横座標は、選択図形の横-イベントの横座標
		開始縦座標は、選択図形の縦-イベントの縦座標
	終わり
	キャンバス1のマウスカーソルが移動した時の手順
		もし移動中でないなら、抜け出す
		もし処理中なら、抜け出す
		処理中は、○
		選択図形の位置は{イベントの横座標+開始横座標,イベントの縦座標+開始縦座標}
		キャンバス1を更新する
		処理中は、×
	終わり
	キャンバス1がマウスのボタンが離された時の手順
		移動中は、×
	終わり
終わり

マウスのイベント手順では、マウスがドラッグされているのに合わせて子キャンバスの位置を変えています。子キャンバスが移動すると、その中にある四角形と直線も合わせて移動します。

まとめ

キャンバスを使ってプログラムで図形を描く方法をご紹介しました。今回も盛りだくさんの内容になりましたが、グラフ描画やゲーム作り、凝った画面の描画など、色々なケースにも利用できますので、ぜひ使い方を覚えて活用していただければ幸いです。

キャンバスを使ったサンプルコードは次の記事でもご紹介しています。

※当ブログの記事の著作権はゆうとにあります。プロデルに関係が無い目的で、文章や図表,プログラムを複製, 改変, 移植して掲載することを堅く禁止します

  • いいね (22)
  • 続編を読みたい (44)

コメントを残す