TweenプラグインのTorigoya_Tween.jsが便利

ウィンドウをアニメーションさせたく、updateメソッド内でちまちま動かしていた。
しかし、さすがに汎用性に欠けるし、コードが複雑になりすぎる。
jQueryのanimateメソッドみたいな、UnityでいうiTweenみたいなプラグインないかなと思っていたら、まさにそのとおりのがあった。
鳥小屋.txtさんのTorigoya_Tween.jsだ。

例えば、以下のようなスクリプトでこんな感じのアニメーションができる。

1
2
3
4
5
6
7
8
9
10
11
var height = 200;
var window = new Window_Base(0, Graphics.height, Graphics.width, height);
window.opacity = 0;
SceneManager._scene.addWindow(window);
var toY = Graphics.height - height;
Torigoya.Tween.create(window)
.to({y: toY - 20, opacity: 255}, 15, Torigoya.Tween.Easing.easeOutSine)
.to({y: toY}, 5, Torigoya.Tween.Easing.easeInSine)
.wait(60)
.to({opacity: 0}, 60, Torigoya.Tween.Easing.linear)
.start();

超便利。すばらしー。

easingがどんなのかわからないときは、ここが参考になる。

簡易メッセージプラグイン

VX Aceに同じようなのがあったけど、MVで見つからなかったので自作した。
以下みたいな感じです。

スクリプトコマンドで以下のように指定して使います。
TickerManager.show(‘\I[5]あいうえお’);

ソースは以下です。
https://raw.githubusercontent.com/kido0617/rpgmakerMV-plugin/master/Ticker/Ticker.js

ニュースティッカー的な感じだから、Tickerという名前。

ライセンス

完全に自由にどうぞ。
クレジットの表記もいりません。

loadBitmapを使うときはsmoothに注意する

画像をスクリプトから読み込むときにImageManager.loadBitmapを使う。
これを使って、画像を表示するには以下のようなコードをスクリプトコマンドから実行すれば良い。

1
2
3
var bitmap = ImageManager.loadBitmap("img/sample/", "a");
var sprite = new Sprite(bitmap);
SceneManager._scene.addChild(sprite);

画像を表示

ここで、例えば、画像を80%で表示するとする。そういうときは、spriteのscaleをいじれば良い。
しかし、このままだと縮小された画像にジャギーが発生する。以下のコードと画像を参照。

1
2
3
4
5
var bitmap = ImageManager.loadBitmap("img/sample/", "a");
var sprite = new Sprite(bitmap);
sprite.scale.x = 0.8;
sprite.scale.y = 0.8;
SceneManager._scene.addChild(sprite);

ジャギーが発生

これを抑止するには、loadBitmapの第4引数(smooth)をtrueにすれば良い。第3引数は色相なので使わなければnull。
以下のようにコードを変更すれば、ジャギーなく表示できる。

1
2
3
4
5
var bitmap = ImageManager.loadBitmap("img/sample/", "a", null, true);
var sprite = new Sprite(bitmap);
sprite.scale.x = 0.8;
sprite.scale.y = 0.8;
SceneManager._scene.addChild(sprite);

ジャギーがない

ちなみに、内部的に何が変わるのかという話だけど、Bitmapの以下の箇所で分岐する。

1
2
3
4
5
if (this._smooth) {
this._baseTexture.scaleMode = PIXI.SCALE_MODES.LINEAR;
} else {
this._baseTexture.scaleMode = PIXI.SCALE_MODES.NEAREST;
}

PIXIのテクスチャーのscaleModeがLINEARかNEARESTの違い。
多分、バイリニア法かニアレストネイバー法使うかの差っぽい。
それぞれ検索するとどんな感じか出るのでそちらを参照

独自のデータをセーブする

はじめに

ツクールMVのセーブデータはjson。正確には以下のコードのようにLZStringライブラリを使って、Base64にしつつ圧縮している。

1
LZString.compressToBase64(json);

自分の好きなデータを保存したい場合、既にある$gameSystemとか$gameVariablesといった変数に付け足す方法がある。
デフォルトで入っているアイテム図鑑プラグインのItemBook.jsは$gameSystemを拡張して、アイテムの取得済みかどうかを保存している。以下のようにGame_System($gameSystem)に_itemBookFlagsを追加している。

1
2
3
Game_System.prototype.clearItemBook = function() {
this._ItemBookFlags = [[], [], []];
};

この方法でも問題ないが、がっつり独自のセーブデータを作った方がいいケースもある。その方法を解説する。

DataManagerを拡張

ツクールのセーブする変数は$gameで始まるのでそれにのっとる。今回は、$gameMyというのを作る。
必要なのは、初期化、セーブ、ロード、の3つ。
以下のような感じになる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
(function(){
window.$gameMy = {};

var _createGameObjects = DataManager.createGameObjects;
DataManager.createGameObjects = function() {
_createGameObjects.call(this);
$gameMy = new Game_My();
};

var _makeSaveContents = DataManager.makeSaveContents;
DataManager.makeSaveContents = function() {
var contents = _makeSaveContents.call(this);
contents.gameMy = $gameMy;
return contents;
};
var _extractSaveContents = DataManager.extractSaveContents;
DataManager.extractSaveContents = function(contents) {
_extractSaveContents.call(this, contents);
$gameMy = contents.gameMy;
};

function Game_My(){
this.saveSomething = "aaa"; //自由にデータを追加できる
}
})();

これでGame_My($gameMy)を通して自由にデータを追加して保存できる。

Google Apps Script で6分以上の処理をする

複数のスプレッドシートを集計したりするのにGoogle Apps Script(GAS)を使うことはよくあります。
ですが、GASは6分という制限時間があり、度々それに悩まされます。
6分を超えると「起動時間の最大値を超えました」とエラーが吐かれ、途中で処理が終了してしまいます。
これを解決する方法として、処理を途中で止め、どこまで処理したかを保存し、1分後に再度実行するようにトリガーを発行するという方法があります。
どこまで処理したかを保存できるような作りでないといけないという制約はあります。
例えば、行毎に処理しているならば、何行まで処理したかを保存しておけば良いということです。
どこに保存するかというと、PropertiesServiceというところにKey-Valueで保存できます。
トリガーは発行すると以下の図のようにずっとトリガー一覧に残ってしまいます。残っていても害はないのですが、邪魔なので削除する処理も入れます。

トリガー

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
function func() {
var startTime = new Date();

//タイマーで起動するのでgetActiveSheet()などは使えない
var sheet = SpreadsheetApp.openById("1W3lfUaF_9msFJ2oRETpKMTvbF_xxxxxxxxxxxxx").getSheetByName("シート1");
var properties = PropertiesService.getScriptProperties(); //途中経過保存用
var startRowKey = "startRow"; //何行目まで処理したかを保存するときに使用するkey
var triggerKey = "trigger"; //トリガーIDを保存するときに使用するkey

//途中から実行した場合、ここに何行目まで実行したかが入る
var startRow = parseInt(properties.getProperty(startRowKey));
if(!startRow){
//初めて実行する場合はこっち
startRow = 1;
}

var rows = sheet.getDataRange().getValues();
for(var i = startRow; i < rows.length; i++){
var diff = parseInt((new Date() - startTime) / (1000 * 60));
if(diff >= 5){
//5分経過していたら処理を中断
properties.setProperty(startRowKey, i); //何行まで処理したかを保存
setTrigger(triggerKey, "func"); //トリガーを発行
return;
}
//なんか重い処理
}

//全て実行終えたらトリガーと何行目まで実行したかを削除する
deleteTrigger(triggerKey);
properties.deleteProperty(startRowKey);
}

//指定したkeyに保存されているトリガーIDを使って、トリガーを削除する
function deleteTrigger(triggerKey) {
var triggerId = PropertiesService.getScriptProperties().getProperty(triggerKey);

if(!triggerId) return;

ScriptApp.getProjectTriggers().filter(function(trigger){
return trigger.getUniqueId() == triggerId;
})
.forEach(function(trigger) {
ScriptApp.deleteTrigger(trigger);
});
PropertiesService.getScriptProperties().deleteProperty(triggerKey);
}

//トリガーを発行
function setTrigger(triggerKey, funcName){
deleteTrigger(triggerKey); //保存しているトリガーがあったら削除
var dt = new Date();
dt.setMinutes(dt.getMinutes() + 1); //1分後に再実行
var triggerId = ScriptApp.newTrigger(funcName).timeBased().at(dt).create().getUniqueId();
//あとでトリガーを削除するためにトリガーIDを保存しておく
PropertiesService.getScriptProperties().setProperty(triggerKey, triggerId);
}

ちなみにですが、https://developers.google.com/apps-script/guides/services/quotasによると、Early Accessだと実行時間は30分になります。
条件満たしていたので会社で申請したら、2週間ぐらい経って、通って30分になりました。