目玉がカーソルを追いかけるやつ
こんにちは、目玉の話です。皆さんは目玉ですか?(パル文体)
この↓ツイがちょいバズったんで、需要があるのかなと思い、開発環境の導入とプログラムの解説をします。あなたも一瞬でできます。40分かかりません。
言語・開発環境は「Processing」です。私は長年のProcessingユーザーなのです。言語はほぼJavaですが、構成はArduino IDEみたいな感じです(なぜならば同じ由来と思想を持つからです)。インタラクティブアート用に作られたらしく、お絵かきとかリアルタイムにぐりぐり動かすのとかをやりやすくなってます。
ここからProcessingをダウンロードします。寄付はご自由に。
https://processing.org/download/
Zipで落ちてくるので、解凍したフォルダ内にあるexeファイルをクリックするともう始められます。クリックする。
yeah
プログラムファイルは「.pde」という拡張子を持ちます。あと、プロジェクト名とフォルダ名が一致している必要があります。
まず「名前を付けて保存」で「CTEv1」(cursor tracking eyes version 1) とでも名前を付けてください。なんでもいいです。
そして、次のコードをコピペしてください。
int x0 = 20, y0 = 30;
int[] sph_center_x = { 80,145,180,240,280};
int[] sph_center_y = {200,105,180,250,130};
int[] sph_diameter = { 60,55,70,60,60};
int[] eye_center_x = { 75,150,180,242,283};
int[] eye_center_y = {195,105,170,253,130};
int[] eye_diameter = {30,25,35,30,30};
int[] iris_diameter = {15,15,18,13,15};
float dfac = 0.04;
void settings() {
size(400,400);
}
void setup() {
background(255);
ellipseMode(CENTER);
noStroke();
}
void draw() {
// GRAY
fill(100,100,100);
for(int n=0;n<5;n++) {
ellipse(sph_center_x[n]+x0, sph_center_y[n]+y0, sph_diameter[n], sph_diameter[n]);
}
// WHITE
fill(255);
for(int n=0;n<5;n++) {
ellipse(eye_center_x[n]+x0, eye_center_y[n]+y0, eye_diameter[n], eye_diameter[n]);
}
// BLUE
fill(40,80,200);
for(int n=0;n<5;n++) {
int dx = mouseX-(eye_center_x[n]+x0);
int dy = mouseY-(eye_center_y[n]+y0);
float ang = atan2(dy,dx);
float dis = sqrt(pow(dx,2)+pow(dy,2));
float ndis = min(dfac*dis,eye_diameter[n]/2.0-iris_diameter[n]/2.0);
float nx = ndis*cos(ang); // as float
float ny = ndis*sin(ang);
ellipse(eye_center_x[n]+x0+nx, eye_center_y[n]+y0+ny, iris_diameter[n], iris_diameter[n]);
}
}
コピペしたら上書き保存して、実行ボタン(▶)を押したら実行されます。
はい
やったね!
(赤いアレだとナニなので灰色にした)
さて、プログラムの内容はめちゃ簡単です。Processingでは関数settings()、setup()、draw()がこの順番で実行されます。
settings()で画面のサイズの設定をします。setup()では背景色とか配置の設定とか色の設定とかそういうのをしています。draw()はプログラム実行中ひたすら繰り返し呼び出される関数なので、ここに描画処理を入れます。
そんで、draw()の中身ですが、"// GRAY"、"// WHITE"、"// BLUE"の箇所でそれぞれ灰・白・青のパーツを描画してます。今回動くのは青のやつだけなので、それの解説だけしときます。
// BLUE
fill(40,80,200);
for(int n=0;n<5;n++) {
int dx = mouseX-(eye_center_x[n]+x0);
int dy = mouseY-(eye_center_y[n]+y0);
float ang = atan2(dy,dx);
float dis = sqrt(pow(dx,2)+pow(dy,2));
float ndis = min(dfac*dis,eye_diameter[n]/2.0-iris_diameter[n]/2.0);
float nx = ndis*cos(ang); // as float
float ny = ndis*sin(ang);
ellipse(eye_center_x[n]+x0+nx, eye_center_y[n]+y0+ny, iris_diameter[n], iris_diameter[n]);
}
目玉が5個あるので、for文で処理を5周させてます。まず、現在のマウスカーソルの位置と白目の中心の座標の差を計算します。
mouseX, mouseYはマウスカーソルのx座標(水平位置)とy座標(垂直位置)を持ってる変数です。Processingにはこういうのがあらかじめ用意されてるんですよ。便利ですね。
int dx = mouseX-(eye_center_x[n]+x0);
int dy = mouseY-(eye_center_y[n]+y0);
そんで、その角度(目玉中心からカーソル点まで引いた直線がなす角度)をアークタンジェント(逆正接)を使って求めます。また、その距離をピタゴラって(エウクレイデって?)求めます。
float ang = atan2(dy,dx);
float dis = sqrt(pow(dx,2)+pow(dy,2));
青いやつ(目玉の虹彩)を、この角度で、この距離の何分の1かのところに置けば、カーソルを追っかけて見えますよね。ただし、白目をはみ出してはいかんので、距離の調整をします。ここでは距離を0.03倍(dfac倍)にして、かつ白目の円周からはみ出さないように制限してます。
float ndis = min(dfac*dis,eye_diameter[n]/2.0-iris_diameter[n]/2.0);
そして最後にcosとsinで青玉の位置を求めます。
float nx = ndis*cos(ang); // as float
float ny = ndis*sin(ang);
できた!
何で40分かかったかっちゅーと、赤丸の配置を座標を色々試して人力探索したからです。
よかったですね。
この記事が気に入ったらサポートをしてみませんか?