プログラミングの備忘録

プログラムをつくる過程を残すもの

processingの備忘録 -キーの検知-

こんにちは。
今回は「キーの検知」についてです。
キーボードのキーを押す・離すことで処理させたいとか、アローキーやWASDキーで上下左右に動かしたいというときに使えます。

早速、キー操作で円が動くプログラムを書いてみます。
アローキーなら、

float x, y;

void draw() {
    background(0);
    
    if(keyPressed == true){ //キーが押されたとき
        if(keyCode == UP)    y -= 2; //そのキーが「上」だったらyの負の方向に
        if(keyCode == DOWN)  y += 2; //そのキーが「下」だったらyの正の方向に
        if(keyCode == LEFT)  x -= 2; //そのキーが「左」だったらxの負の方向に
        if(keyCode == RIGHT) x += 2; //そのキーが「右」だったらxの正の方向に
    }
    ellipse(x, y, 20, 20);
}

WASDならif文の処理を以下のように変えます。

if(key == 'w') y -= 2; //そのキーが「w」だったらyの負の方向に
if(key == 's') y += 2; //そのキーが「s」だったらyの正の方向に
if(key == 'a') x -= 2; //そのキーが「a」だったらxの負の方向に
if(key == 'd') x += 2; //そのキーが「d」だったらxの正の方向に

これらは、長押ししながら押すキーを素早く変えると挙動がおかしくなったり、斜め移動ができなかったりと欠点があります。とはいっても、一方向のみに動かせればいいというときはこれで問題ないです。
「keyCode」は最後に押されたキーの情報が入るようで、上のプログラムでif(keyPressed == true)の条件がないと、キーを離しても永遠動き続けます。

以下のような関数もありますが、長押し始めに一瞬止まるのでこれもまた違和感があります。ですが、後述するように、あるキーを押したときだけに処理するなど、長押しする必要がない場合はこれで問題ないです。

void keyPressed(){
    if(key == 'w') y -= 2;
    if(key == 's') y += 2;
    if(key == 'a') x -= 2;
    if(key == 'd') x += 2;
}


素早く変えたときや長押し始めの挙動のおかしさを解決するためには、以下のようにするとよいです。

float x, y;
boolean up, down, left, right; //キーの押す・離すを検知する値を定義

void draw() {
    background(0);
    
    //各キーが押されているとき、それに対応する方向に動かす
    if(up == true)    y -= 2;
    if(down == true)  y += 2;
    if(left == true)  x -= 2;
    if(right == true) x += 2;
  
    ellipse(x, y, 20, 20);
}

void keyPressed(){ //各キーが押されたとき、それに対応するbool値がtrue(=押された)になる
    if(keyCode == UP)    up = true;
    if(keyCode == DOWN)  down = true;
    if(keyCode == LEFT)  left = true;
    if(keyCode == RIGHT) right = true;
}

void keyReleased(){ //各キーが離されたとき、それに対応するbool値がfalse(=離された)になる
    if(keyCode == UP)    up = false;
    if(keyCode == DOWN)  down = false;
    if(keyCode == LEFT)  left = false;
    if(keyCode == RIGHT) right = false;
}

「boolean」で「bool値」という「true」か「false」をとる値を定義して、キーを押す・離すを検知しています。
「boolean」は「float」や「int」などと同じように、こういう種類の値だよと指定するためのものです。
調べてみると、二進数を使ったパターンもあるようですが、また必要になったらブログ化したいと思います。


さて、先に述べたように、長押しの必要がないときはkeyPressed()でよいということでした。
processingのサンプルコードがたまにそうであったり、processingのソフト上でスケッチのタブを見るとわかりますが、クラスなどコードを書いたファイルを別のファイルとして保存しておき、プログラム本文が書かれたファイルがあるフォルダに入れておけば、プログラム本文を実行したときに勝手に実行してくれます。
これを利用して、プログラムを実行している画面を撮るためのコードを別のファイルに書いておき、撮りたいときにフォルダに入れれば撮れるようにしてみます。

//sketch.pde

void draw(){
    ellipse(50, 50, 20, 20);
}
//screenshot.pde

void keyPressed(){
    if(key == 's'){
        saveFrame("image.png");
        println("Saved.");
    }
}

これら2つのコードを同じ「sketch」フォルダに入れておけば、sketch.pdeを実行したときにscreenshot.pdeも実行してくれるため、「s」キーを押したときに画像を保存できます。
ただしこれはプログラム本文にdraw()が必要で、かつプログラム本文にはkeyPressed()が含まれていないことが条件です。
新たにスクショ用の関数をつくってもいいですが、その場合はプログラム本文のdraw()内にその関数を呼び出す処理を追加する必要があります。
なので使う場面は限られると思いますが、フラクタルなどの静止画をつくったときや以前つくったブラウン運動っぽいプログラムなどであれば、スクショ用に使えます。


というわけで、キーを押す・離すことによる処理について述べてみました。
きりがよいのでここまでにしたいと思います。また次回。