06-05 震える文字

練習問題6-5-1

06-04 の練習問題6-4-4 を参考に、星の代わりに 線だけ を描く土台を作りましょう。
練習問題を進めるうちに機能を足していくので、機能ごとに 関数 に分けて作ります。6-5-1 では drawGrid(方眼)と drawPaths(直線)です。

let pointX = [];
let pointY = [];

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(255);
  drawGrid();   // 方眼の背景
  drawPaths();  // 確定した線
}

function drawGrid() {
  stroke(220);
  strokeWeight(1);
  for(let x=0; x<width; x+=20){
    line(x, 0, x, height)
  }
  for(let y=0; y<height; y+=20){
    line(0, y, width, y)
  }
}

function drawPaths() {
  stroke(0);
  strokeWeight(3);
  for(let i=0; i<pointX.length-1; i++){
    line(pointX[i], pointY[i], pointX[i+1], pointY[i+1])
  }
}

function mousePressed() {
  if(mouseButton===LEFT){
    pointX.push(mouseX);
    pointY.push(mouseY);
  }
}
前に習ったことをいろいろ使ったので、難しかったです。

練習問題6-5-2

練習問題6-5-1 では、クリックしたあとでないと線が見えませんでした。
6-5-2 では drawPreview(プレビュー線)を追加します。

  • 点が 1つ以上 あるとき、最後の点から mouseX と mouseY へプレビュー線を引く
  • draw の中から drawPreview を呼び出す
let pointX = [];
let pointY = [];

function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(255);
  drawGrid();   // 方眼の背景
  drawPaths();  // 確定した線
  drawPreview()
}

function drawGrid() {
  stroke(220);
  strokeWeight(1);
  for(let x=0; x<width; x+=20){
    line(x, 0, x, height)
  }
  for(let y=0; y<height; y+=20){
    line(0, y, width, y)
  }
}

function drawPaths() {
  stroke(0);
  strokeWeight(3);
  for(let i=0; i<pointX.length-1; i++){
    line(pointX[i], pointY[i], pointX[i+1], pointY[i+1])
  }
}

function mousePressed() {
  if(mouseButton===LEFT){
    pointX.push(mouseX);
    pointY.push(mouseY);
  }
}
function drawPreview(){
  if(pointX.length>=1){
    line(pointX[pointX.length-1], pointY[pointY.length-1], mouseX,mouseY)
  }
}
一個目の点から線を追従させるのには成功しましたが、その後追従してくれなくなってしまい、なぜかと思いわからなかったため、AIに聞いたところ、if(pointX.length>=1)が、if(pointX>=1)になってしまっていました。凡ミスばっかりで大変です。

練習問題6-5-3

練習問題6-5-2 のままだと、絵を描き終えても、最後の点からマウスへ プレビュー線が出続けます
プレビューを止める仕組みを追加しましょう。
6-5-3 では drawPreview にプレビュー停止の機能を足します。

let canvas;
let pointX = [];
let pointY = [];
let isDrawing = false;

function setup() {
  canvas = createCanvas(400, 400);
  canvas.elt.addEventListener("contextmenu", function (e) {e.preventDefault();});
}

function draw() {
  background(255);
  drawGrid();
  drawPaths();
  drawPreview();
}

function drawGrid() {
  stroke(220);
  strokeWeight(1);
  for(let x=0; x<width; x+=20){
    line(x, 0, x, height)
  }
  for(let y=0; y<height; y+=20){
    line(0, y, width, y)
  }
}

function drawPaths() {
  stroke(0);
  strokeWeight(3);
  for(let i=0; i<pointX.length-1; i++){
    line(pointX[i], pointY[i], pointX[i+1], pointY[i+1])
  }
}

function drawPreview() {
  if(isDrawing){
    if(pointX.length>=1){
      line(pointX[pointX.length-1], pointY[pointY.length-1], mouseX,mouseY)
    }
  }
}

function mousePressed() {
  if (mouseButton === LEFT) {
    pointX.push(mouseX);
    pointY.push(mouseY);
    isDrawing = true
  } else if (mouseButton === RIGHT) {
    isDrawing = false
  }
}

trueとfalseのおさらいになってよかったです。

練習問題6-5-4

これまで置いた点はずっと線でつながっていました(一筆書き)。そのため文字の「A」のように、途中で線を切る形は描けませんでした。

6-5-4 では、線の 切れ目 を pointX と pointY に -1 で記録し、線を切れるようにします。-1 は座標ではなく、切れ目のしるし です。

let canvas;
let pointX = [];
let pointY = [];
let isDrawing = false;

function setup() {
  canvas = createCanvas(400, 400);
  canvas.elt.addEventListener("contextmenu", function (e) {e.preventDefault();});
}

function draw() {
  background(255);
  drawGrid();
  drawPaths();
  drawPreview();
}

function drawGrid() {
  stroke(220);
  strokeWeight(1);
  for(let x=0; x<width; x+=20){
    line(x, 0, x, height)
  }
  for(let y=0; y<height; y+=20){
    line(0, y, width, y)
  }
}

function drawPaths() {
  stroke(0);
  strokeWeight(3);
  for (let i = 0; i < pointX.length - 1; i++) {
    if (pointX[i+1]!==-1&&pointX[i]!==-1) {
        line(pointX[i], pointY[i], pointX[i + 1], pointY[i + 1]);
    }
  }
}

function drawPreview() {
  if(isDrawing){
    if(pointX.length>=1){
      line(pointX[pointX.length-1], pointY[pointY.length-1], mouseX,mouseY)
    }
  }
}

function mousePressed() {
  if (mouseButton === LEFT) {
    pointX.push(mouseX);
    pointY.push(mouseY);
    isDrawing = true
  } else if (mouseButton === RIGHT) {
    pointX.push(-1)
    pointY.push(-1)
    isDrawing = false;
  }
}
本当に頭が回っていないのか難しかったのかわかりませんが、全然糸口がつかめず、AIにいろいろ聞きました。何を間違たのかはたくさんありすぎて思い出せません。
AIに頼りすぎていないかがとても心配です。

練習問題6-5-5

練習問題6-5-4 を改造し、C キー を押したら点と線を すべて消す プログラムを作りなさい。

6-5-5 では keyPressed を追加し、C キーですべて消せるようにします。配列を空にし、isDrawing も false に戻しなさい。
6-5-4 と同じ部分は省略しています。

let canvas;
let pointX = [];
let pointY = [];
let isDrawing = false;

function setup() {
  canvas = createCanvas(400, 400);
  canvas.elt.addEventListener("contextmenu", function (e) {e.preventDefault();});
}

function draw() {
  background(255);
  drawGrid();
  drawPaths();
  drawPreview();
}

function drawGrid() {
  stroke(220);
  strokeWeight(1);
  for(let x=0; x<width; x+=20){
    line(x, 0, x, height)
  }
  for(let y=0; y<height; y+=20){
    line(0, y, width, y)
  }
}

function drawPaths() {
  stroke(0);
  strokeWeight(3);
  for (let i = 0; i < pointX.length - 1; i++) {
    if (pointX[i+1]!==-1&&pointX[i]!==-1) {
        line(pointX[i], pointY[i], pointX[i + 1], pointY[i + 1]);
    }
  }
}

function drawPreview() {
  if(isDrawing){
    if(pointX.length>=1){
      line(pointX[pointX.length-1], pointY[pointY.length-1], mouseX,mouseY)
    }
  }
}

function mousePressed() {
  if (mouseButton === LEFT) {
    pointX.push(mouseX);
    pointY.push(mouseY);
    isDrawing = true
  } else if (mouseButton === RIGHT) {
    pointX.push(-1)
    pointY.push(-1)
    isDrawing = false;
  }
}

function keyPressed(){
  if(key==="c")
  pointX = []
  pointY = []
  isDrawing = false
}
これは意外にもすぐにできました。
先ほどまでの課題はものすごく難しかったので、こちらも難しいかと思ったのですが、結構すぐにできて驚きました。

練習問題6-5-6

いよいよ 震える文字 の仕上げです。
6-5-6 では shakeLine 関数を追加し、line を自作関数 shakeLine に置き換えます。
shakeLine の中では random を使用して、毎回座標を少しだけずらして、線をブルブル震えさせます。ボカロのミュージックビデオのような文字演出にも使われるテクニックです。

let canvas;
let pointX = [];
let pointY = [];
let isDrawing = false;
let isShaking = false;

function setup() {
  canvas = createCanvas(400, 400);
  canvas.elt.addEventListener("contextmenu", function (e) {e.preventDefault();});
}

function draw() {
  background(255);
  drawGrid();
  drawPaths();
  drawPreview();
}

function drawGrid() {
  stroke(220);
  strokeWeight(1);
  for(let x=0; x<width; x+=20){
    line(x, 0, x, height)
  }
  for(let y=0; y<height; y+=20){
    line(0, y, width, y)
  }
}

function drawPaths() {
  stroke(0);
  strokeWeight(3);
  for (let i = 0; i < pointX.length - 1; i++) {
    if (pointX[i+1]!==-1&&pointX[i]!==-1) {
        shakeLine(pointX[i], pointY[i], pointX[i + 1], pointY[i + 1]);
    }
  }
}

function drawPreview() {
  if(isDrawing){
    if(pointX.length>=1){
      line(pointX[pointX.length-1], pointY[pointY.length-1], mouseX,mouseY)
    }
  }
}

function mousePressed() {
  if (mouseButton === LEFT) {
    pointX.push(mouseX);
    pointY.push(mouseY);
    isDrawing = true
  } else if (mouseButton === RIGHT) {
    pointX.push(-1)
    pointY.push(-1)
    isDrawing = false;
  }
}

function keyPressed(){
  if (key === "c" || key === "C") {
  pointX = []
  pointY = []
  isDrawing = false
  }
  if(key === " "&&!isShaking){
    isShaking = true
  }else if(key===" "){
    isShaking = false
  }
}

function shakeLine(x1, y1, x2, y2) {
  let r = random(-5, 5)
  if(isShaking){
    line(x1+r, y1+r, x2+r, y2+r)
  }else{
    line(x1, y1, x2, y2)
  }
}
結構難しかったですが、手ごたえがあってよかったです。今回はあまりAIに聞かなかったのも個人的にはよかったです。

練習問題6-5-7

練習問題6-5-6 のプログラムを使い、自分の イニシャル(名前の頭文字)を直線で描いてみなさい。

完成したら、次の問いに答え、レポートに書いて先生に確認してもらいなさい。

  1. 線を切るために、右クリックは何回使いましたか?
  2. 切れ目のしるし(-1)を入れないと、どんな問題が起きますか?
  3. drawGrid や drawPaths のように関数に分けると、draw のどこが楽になりますか?
  4. shakeLine 関数があると、プログラムのどこが楽になりますか?

Q 線を切るために、右クリックは何回使いましたか?
A イニシャルの事ですよね?点も描いたので6回だと思います。

Q 切れ目のしるし(-1)を入れないと、どんな問題が起きますか?
A 使わなければどうなるかということならば、線と線を切り離すことができなくなって、自由度が低下してしまいます。

Q drawGrid や drawPaths のように関数に分けると、draw のどこが楽になりますか?
A drawの中身がとても見やすくなり、プログラムを変更するときなどにも見つけやすいと思います。

Q shakeLine 関数があると、プログラムのどこが楽になりますか?
A もともとの線を基準に新たなifなどでさらに応用がしやすくなったと思います。

コメントする