jsPsych上でp5jsを使う
結論
p5js のインスタンスモードを jspsych プラグイン内で使う。
デモ
準備
CDNを使う、p5.min.jsをダウンロードして使う、など。
jsPsychのjsファイルを読み込む前に、p5.jsを読み込む必要があります。
Cognition.runの場合
External JS/CSSにp5.min.jsをアップロードすれがOK
コード
jsPsych 6.3用です。jsPsych 7には使えないと思います。
code:javascript
// p5オブジェクト
// プラグイン終了時にメモリを開放するため、プラグイン外に宣言。詳細は下に。
let myp5;
// プラグインの定義
// plugin-nameはわかりやすいように適当に決めればよい
var plugin = {};
plugin.info = {
name: 'plugin-name',
parameters: {
// パラメータが必要ならここで指定
}
}
// これがプラグインの本体
plugin.trial = function(display_element, trial){
// 時間になったら関数を終了する
let end_trial = function () {
jsPsych.pluginAPI.clearAllTimeouts();
display_element.innerHTML = "";
jsPsych.finishTrial();
// プラグイン終了時に p5js も閉じる
// ※ これ入れとかないと多分メモリリークします
myp5.remove();
};
// trial_duration が指定されてる場合は、その時間経過したら終了する
if (trial.trial_duration !== null) {
jsPsych.pluginAPI.setTimeout(function () {
end_trial();
}, trial.trial_duration);
};
// p5jsのオブジェクト
let sketch = function (p) {
//ーーーーーーーーーーーーーーーーーーーーーーーーーー
// ここに p5js をインスタンスモードで sketch する。
// pがp5jsのインスタンスなので、p.hogehogeでp5jsが公開しているオブジェクトにアクセス可能
p.setup = function () {
p.createCanvas(400, 400);
}
p.draw = function () {
p.background(220);
};
//
//ーーーーーーーーーーーーーーーーーーーーーーーーーー
};
// p5オブジェクトを作成
myp5 = new p5(sketch, display_element);
};
return plugin;
})();
// jspysch の timline で p5js を呼び出す関数
let p5_trial = {
type: 'plugin-name', //''内の文字列は上のプラグイン名前と同じにする
trial_duration: 2000, // 2000ms 刺激を表示する設定
};
記事内での目的
jsPsych で p5js を使いたい。
これにより、例えば以下のようなの利点が得られる。
1. p5js の簡単なコードで綺麗な実験刺激を作る
2. 教示文のレイアウトを css や htlm を使わないで、簡単に綺麗にする
3. cognition.run や codepen で簡単にウェブ実験を作成、テスト、修正、共有できる
インスタンスモードとは
インスタンスモードはいつも通り p5js コード書いた後、 p5js 独自の変数を「 p.変数 」のように頭に p. を追加することで可能となる。冒頭のデモコードでは p5js の新規ファイルを開いた際にいつも書かれている「400*400 で背景色 220 のキャンバスを開く」という内容をプラグインにしてある。timline では「2000ms 表示する」設定にしてある。
jspsych にインスタンスモードの p5js コードを実装する方法
p5js で作った刺激や教示を jspsych のプラグインの中にコピペする。
p5jsのオブジェクト(定数、関数)を呼び出している箇所は、全てp5.hogehogeと書き換える。
jsPsych の timeline でプラグインを呼び出す。
timline で何度も p5js を呼び出すことでメモリを圧迫、正しく描画されなくなる問題
p5jsをつかう試行を繰り返す際に、そのままだとメモリリークが起きる(多分。インスタンスモードのp5jsオブジェクトをつくるとcanvasを開くためだと思われる)。
p5js の remove() をプラグイン終了時に呼び出すことで解決できる。
p5js の remove() をプラグイン終了時に呼び出すためには、 myp5をplugin.trial = function(display_element, trial){}の内部ではなく、外で宣言する必要がある様です。
これにより、試行数が増えても p5js が重複してメモリを圧迫してしまう問題を解決できるようです。
code:javascript
// ここで宣言
let myp5;
// ここで宣言するなら大丈夫かもしれない(未検証)
// let myp5;
plugin.trial = function(display_element, trial){
// ここで宣言してもだめ
// let myp5;
let end_trial = function () {
myp5.remove();
};
let sketch = function (p) {
p.setup = function () {
};
p.draw = function () {
};
};
myp5 = new p5(sketch, display_element);
};
return plugin;
})();
参考
執筆:喜田(2021年10月13日)