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
黒鍵はここから少しだけ工夫しています。
黒鍵の場合は、このキーの半分だけ右にずらして描画するようにしています。
これは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);
}
}
これで、一見してキーが並んだのですが、ミの#?もしくはファの♭?は存在しないはずでは!と言うことに気がつきました。
そこで、黒鍵のうち左から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のエディターにコピペして確認して見て下さい!
続きはまた後日!