更新:2022年8月16日 HSPトップへもどる
HSP製 Webアプリの実体は JavaScript を含んだ htmlファイルです。
自分の作ったオリジナルのスクリプトがこの部分に変換されます。
それに加えて
プログラムエンジンとなる hsp3dish.js
まとめた素材データ test.data
の3つのファイルでWebアプリがブラウザから実行されます。
・HSPスクリプトエディタで .hsp スクリプトを作成
↓
・HSP3Dish helper で 変換
↓
・ .html ができる。
#include "hsp3dish.as"
title "いちばん簡単なスクリプト"
*main
redraw 0
pos 10,100 : mes "みなさん こんにちは"
redraw 1
await 100
goto *main
↓ これを HSP3Dish helper で .html に変換すると
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>minimum - HSP3Dish</title>
<style>
body {
font-family: arial;
margin: 0;
padding: none;
}
.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
div.emscripten { text-align: center; }
div.emscripten_border { border: 1px solid black; }
/* the canvas *must not* have any border or padding, or mouse coords will be wrong */
canvas.emscripten { border: 0px none; }
#emscripten_logo {
display: inline-block;
margin: 0;
}
.spinner {
height: 30px;
width: 30px;
margin: 0;
margin-top: 20px;
margin-left: 20px;
display: inline-block;
vertical-align: top;
-webkit-animation: rotation .8s linear infinite;
-moz-animation: rotation .8s linear infinite;
-o-animation: rotation .8s linear infinite;
animation: rotation 0.8s linear infinite;
border-left: 5px solid rgb(235, 235, 235);
border-right: 5px solid rgb(235, 235, 235);
border-bottom: 5px solid rgb(235, 235, 235);
border-top: 5px solid rgb(120, 120, 120);
border-radius: 100%;
background-color: rgb(189, 215, 46);
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(360deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(360deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(360deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(360deg);}
}
#status {
display: inline-block;
vertical-align: top;
margin-top: 30px;
margin-left: 20px;
font-weight: bold;
color: rgb(120, 120, 120);
}
#progress {
height: 20px;
width: 30px;
}
#controls {
display: inline-block;
float: right;
vertical-align: top;
margin-top: 30px;
margin-right: 20px;
}
#output {
width: 100%;
height: 200px;
margin: 0 auto;
margin-top: 10px;
display: block;
background-color: black;
color: white;
font-family: 'Lucida Console', Monaco, monospace;
outline: none;
}
</style>
</head>
<body>
<div class="spinner" id='spinner'></div>
<div class="emscripten" id="status">Downloading...</div>
<span id='controls'>
<span><input type="hidden" id="resize"></span>
<span><input type="hidden" id="pointerLock"></span>
<span><input type="hidden" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked,
document.getElementById('resize').checked)">
</span>
</span>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<div class="emscripten_border">
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
</div>
<textarea id="output" rows="8"></textarea>
<script type='text/javascript'>
var statusElement = document.getElementById('status');
var progressElement = document.getElementById('progress');
var spinnerElement = document.getElementById('spinner');
var Module = {
INITIAL_MEMORY: 209715200,
preRun: [],
postRun: [],
print: (function() {
var element = document.getElementById('output');
if (element) element.value = ''; // clear browser cache
return function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
// These replacements are necessary if you render to raw HTML
//text = text.replace(/&/g, "&");
//text = text.replace(/</g, "<");
//text = text.replace(/>/g, ">");
//text = text.replace('\n', '<br>', 'g');
console.log(text);
if (element) {
element.value += text + "\n";
element.scrollTop = element.scrollHeight; // focus on bottom
}
};
})(),
printErr: function(text) {
text = Array.prototype.slice.call(arguments).join(' ');
if (0) { // XXX disabled for safety typeof dump == 'function') {
dump(text + '\n'); // fast, straight to the real console
} else {
console.error(text);
}
},
canvas: document.getElementById('canvas'),
setStatus: function(text) {
if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
if (text === Module.setStatus.text) return;
var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
var now = Date.now();
if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
if (m) {
text = m[1];
progressElement.value = parseInt(m[2])*100;
progressElement.max = parseInt(m[4])*100;
progressElement.hidden = false;
spinnerElement.hidden = false;
} else {
progressElement.value = null;
progressElement.max = null;
progressElement.hidden = true;
if (!text) spinnerElement.style.display = 'none';
}
statusElement.innerHTML = text;
},
totalDependencies: 0,
monitorRunDependencies: function(left) {
this.totalDependencies = Math.max(this.totalDependencies, left);
Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
},
arguments: ["minimum.ax"]
};
Module.setStatus('Downloading...');
/* block.js */
var Module;
if (typeof Module === 'undefined') Module = eval('(function() { try { return Module || {} } catch(e) { return {} } })()');
if (!Module.expectedDataFileDownloads) {
Module.expectedDataFileDownloads = 0;
Module.finishedDataFileDownloads = 0;
}
Module.expectedDataFileDownloads++;
(function() {
var PACKAGE_PATH;
if (typeof window === 'object') {
PACKAGE_PATH = window['encodeURIComponent'](window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
} else {
// worker
PACKAGE_PATH = encodeURIComponent(location.pathname.toString().substring(0, location.pathname.toString().lastIndexOf('/')) + '/');
}
var PACKAGE_NAME = 'minimum.data';
var REMOTE_PACKAGE_NAME = (Module['filePackagePrefixURL'] || '') + 'minimum.data';
var REMOTE_PACKAGE_SIZE = 312;
var PACKAGE_UUID = '51f84d03-0c74-4552-ac13-924e79e76977';
function fetchRemotePackage(packageName, packageSize, callback, errback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', packageName, true);
xhr.responseType = 'arraybuffer';
xhr.onprogress = function(event) {
var url = packageName;
var size = packageSize;
if (event.total) size = event.total;
if (event.loaded) {
if (!xhr.addedTotal) {
xhr.addedTotal = true;
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
Module.dataFileDownloads[url] = {
loaded: event.loaded,
total: size
};
} else {
Module.dataFileDownloads[url].loaded = event.loaded;
}
var total = 0;
var loaded = 0;
var num = 0;
for (var download in Module.dataFileDownloads) {
var data = Module.dataFileDownloads[download];
total += data.total;
loaded += data.loaded;
num++;
}
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
if (Module['setStatus']) Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
} else if (!Module.dataFileDownloads) {
if (Module['setStatus']) Module['setStatus']('Downloading data...');
}
};
xhr.onload = function(event) {
var packageData = xhr.response;
callback(packageData);
};
xhr.send(null);
};
function handleError(error) {
console.error('package error:', error);
};
var fetched = null, fetchedCallback = null;
fetchRemotePackage(REMOTE_PACKAGE_NAME, REMOTE_PACKAGE_SIZE, function(data) {
if (fetchedCallback) {
fetchedCallback(data);
fetchedCallback = null;
} else {
fetched = data;
}
}, handleError);
function runWithFS() {
function assert(check, msg) {
if (!check) throw msg + new Error().stack;
}
function DataRequest(start, end, crunched, audio) {
this.start = start;
this.end = end;
this.crunched = crunched;
this.audio = audio;
}
DataRequest.prototype = {
requests: {},
open: function(mode, name) {
this.name = name;
this.requests[name] = this;
Module['addRunDependency']('fp ' + this.name);
},
send: function() {},
onload: function() {
var byteArray = this.byteArray.subarray(this.start, this.end);
this.finish(byteArray);
},
finish: function(byteArray) {
var that = this;
Module['FS_createPreloadedFile'](this.name, null, byteArray, true, true, function() {
Module['removeRunDependency']('fp ' + that.name);
}, function() {
if (that.audio) {
Module['removeRunDependency']('fp ' + that.name); // workaround for chromium bug 124926 (still no audio with this, but at least we don't hang)
} else {
Module.printErr('Preloading file ' + that.name + ' failed');
}
}, false, true); // canOwn this data in the filesystem, it is a slide into the heap that will never change
this.requests[this.name] = null;
},
};
new DataRequest(0, 312, 0, 0).open('GET', 'minimum.ax');
function processPackageData(arrayBuffer) {
Module.finishedDataFileDownloads++;
assert(arrayBuffer, 'Loading data file failed.');
var byteArray = new Uint8Array(arrayBuffer);
var curr;
// copy the entire loaded file into a spot in the heap. Files will refer to slices in that. They cannot be freed though.
var ptr = Module['_malloc'](byteArray.length);
Module['HEAPU8'].set(byteArray, ptr);
DataRequest.prototype.byteArray = Module['HEAPU8'].subarray(ptr, ptr+byteArray.length);
DataRequest.prototype.requests["minimum.ax"].onload();
Module['removeRunDependency']('datafile_minimum.data');
};
Module['addRunDependency']('datafile_minimum.data');
if (!Module.preloadResults) Module.preloadResults = {};
Module.preloadResults[PACKAGE_NAME] = {fromCache: false};
if (fetched) {
processPackageData(fetched);
fetched = null;
} else {
fetchedCallback = processPackageData;
}
ENV.HSP_WX = "320";//スクリプトの動作解像度
ENV.HSP_WY = "480";
ENV.HSP_SX = "320";//表示解像度
ENV.HSP_SY = "480";
ENV.HSP_AUTOSCALE = "0";//スケーリングモード
ENV.HSP_FPS = "0";//フレームレート
ENV.HSP_LIMIT_STEP = "15000";//ブラウザに処理を返すまでの実行ステップ数
}
if (Module['calledRun']) {
runWithFS();
} else {
if (!Module['preRun']) Module['preRun'] = [];
Module["preRun"].push(runWithFS); // FS is not initialized yet, wait for it
}
})();
var fixAudioContext = function (e) {
SDL.openAudioContext();
var context = SDL.audioContext;
if (context) {
// Create empty buffer
var buffer = context.createBuffer(1, 1, 22050);
var source = context.createBufferSource();
source.buffer = buffer;
// Connect to output (speakers)
source.connect(context.destination);
// Play sound
if (source.start) {
source.start(0);
} else if (source.play) {
source.play(0);
} else if (source.noteOn) {
source.noteOn(0);
}
//const soundEffect = new Audio();
//soundEffect.play();
console.log('audio unlock:');
}
var target = document;
//var target = document.getElementById('canvas');
// Remove events
target.removeEventListener('touchstart', fixAudioContext);
target.removeEventListener('touchend', fixAudioContext);
target.removeEventListener('mousedown', fixAudioContext);
};
//var target = document.getElementById('canvas');
var target = document;
// iOS 6-8
target.addEventListener('touchstart', fixAudioContext);
// iOS 9
target.addEventListener('touchend', fixAudioContext);
target.addEventListener('mousedown', fixAudioContext);
</script>
<script async type="text/javascript" src="hsp3dish.js"></script>
<p><font size="2" color="#404040">powered by <a href="https://hsp.tv/make/hsp3dish.html" target="_blank">hsp3dish.js</a> / OpenHSP</font></p>
</body>
</html>
※ HSP3Dish helper は HSP3.7ベータ2付属の ver.1.94 を使用。
↑このページでは見づらいので、自分のテキストエディタにコピー貼り付けして横幅の広い画面でみると見やすいです。
この .htmlファイルは開発者が自由に編集してかまいません
これまでに ホームページを作ったことがなかったり、HTML タグを見たことがなかったり、JavaScript を勉強した経験がないと、どこを修正してよいのか、わけがわからなくて心配になるかもしれません。
「なかみを書き換えて変更したら、動かなくなっちゃうんじゃないかな…?」
という不安があるかもしれませんが、一つづつゆっくり見ていけば、それほどむずかしくはありません。
よくみると HSPでいうところの「命令」と似ている htmlの「タグ」は、
・ここからタグの命令がはじまりますよ
・ここまででタグの命令はおわりですよ
<title> かんたんサンプル </title>
<script> </script>
のように、それぞれの命令が「開始のしるし」「終了のしるし」一組づつになって、それがたくさんあつまっているだけです。
おおまかに言うと、HSPスクリプトエディタで作ったプログラムの部分は、変換されて、まんなかの
<script> </script> のあいだに含まれています。
さいしょは、それ以外の部分を編集、追記、修正していくとよいかもしれません。
たとえば、アプリ画面の下部に、ゲームの説明文章を表示するだけでも親切で役に立つかもしれません。
.html を編集するときは、テキストエディタ(アプリ)を使用するのが良いです。
「テキストエディタ」はネットで検索するといろいろ無料のものが出てきます。
自分の好きなモノ、安全なモノを使用しましょう。
Webサイト用 htmlファイルを編集するのに特化したアプリもあります。
ざんねんながら付属の「HSPスクリプトエディタ」では日本語文字が化けてコメントなど読みにくくなるので「htmlファイルを編集する」という目的では使いづらいです。
「◆画面サイズの実験」のページに、タグのコメント化(無効化)や修正の具体例が書いてあります
もっと詳しい情報を知りたい方、
または、この分野が得意で知識と開発技術があって協力したい方は、
OpenHSP( .js 作者 zakki ) OpenHSP(公式 onitama )
こちらをご覧ください