導入すると以下の機能が追加されます.
- BGMとボイス・SEのボリューム調整機能
ボイスとSEは共通です. - ゲーム画面のスクリーンショット取得機能
自動的にIDをマスクすることもできます. - ゲームの描画処理を若干軽量化
環境にも依りますが,描画処理が滑らかになります.スクロール処理などで顕著. - ゲームの描画品質の変更機能
アンチエイリアスを切ることで描画速度が改善する可能性があります. - スクリーンサイズの変更が出来ます
50%から10%刻みの6段階の変更が可能です.
(タッチ操作は一切考慮に入れてないから正しく動作しないかも…) - フルスクリーンへの切り替えを追加してみました
esc/f11キーの他, 画面右上をクリックすることで復帰可能にしています. - フレームスキップ機構を追加してみました
処理が重い環境で試してみると良いかもしれません.
※チートツールではありません.あくまで,インターフェースの機能改善ツールであって,ゲームの中身には一切触れていません.また,筆者は自動化とかには興味ありません.
※今後パフォーマンス改善やボリューム設定機構がゲーム側で実装された場合,本スクリプトが競合を引き起こすかもしれません.(ゲームのリサイズ機能が実装されたら多分死ぬ)
※現状に不満がなければ無理に導入するものでもありません.どうしてもこれが必要な場合に限って渋々入れてください.
動作環境:
- firefox + GreaseMonkey
動作チェックはubuntu 14.04 64bit + firefox 47 64bitで行っています.
変なことはしていないからwindowsでも動くんじゃね? - HTML5の仕組みしか使っていないので,choromeでも動くかもしれない
chrome + Tampermonkey環境でも動くっぽ - ie?edge?safari?知らね
ライセンス
- MIT
ご自由に.その代わり作者は一切の責任を負いません.コードを読んで変なことをしていないことを確認し,その危険性についてよく理解した上でご利用ください.
右クリックメニューが有効となってしまう.
ゲーム上差し支えないものの,挙動が変化してしまうのはあまり嬉しくない.
ファイル
http://www.h2.dion.ne.jp/~defghi/shiro/shiro_fuku.user.js
↓新URL
http://defghi1977.html.xdomain.jp/tech/shiro/shiro_fuku.user.js
※GreaseMonkeyが有効だと勝手にインストール機構が動作する模様.
以下コード
// ==UserScript==
// @name shiro_fuku
// @namespace defghi1977
// @description 御城プロジェクト:REライフをほんのり快適にします
// @include http://assets.shiropro-re.net/html/Oshiro.html
// @include http://osapi.dmm.com/gadgets/ifr*
// @include http://www.dmm.com/netgame/social/-/gadgets/=/app_id=777106/
// @version 4.0
// @grant none
// ==/UserScript==
/*
written by DEFGHI1977
http://defghi1977-onblog.blogspot.jp/2016/04/re-js.html
追加される機能
・グラフィック描画タイミングの調整
ゲーム画面の描画が若干滑らかになります.
※トレードオフとして消費メモリが若干増加しています.
・BGM/効果音/音声ボリューム調整機能
・グラフィック描画品質変更機能
アンチエイリアス処理を切ることでゲームの処理負荷が軽減されるかもしれません.
※環境によっては却って処理速度が犠牲になる可能性もあります.
・ゲーム画面のサイズ変更機能
50%から10%刻みでの6段階で設定できます.ブラウザ側でのズーム指定をする必要がなくなりました.
・ゲームのフルスクリーン化
esc/F11キー等で元に戻せます.
・ゲームのスクリーンショットを撮ることが出来ます.
自動的にIDにマスクをかけることも出来ます.
*/
'use strict';
//ready to fullscreen
if (/http:\/\/www\.dmm\.com\/netgame\/social\/-\/gadgets\/=\/app_id=777106\//.test(location.href)) {
(function () {
var iframe = document.querySelector('#game_frame');
iframe.setAttribute('allowfullscreen', 'true');
iframe.allowfullscreen = true;
}) ();
return;
}
if (/http:\/\/osapi\.dmm\.com\/gadgets\/ifr/.test(location.href)) {
(function () {
var mo = new MutationObserver(function (mutations) {
mutations.every(function (mu) {
for (var i = 0, len = mu.addedNodes.length; i < len; i++) {
var node = mu.addedNodes[i];
if (node.id == 'oshiro') {
node.setAttribute('allowfullscreen', 'true');
node.allowfullscreen = true;
mo.disconnect();
return false;
}
}
return true;
});
});
mo.observe(document, {
childList: true,
subtree: true
});
}) ();
return;
} //main panel setting
(function () {
var version = '4.0';
var appName = '🏯城福';
var panel = document.createElement('div');
panel.className = 'shiro_fuku';
var s = panel.style;
s.fontSize = '10px';
s.fontWeight = 'bold';
s.textAlign = 'left';
s.color = 'white';
s.textShadow = '1px 1px 0 navy';
s.lineHeight = '30px';
document.body.insertBefore(panel, document.querySelector('.emscripten_border').nextElementSibling);
var ui = document.createElement('div');
ui.className = 'shiro_ui';
ui.textContent = appName + 'v' + version + ' ';
var su = ui.style;
su.position = 'relative';
su.zIndex = '1';
su.paddingLeft = '3px';
panel.appendChild(ui);
}) ();
//shiro_volume
(function (proto) {
var keyBGM = 'defghi1977.shiro_vol.bgm';
var keyEFC = 'defghi1977.shiro_vol.effect';
var audios = [
];
//ui settings
var ui = document.querySelector('.shiro_ui');
var rangeBGM = document.createElement('input');
rangeBGM.type = 'range';
rangeBGM.min = 0;
rangeBGM.max = 1;
rangeBGM.step = 0.1;
rangeBGM.title = 'BGMのボリュームを調整します';
rangeBGM.style.width = '75px';
rangeBGM.style.height = '1em';
rangeBGM.value = localStorage.getItem(keyBGM) || 1;
var rangeEFC = rangeBGM.cloneNode(false);
rangeEFC.value = localStorage.getItem(keyEFC) || 1;
rangeEFC.title = '効果音ボリュームを調整します';
//add ui
ui.appendChild(document.createTextNode('BG:'));
ui.appendChild(rangeBGM);
ui.appendChild(document.createTextNode('EF:'));
ui.appendChild(rangeEFC);
//events
function getEventListener(key) {
return function (e) {
localStorage.setItem(key, this.value);
syncAll();
}
}
rangeBGM.addEventListener('input', getEventListener(keyBGM));
rangeEFC.addEventListener('input', getEventListener(keyEFC));
//overrides to change volume when call play method
var op = proto.play;
proto.play = function () {
if (!this._captured) {
audios.push(this);
this._captured = true;
}
sync(this);
return op.apply(this, arguments);
}
function syncAll() {
audios.forEach(sync);
} //sound effects
function sync(audio) {
audio.volume = audio.loop ? rangeBGM.value : rangeEFC.value;
}
}) (HTMLAudioElement.prototype);
//shiro_skip & shiro_qa
(function () {
var width = 1280;
var height = 720;
//append interface
var ui = document.querySelector('.shiro_ui');
ui.appendChild(document.createTextNode('QA:'));
var qa = document.createElement('input');
qa.type = 'checkbox';
qa.checked = true;
qa.disabled = true;
qa.title = '描画品質を変更します';
ui.appendChild(qa);
ui.appendChild(document.createTextNode('FS:'));
var selSkip = document.createElement('select');
selSkip.innerHTML = '<option value="1">Full</option>'
+ '<option value="2">1/2</option>'
+ '<option value="3">1/3</option>';
selSkip.title = '描画頻度を変更します';
selSkip.disabled = true;
ui.appendChild(selSkip);
//customized screen
var panel = document.querySelector('.shiro_fuku');
var screen = document.createElement('canvas');
screen.id = 'shiro_screen';
screen.width = width;
screen.height = height;
screen.addEventListener('contextmenu', function (e) {
e.preventDefault();
});
var s = screen.style;
s.transform = 'translateZ(0)'; //force gpu
s.display = 'block';
s.boxShadow = '0 30px 0 0 indigo';
s.position = 'relative';
s.zIndex = 0;
panel.insertBefore(screen, panel.firstChild);
//hide original screen
document.querySelector('.emscripten_border').style.display = 'none';
//find inmemory screen
var proto = HTMLCanvasElement.prototype;
var ogc = proto.getContext;
var buffer;
var bctx;
proto.getContext = function () {
var ctx;
if (!buffer && !this.parentNode && this.width == width && this.height == height) {
//kill opacity of buffer(to lighten rendering)
ctx = ogc.call(this, '2d', {
alpha: false
});
buffer = this;
bctx = ctx;
init();
} else {
ctx = ogc.apply(this, arguments);
}
return ctx;
};
function init() {
//add quality changer
(function () {
qa.addEventListener('change', function () {
[
'imageSmoothingEnabled',
'mozImageSmoothingEnabled',
'webkitImageSmoothingEnabled',
'msImageSmoothingEnabled'
].forEach(function (prop) {
bctx[prop] = qa.checked;
});
});
qa.disabled = false;
}) ();
//render width frame skip
(function () {
var ra = requestAnimationFrame || mozRequestAnimationFrame || webkitRequestAnimationFrame || msRequestAnimationFrame;
var sctx = screen.getContext('2d', {
alpha: false
});
var fr = 0;
var skip = 1;
var draw = drawF;
selSkip.addEventListener('change', setSkip);
selSkip.addEventListener('keyup', setSkip);
function setSkip() {
skip = selSkip.value * 1;
draw = skip == 1 ? drawF : drawS;
}
setSkip();
selSkip.disabled = false;
function transfer() {
sctx.drawImage(buffer, 0, 0, screen.width, screen.height);
}
function drawF() {
transfer();
ra(draw);
}
function drawS() {
if (fr++ % skip == 0) {
transfer();
}
ra(draw);
} //start rendering
draw();
}) ();
//ignore rendering to original screen
var canvas = document.querySelector('#canvas');
var ctx = canvas.getContext('2d');
ctx.drawImage = ctx.clearRect = ctx.putImageData = function () {
};
}
}) ();
//shiro_zoom
(function () {
var key = 'defghi1977.shiro_zoom.value';
var panel = document.querySelector('.shiro_fuku');
var eb = document.querySelector('.emscripten_border');
var screen = document.querySelector('#shiro_screen');
var sstyle = screen.style;
var ui = document.querySelector('.shiro_ui');
ui.appendChild(document.createTextNode('ZM:'));
var selZoom = document.createElement('select');
selZoom.title = 'スクリーンの表示倍率を指定します';
selZoom.innerHTML = '<option value="1">100%</option>'
+ '<option value="0.9">90%</option>'
+ '<option value="0.8">80%</option>'
+ '<option value="0.7">70%</option>'
+ '<option value="0.6">60%</option>'
+ '<option value="0.5">50%</option>';
//screen zoom
var zoom = localStorage.getItem(key) * 1 || 1;
var xzoom;
var yzoom;
selZoom.value = zoom;
apply();
selZoom.addEventListener('change', apply);
selZoom.addEventListener('keyup', apply);
function apply() {
xzoom = yzoom = zoom = selZoom.value * 1;
localStorage.setItem(key, zoom);
sstyle.width = screen.width * xzoom + 'px';
sstyle.height = screen.height * yzoom + 'px';
}
ui.appendChild(selZoom);
//emulate mouse events
[
'mousedown',
'mouseup',
'mouseover',
'mouseout',
'mousemove',
'click',
'dblclick',
'wheel'
].forEach(function (type) {
panel.addEventListener(type, cancelEvents);
screen.addEventListener(type, createEmulator(type));
});
function cancelEvents(e) {
e.stopPropagation();
}
function createEmulator(type) {
var translate = getTranslator(type);
return function (e) {
e.stopPropagation();
e.preventDefault();
eb.dispatchEvent(translate(e));
};
}
function getTranslator(type) {
var eConstructor = type == 'wheel' ? WheelEvent : MouseEvent;
var param = {
//by Event
bubbles: null,
cancelable: null,
//by UIEvent
detail: null,
view: null,
//by MouseEvent
screenX: null,
screenY: null,
clientX: null,
clientY: null,
ctrlKey: null,
shiftKey: null,
altKey: null,
metaKey: null,
button: null,
buttons: null,
relatedTarget: null,
region: null,
//by WheelEvent
deltaX: null,
deltaY: null,
deltaZ: null,
deltaMode: null
};
return function (e) {
for (var i in param) {
param[i] = e[i];
}
param.clientX = (param.clientX - 5) / xzoom + 5;
param.clientY /= yzoom;
param.relatedTarget = document.body;
return new eConstructor(type, param);
}
} //fullscreen
document.addEventListener('fullscreenchange', onfullscreenchange);
document.addEventListener('webkitfullscreenchange', onfullscreenchange);
document.addEventListener('msfullscreenchange', onfullscreenchange);
function onfullscreenchange() {
if (document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement) {
//spread screen
sstyle.width = '100%';
sstyle.height = '100%';
var cs = getComputedStyle(screen);
var w = cs.width.replace(/px/, '') * 1;
var h = cs.height.replace(/px/, '') * 1;
//culcurate zoom
xzoom = w / screen.width;
yzoom = h / screen.height;
} else {
//reset zoom
apply();
}
}
}) ();
//shiro_fullscreen
(function () {
var panel = document.querySelector('.shiro_fuku');
var screen = document.querySelector('#shiro_screen');
var ui = document.querySelector('.shiro_ui');
var fs = document.createElement('input');
fs.type = 'button';
fs.title = '画面をフルスクリーンに切り替えます';
fs.value = 'FS';
ui.appendChild(fs);
fs.addEventListener('click', function () {
try {
if (screen.requestFullscreen) {
screen.requestFullscreen();
} else if (screen.webkitRequestFullScreen) {
screen.webkitRequestFullScreen();
} else {
return;
}
exit.style.display = 'block';
} catch (e) {
}
});
screen.addEventListener('click', function(e){
console.log([window.screen.width - e.clientX,window.screen.height - e.clientY]);
var isFullscreen = document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
if(isFullscreen && window.screen.width - e.screenX < 25 && e.screenY < 25){
if (document.exitFullscreen) {
document.exitFullscreen()
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
}
}
});
}) ();
//shiro_shot
(function () {
var ui = document.querySelector('.shiro_ui');
var button = document.createElement('input');
button.type = 'button';
button.value = 'as is';
button.title = '画面をそのまま出力します';
button.addEventListener('click', shot);
var buttonM = document.createElement('input');
buttonM.type = 'button';
buttonM.value = 'mask';
buttonM.title = 'IDを隠します';
buttonM.addEventListener('click', shot);
var link = document.createElement('a');
link.download = 'shiro_shot.png';
var canvas = document.createElement('canvas');
ui.appendChild(document.createTextNode('SS:'));
ui.appendChild(button);
ui.appendChild(buttonM);
ui.appendChild(link);
function shot(e) {
var game = document.querySelector('#shiro_screen') || document.querySelector('#canvas');
canvas.width = game.width;
canvas.height = game.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(game, 0, 0);
if (e.target === buttonM) {
ctx.fillStyle = '#2e0f06';
ctx.fillRect(210, 5, 210, 24);
}
if (link.href) {
URL.revokeObjectURL(link.href);
}
canvas.toBlob(function (blob) {
link.href = URL.createObjectURL(blob);
link.click();
}, 'image/png');
}
}) ();
0 件のコメント:
コメントを投稿