Processing画面上の図形をマウスでドラッグし、その動きを記録する方法、記録した内容をテキストデータとして外部に保存する方法、さらにそのテキストデータを読み取って動きを再生させるサンプルです。
まずは、ドラッグする図形を円とした場合のプログラムから始めます。今回は
mouseDragged()は使わず、startDragというフラグを用意し、
mousePressed()でドラッグ開始(startDrag=true)、
mouseReleased()でドラッグ終了(startDrag=false)とみなす方法を用います。
円の中心座標から少しずれた位置にマウスを合わせてそのままドラッグできるように、円の中心座標とマウス座標の差分を計算しておき、その差分を足した値を最終的に円の座標に反映されるようにします。
また、
dist()を使って円の中心座標からマウス座標までの距離を計算し、その距離が円の半径以内であれば円の上にマウスがあることとみなしてドラッグ可能にします。
dist()は、dist(x1,y1,x2,y2)のように(x1,y1)と(x2,y2)の二点間の距離を計算します。
「円をドラッグする」: [プログラムを表示]
//円のXY座標の変数を用意する
int x,y;
//円の座標とマウス座標の差分(ずれ)の変数
int dx,dy;
//ドラッグ開始終了のフラグを用意
boolean startDrag;
//円の半径
int r=30;
void setup(){
size(600,600);//画面サイズ設定
smooth();//滑らかな描画にする
stroke(255);//線色を白
fill(0);//塗り色を黒
x=width/2;//円を画面中心に配置しておく
y=height/2;
}
void draw(){
background(0);//背景色(黒)
//ドラッグ中の場合
if(startDrag==true){
//マウス座標に差分を加えた値を円の座標に代入
x=mouseX+dx;
y=mouseY+dy;
}
//円を描画する
ellipse(x,y,r*2,r*2);
}
void mousePressed(){
//円中心座標とマウス座標の距離が円半径以内の場合
if(dist(x,y,mouseX,mouseY)<=r){
//ドラッグ用フラグをtrue(ドラッグ中)にする
startDrag=true;
//円の座標とマウス座標の差分を求めておく
dx=x-mouseX;
dy=y-mouseY;
}
}
void mouseReleased(){
//ドラッグ用フラグをfalse(ドラッグなし)にする
startDrag=false;
}
「円をドラッグ+記録機能」:上記プログラムに、ドラッグした円の動き(連続する座標値)を記録する機能を付け加えます(以下のプログラム)。「r」キーを押すことで記録開始にします。再度「r」キーを押すと記録停止するようにし、記録中は円の塗色を赤に変化させます。プログラム的には、recordStartというフラグを用意し、記録開始/停止を判別できるようにします。xPosとyPosという座標を記録するための配列を用意しておき、記録中はそれらの配列に座標値を付け加えていきます。
赤文字の部分が付け足したプログラムです。
[プログラムを表示]
//円のXY座標の変数を用意する
int x,y;
//円の座標とマウス座標の差分(ずれ)の変数
int dx,dy;
//ドラッグ開始終了のフラグ
boolean startDrag;
//円の半径
int r=30;
//記録中/記録停止のフラグ
boolean startRecord;
//座標記録用の配列を用意し、内容を空にしておく。
int[] xPos={};
int[] yPos={};
void setup(){
size(600,600);//画面サイズ設定
smooth();//滑らかな描画にする
stroke(255);//線色を白
fill(0);//塗り色を黒
x=width/2;//円を画面中心に配置しておく
y=height/2;
}
void draw(){
background(0);//背景色(黒)
//ドラッグ中の場合
if(startDrag==true){
//マウス座標に差分を加えた値を円の座標に代入
x=mouseX+dx;
y=mouseY+dy;
}
//記録中の場合
if(startRecord==true){
xPos=append(xPos,x);//座標値を配列に付け加えていく
yPos=append(yPos,y);
}
//円を描画する
ellipse(x,y,r*2,r*2);
}
void mousePressed(){
//円中心座標とマウス座標の距離が円半径以内の場合
if(dist(x,y,mouseX,mouseY)<=r){
//ドラッグ用フラグをtrue(ドラッグ中)にする
startDrag=true;
//円の座標とマウス座標の差分を求めておく
dx=x-mouseX;
dy=y-mouseY;
}
}
void mouseReleased(){
//ドラッグ用フラグをfalse(ドラッグなし)にする
startDrag=false;
}
void keyPressed(){
if(key=='r'){//「r」キーを押した場合
if(startRecord==true){//記録中の場合
startRecord=false;//記録なしに戻す
fill(0,0,0);//円の塗色を黒に戻す
}else{//記録なしの場合
startRecord=true;//記録中にする
fill(255,0,0);//円の塗色を赤にする
}
}
}
xPos={}というように空の配列をはじめに用意しておき、
append()を使って変化する座標値を配列xPosに付け加えていきます。よって、配列xPosに含まれる要素は、記録されるごとに増えていきます。
xPos.lengthを用いれば、記録された配列内の座標の個数を調べることができます。
記録停止しているときに「r」キーが押されればstartRecord=trueにし、逆に記録停止しているときに押されれば、startRecord=falseに切り替えられるように、フラグstartRecordを使い分けます。
「円をドラッグ+記録機能+保存機能」:さらに以下では、記録された内容をテキストファイルとして外部保存する機能と記録した座標値を消去する機能を付け足します(赤い文字部分)。「r」キーで記録、「s」キーでファイル保存、「c」キーで記録内容を消去することにします。
[プログラムを表示]
//円のXY座標の変数を用意する
int x,y;
//円の座標とマウス座標の差分(ずれ)の変数
int dx,dy;
//ドラッグ開始終了のフラグ
boolean startDrag;
//円の半径
int r=30;
//記録中/記録停止のフラグ
boolean startRecord;
//座標記録用の配列を用意し、内容を空にしておく
int[] xPos={};
int[] yPos={};
//消去用に空の配列を用意しておく
int[] clearArray={};
void setup(){
size(600,600);//画面サイズ設定
smooth();//滑らかな描画にする
stroke(255);//線色を白
fill(0);//塗り色を黒
x=width/2;//円を画面中心に配置しておく
y=height/2;
}
void draw(){
background(0);//背景色(黒)
//ドラッグ中の場合
if(startDrag==true){
//マウス座標に差分を加えた値を円の座標に代入
x=mouseX+dx;
y=mouseY+dy;
}
//記録中の場合
if(startRecord==true){
xPos=append(xPos,x);//座標値を配列に付け加えていく
yPos=append(yPos,y);
}
//円を描画する
ellipse(x,y,r*2,r*2);
}
void mousePressed(){
//円中心座標とマウス座標の距離が円半径以内の場合
if(dist(x,y,mouseX,mouseY)<=r){
//ドラッグ用フラグをtrue(ドラッグ中)にする
startDrag=true;
//円の座標とマウス座標の差分を求めておく
dx=x-mouseX;
dy=y-mouseY;
}
}
void mouseReleased(){
//ドラッグ用フラグをfalse(ドラッグなし)にする
startDrag=false;
}
void keyPressed(){
//記録用の処理
if(key=='r'){//「r」キーを押した場合
if(startRecord==true){//記録中の場合
startRecord=false;//記録なしに戻す
fill(0,0,0);//円の塗色を黒に戻す
}else{//記録なしの場合
startRecord=true;//記録中にする
fill(255,0,0);//円の塗色を赤にする
}
}
//保存用の処理
if(key=='s'){//「s」キーを押した場合
//ファイル選択画面で保存先を決める
String savePath = selectOutput();
//保存先のパスが空ではないとき
if (savePath != null) {
//保存用のインスタンスを用意する
PrintWriter output;
//保存先にファイルを生成
output=createWriter(savePath);
//配列に含まれる値を出力する
for(int i=0;i<xPos.length;i++){
output.println(xPos[i]+","+yPos[i]);//X座標+コンマ+Y座標+改行
}
output.flush();//データ保存
}
}
//記録内容を消去する処理
if(key=='c'){//「c」キーを押した場合
xPos=clearArray;//X座標の配列に空の配列を代入し、内容を消去
yPos=clearArray;//Y座標の配列に空の配列を代入し、内容を消去
}
}
上記プログラムでは、
printWriterを使って外部ファイルとして座標値データを保存しています。「s」キーを押すと
selectOutput()によってダイアローグ画面が現れるので、保存名と保存先を指定します。「positions.txt」のように、「.txt」の拡張子をつけて任意の場所(デスクトップなど)に保存します。再度上書き保存する場合は、ダイアローグ画面上で、同じファイルを選択し保存ボタンを押します(上書き保存の確認メッセージが現れます)。
「円をドラッグ+記録機能+保存機能+再生機能」:次に、記録された内容や保存された内容のデータを読み取り、そのデータに基づいて動きを再生するプログラムをします。再生中は円の塗色が緑に変化し、再生終了すれば黒に戻ります。
まず、「r」キーを押して記録開始し、マウスで円をドラッグします(ドラッグ記録中)。
次に再度「r」キーを押して記録を停止します。
記録された内容を再生するために、「p」キーを押します。動きが再生されている間は円が緑色になります。
「s」キーを押すことで、記録内容を外部ファイルとしてデスクトップなどの任意の場所にファイル名(拡張子「.txt」)をつけて保存します。
「s」キーで保存されたファイルを読み込むには、「l」(小文字のエル)キーを押してファイル選択画面の中でファイル選択します。読み込んだファイルのデータは配列xPosとyPosに記憶されます。「p」キーを押せば、読み込んだ記録を再生します。
「c」キーによって、配列内のデータを空にしないかぎり、「r」キーによる記録した座標値は追加されていきます。
「各キーの機能割当」:
r:記録開始(record)/記録停止
c:記録消去(clear)
s:保存(save)
l:ファイル読み込み(load)
p:再生(play)
赤文字部分がさらに追加した再生機能の内容です。
[プログラムを表示]
//円のXY座標の変数を用意する
int x,y;
//円の座標とマウス座標の差分(ずれ)の変数
int dx,dy;
//ドラッグ開始終了のフラグ
boolean startDrag;
//円の半径
int r=30;
//記録中/記録停止のフラグ
boolean startRecord;
//座標記録用の配列を用意し、内容を空にしておく。
int[] xPos={};
int[] yPos={};
//消去用に空の配列を用意しておく
int[] clearArray={};
boolean startPlay;//再生用フラグ
int count;//再生用カウンタ変数
void setup(){
size(600,600);//画面サイズ設定
smooth();//滑らかな描画にする
stroke(255);//線色を白
fill(0);//塗り色を黒
x=width/2;//円を画面中心に配置しておく
y=height/2;
}
void draw(){
background(0);//背景色(黒)
//ドラッグ中の場合
if(startDrag==true){
//マウス座標に差分を加えた値を円の座標に代入
x=mouseX+dx;
y=mouseY+dy;
}
//記録中の場合
if(startRecord==true){
xPos=append(xPos,x);//座標値を配列に付け加えていく
yPos=append(yPos,y);
}
//再生中の場合
if(startPlay==true){
//カウンタ変数に合わせてXY座標の配列の値を円の座標に代入していく
x=xPos[count];
y=yPos[count];
fill(0,255,0);//塗色を緑にする
count++;//カウンタ変数を増加させる
if(count>xPos.length-1){//カウント数が配列データの個数以上になったら
startPlay=false;//再生停止にする
count=0;//カウンタ変数をゼロに戻す
println("Finish Playing");//再生終了の出力
fill(0);//塗色を黒に戻す
}
}
//円を描画する
ellipse(x,y,r*2,r*2);
}
void mousePressed(){
//円中心座標とマウス座標の距離が円半径以内の場合
if(dist(x,y,mouseX,mouseY)<=r){
//ドラッグ用フラグをtrue(ドラッグ中)にする
startDrag=true;
//円の座標とマウス座標の差分を求めておく
dx=x-mouseX;
dy=y-mouseY;
}
}
void mouseReleased(){
//ドラッグ用フラグをfalse(ドラッグなし)にする
startDrag=false;
}
void keyPressed(){
//記録用の処理
if(key=='r'){//「r」キーを押した場合
if(startRecord==true){//記録中の場合
startRecord=false;//記録なしに戻す
fill(0,0,0);//円の塗色を黒に戻す
}else{//記録なしの場合
startRecord=true;//記録中にする
fill(255,0,0);//円の塗色を赤にする
}
}
//保存用の処理
if(key=='s'){//「s」キーを押した場合
//ファイル選択画面で保存先を決める
String savePath = selectOutput();
//保存先のパスが空ではないとき
if (savePath != null) {
//保存用のインスタンスを用意する
PrintWriter output;
//保存先にファイルを生成
output=createWriter(savePath);
//配列に含まれる値を出力する
for(int i=0;i<xPos.length;i++){
output.println(xPos[i]+","+yPos[i]);//X座標+コンマ+Y座標+改行
}
output.flush();//データ保存
}
}
//記録内容を消去する処理
if(key=='c'){//「c」キーを押した場合
xPos=clearArray;//X座標の配列に空の配列を代入し、内容を消去
yPos=clearArray;//Y座標の配列に空の配列を代入し、内容を消去
}
//再生用の処理
if(key=='p'){
//記録されているデータがある場合
if(xPos.length>0){
startPlay=true;//再生中にする
}
}
//ファイルデータ読み込みの処理
if(key=='l'){//「l」キーを押した場合
//読み込みファイルパスの指定
String loadPath = selectInput();
//パスが空ではないとき
if (loadPath != null){
//座標用配列に空の配列を代入し、内容を消去しておく
xPos=clearArray;
yPos=clearArray;
//文字列の配列を用意し、データを行ごとに配列に代入する(読み込む)
String[] lines=loadStrings(loadPath);
//各行ごとに、文字列データをXとYの座標の数値に変換する
for (int i=0; i<lines.length; i++) {//行数の分だけ繰り返し処理する
//コンマ記号を境目に文字列データを分割し、数値用の配列に代入
int[] data=int(split(lines[i],','));
//数値用配列のはじめの値をX座標用配列に追加していく
xPos=append(xPos,data[0]);
//数値用配列のつぎの値をY座標配列に追加していく
yPos=append(yPos,data[1]);
}
}
}
}
「p」キーを押すことで、再生用フラグstartPlayがtrueになり、ループ内で再生用の処理が行われます。変数countを用意しループするごとにcountを+1ずつ増加させ、配列内の座標データをひとつずつ円の座標に代入していきます。配列内のデータ数を
xPos.lengthで調べ、最後のデータまで読み込んだら再生用フラグstartPlayをfalseにし再生停止させます。
「l」キーを押し、
selectInput()によってファイル選択画面が現れ、保存したファイルを選択します。選択したファイル内のデータを
loadStrings()によって、「X座標値+コンマ+Y座標値」という一行ずつの文字列を
split()でコンマ記号を境目として二つのデータに分けて、同時にそれら文字列を
int()で整数化し、
append()によって座標用の配列xPosとyPosに追加していきます(代入する前にxPosとyPosを空の配列にしておきます)。
誤作動が起こらないように、再生中はキー入力を禁止したり、読み込まれるファイルが相応しくない場合の例外処理などが実際には必要になりますが、今回のプログラムでは省略しています。
ダイヤテック (2008-06-26)
売り上げランキング: 19889
0 件のコメント:
コメントを投稿