見出し画像

p5.jsでシンセサイザーを作る 第13話 キーを配置する

Javascriptとp5.jsを使って、オリジナルなシンセサイザーを作るプログラミングの記事です。とりあえず何を作るのかを手っ取り早くお伝えしたいので、第0話で公開している完成品もチェックしてみてください。

キーを配置します

前回はノブの配置ができましたので、次はキー(キーボード)を配置します。

とりあえずキーを一つだけ描画する

第5話で作成したキーのソースを改変して、複数のパーツを配置できるようにしていきます。

let keySize = 50; // キーのサイズ
let keyTop = keySize / 1.4; // キートップのサイズ
let topSize = 7; // キートップの位置を中央に寄せる幅
let keyX = 50; // キーの位置X
let keyY = 50; // キーの位置Y
let keyStat = false; // キーのクリック判定

let strokeValue = 2; // 枠線の太さ

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

function draw() {
  background(250); //背景の色
  
  stroke(150, 100, 100);
  strokeWeight(strokeValue);
  
  fill(230, 230, 230); // キーのベース
  rect(keyX , keyY, keySize, keySize);
  
  fill(100, 100, 100);  // キーの影部分を三角形で表現
    triangle(
      keyX, keyY, //左上
      keyX, keyY + keySize, //左上
      keyX + keySize, keyY + keySize //右下
    );
  
  fill(250, 250, 250) // キーのトップ部分
  rect(keyX + topSize, keyY + topSize, keyTop, keyTop);
  
  if (keyStat == true){ // マウスクリックでオレンジ色でキートップを塗り替える
    fill(255, 125, 0);
    rect(keyX + topSize, keyY + topSize, keyTop, keyTop);
  }
}

function touchStarted() {
  if (
    mouseX > keyX - keySize &&
    mouseX < keyX + keySize &&
    mouseY > keyY - keySize &&
    mouseY < keyY + keySize
  ) {
    keyStat = true;
  }
}

function touchEnded() {
  keyStat = false;
}
キーを一つだけ描画します

キーボードは白鍵と黒鍵に分ける

前回と同じように、必要な変数を配列にしていきます。
キーボードはドレミファソラシドの8個、そして、ド#レ#ファ#ソ#ラ#の5個で、合計13個のキーが描画されるようにします。
私の場合は8個と5個を二つのグループに分けて描画することにしました。

こちらの二つのグループに分けてみます。

いわゆる、白鍵と黒鍵を異なる配列にすると言うアプローチです。

①宣言の部

let keySize = 50; // キーのサイズ
let keyTop = keySize / 1.4; // キートップのサイズ
let topSize = 7; // キートップの位置を中央に寄せる幅
let keyX = 50; // キーの位置X
let keyY = 150; // キーの位置Y
let keyInterval = 50;
let keyStat = [false, false, false, false, false, false, false, false]; // 白鍵の判定
let keyStatS = [false, false, false, false, false, false]; // 黒鍵の判定

let strokeValue = 2; // 枠線の太さ

keyStatは白鍵の8個に対するキー判定に使います
keyStatSは黒鍵の5個に対するキー判定に使います。
黒鍵に使うkeyStatsは6個の配列要素がありますが、これは後で解説します。

②初期化の部

ここはキャンバスサイズの指定だけなので、変更はありません。

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

③実行の部

function draw() {
  background(250); //背景の色
  drawHousing();
  drawInterface(); 
}

ここではキーのベース部分を描画するdrawHousing()と
キーをオレンジに光らせるためのdrawInterface()を呼び出します。
詳しくは④動作の部に記述します。

④動作の部

ここからは、キーのベースとオレンジ色に光るレスポンス、それに当たり判定が入ります。

まずは、白鍵と黒鍵をかき分けます。

function drawHousing(){
  stroke(150, 100, 100);
  strokeWeight(strokeValue);

  ////////ここから白鍵////////////////
  fill(230, 230, 230); // キーのベース
  for(let i = 0; i < 8; i++){
    rect(keyX + keyInterval * i, keyY, keySize, keySize);
  }

  fill(100, 100, 100);  // キーの影部分の色
  
  for(let i = 0; i < 8; i++){
    triangle(
      keyX + keyInterval * i, keyY, //左上
      keyX + keyInterval * i, keyY + keySize, //左下
      keyX  + keyInterval * i+ keySize, keyY + keySize //右下
    );
  }
  
  fill(250, 250, 250) // キーのトップ部分
  for(let i = 0; i < 8; i++){
    rect(keyX + keyInterval * i + topSize, keyY + topSize, keyTop, keyTop);
  }
  
  ////////ここから黒鍵////////////////
  
  fill(230, 230, 230); // キーのベース
  for(let i = 0; i < 6; i++){
    if(i != 2){
      rect(keyX + keyInterval * i + keySize / 2, keyY - keySize, keySize, keySize);
    }
  }

  fill(100, 100, 100);  // キーの影部分の色
  
  for(let i = 0; i < 6; i++){
    if(i != 2){
      triangle(
        keyX + keyInterval * i + keySize / 2, keyY - keySize, //左上
        keyX + keyInterval * i + keySize / 2, keyY, //左下
        keyX  + keyInterval * i + keySize / 2 + keySize, keyY //右下
      );
    }
  }
  
  fill(250, 250, 250) // キーのトップ部分
  for(let i = 0; i < 6; i++){
    if(i != 2){
      rect(keyX + keyInterval * i + topSize + keySize / 2, keyY- keySize + topSize, keyTop, keyTop);
    }
  }
}

今回のキーを配置するときのコツです。
白鍵は、シンプルに左端のキー(ド)からkeySizeの分だけ左にシフトする描画を8回繰り返せばOKです。
keyX + keyInterval * i

普通に8個並びます。ドレミファソラシドー

黒鍵はここから少しだけ工夫しています。
黒鍵の場合は、このキーの半分だけ右にずらして描画するようにしています。
これは6回繰り返して描画しています。

keyX + keyInterval * i + keySize / 2

キーの半分だけ右にずらすのはこの部分です
+ keySize / 2

 for(let i = 0; i < 6; i++){
   if(i != 2){
      rect(keyX + keyInterval * i + keySize / 2, keyY - keySize, keySize, keySize);
    }
  }
黒鍵部分を6回描画すると

これで、一見してキーが並んだのですが、ミの#?もしくはファの♭?は存在しないはずでは!と言うことに気がつきました。

ここです。


そこで、黒鍵のうち左から3番目。つまり配列の番号が2の時にはキーを描画しないようにfor分のループの中にif文を追加しました。

if(i != 2){
}

例の、ミの#とかファの♭というのは、黒鍵の3番目に位置していますので、for文で指定したiが2でなければパーツを描画するという記述にしました。iは0から始まっているので、2の時はちょうど3番目の配列要素ということになります。

当たり判定も同じルーチンにする

8個の白鍵と6個の黒鍵(1個は存在しない)を描画しました。for文、配列、if文を活用した書き方を応用して、キーの当たり判定も全て記述を変えていきます。

function touchStarted() {
  for (let i = 0; i < 8; i++) {
    if (
      mouseX > keyX + keySize * i &&
      mouseX < keyX + keySize * i + keySize &&
      mouseY > keyY&&
      mouseY < keyY + keySize
    ) {
      keyStat[i] = true;
    }
  }
  for (let i = 0; i < 6; i++) {
    if (
      mouseX > keyX + keySize / 2 + keySize * i &&
      mouseX < keyX + keySize / 2 + keySize * i + keySize &&
      mouseY > keyY - keySize &&
      mouseY < keyY
    ) {
      if(i != 2){
        keyStatS[i] = true;
      }
    }
  }
}

function touchEnded() {
  for (let i = 0; i < 8; i++) {
    keyStat[i] = false;
  }
  for (let i = 0; i < 6; i++) {
    keyStatS[i] = false;
  }
}

実行してみます

クリックしたキーが全部反応するようになりました!

できました!

このプログラムでは、マウスの当たり判定を使っているのですが、PCのキーボードを使うように応用すると、快適にキー入力できるようになりそうです。

この記事のコード全文

let keySize = 50; // キーのサイズ
let keyTop = keySize / 1.4; // キートップのサイズ
let topSize = 7; // キートップの位置を中央に寄せる幅
let keyX = 50; // キーの位置X
let keyY = 150; // キーの位置Y
let keyInterval = 50;
let keyStat = [false, false, false, false, false, false, false, false]; // 白鍵の判定
let keyStatS = [false, false, false, false, false, false]; // 黒鍵の判定

let strokeValue = 2; // 枠線の太さ

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

function draw() {
  background(250); //背景の色
  drawHousing();
  drawInterface(); 
}

function drawHousing(){
  stroke(150, 100, 100);
  strokeWeight(strokeValue);

  ////////ここから白鍵////////////////
  fill(230, 230, 230); // キーのベース
  for(let i = 0; i < 8; i++){
    rect(keyX + keyInterval * i, keyY, keySize, keySize);
  }

  fill(100, 100, 100);  // キーの影部分の色
  
  for(let i = 0; i < 8; i++){
    triangle(
      keyX + keyInterval * i, keyY, //左上
      keyX + keyInterval * i, keyY + keySize, //左下
      keyX  + keyInterval * i+ keySize, keyY + keySize //右下
    );
  }
  
  fill(250, 250, 250) // キーのトップ部分
  for(let i = 0; i < 8; i++){
    rect(keyX + keyInterval * i + topSize, keyY + topSize, keyTop, keyTop);
  }
  
  ////////ここから黒鍵////////////////
  
  fill(230, 230, 230); // キーのベース
  for(let i = 0; i < 6; i++){
    if(i != 2){
      rect(keyX + keyInterval * i + keySize / 2, keyY - keySize, keySize, keySize);
    }
  }

  fill(100, 100, 100);  // キーの影部分の色
  
  for(let i = 0; i < 6; i++){
    if(i != 2){
      triangle(
        keyX + keyInterval * i + keySize / 2, keyY - keySize, //左上
        keyX + keyInterval * i + keySize / 2, keyY, //左下
        keyX  + keyInterval * i + keySize / 2 + keySize, keyY //右下
     );
    }
  }
  
  fill(250, 250, 250) // キーのトップ部分
  for(let i = 0; i < 6; i++){
    if(i != 2){
      rect(keyX + keyInterval * i + topSize + keySize / 2, keyY- keySize + topSize, keyTop, keyTop);
    }
  }
}

function drawInterface(){
  for(let i = 0; i < 8; i++){
    if (keyStat[i] == true){ // オレンジ色で白鍵のキートップを塗り替える
      fill(255, 125, 0);
      rect(keyX + keyInterval * i + topSize, keyY + topSize, keyTop, keyTop);
    }
  }
  for(let i = 0; i < 6; i++){
    if (keyStatS[i] == true){ // オレンジ色で白鍵のキートップを塗り替える
      fill(255, 125, 0);
      rect(keyX + keyInterval * i + topSize + keySize / 2, keyY- keySize + topSize, keyTop, keyTop);
    }
  }
}

function touchStarted() {
  for (let i = 0; i < 8; i++) {
    if (
      mouseX > keyX + keySize * i &&
      mouseX < keyX + keySize * i + keySize &&
      mouseY > keyY&&
      mouseY < keyY + keySize
    ) {
      keyStat[i] = true;
    }
  }
  for (let i = 0; i < 6; i++) {
    if (
      mouseX > keyX + keySize / 2 + keySize * i &&
      mouseX < keyX + keySize / 2 + keySize * i + keySize &&
      mouseY > keyY - keySize &&
      mouseY < keyY
    ) {
      if(i != 2){
        keyStatS[i] = true;
      }
    }
  }
}

function touchEnded() {
  for (let i = 0; i < 8; i++) {
    keyStat[i] = false;
  }
  for (let i = 0; i < 6; i++) {
    keyStatS[i] = false;
  }
}

実際にp5.jsのエディターにコピペして確認して見て下さい!

続きはまた後日!

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?