DIR : /home/kozerus/public_html/jkwii/js/jsdoit/kojsdoit01_index.js
/home/kozerus/public_html/jkwii/js/jsdoit
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// 頂点シェーダー
var vshader_src =
"#ifdef GL_ES \n" +
" precision highp float; \n" +
"#endif \n" +
" \n" +
"attribute vec3 vs_attr_pos; \n" +
"attribute vec3 vs_attr_col; \n" +
"attribute vec2 vs_attr_uvc; \n" +
"uniform mat4 vs_unif_mat; \n" +
" \n" +
"varying vec4 color; \n" +
"varying vec2 texCoord; \n" +
" \n" +
"void main() { \n" +
" color = vec4(vs_attr_col, 1.0); \n" +
" texCoord = vs_attr_uvc; \n" +
" gl_Position = vs_unif_mat * vec4(vs_attr_pos, 1.0); \n" +
"} \n" +
"";
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// フラグメントシェーダー
var fshader_src =
"#ifdef GL_ES \n" +
" precision highp float; \n" +
"#endif \n" +
" \n" +
"uniform sampler2D texture; \n" +
" \n" +
"varying vec4 color; \n" +
"varying vec2 texCoord; \n" +
" \n" +
"void main() { \n" +
" vec4 fragColor = texture2D(texture, texCoord) * color; \n" +
" if(fragColor.a > 0.8){ \n" +
" gl_FragColor = fragColor; \n" +
" }else{ \n" +
" discard; \n" +
" } \n" +
"} \n" +
"";
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// 簡易3Dエンジンクラス
function Engine3d(){
this.gl;
this.shader;
this.s_pos;
this.s_col;
this.s_uvc;
this.s_mat;
// ----------------------------------------------------------------
// 初期化
// エンジン初期化
this.init = function(canvas){
// コンテキストの獲得
try{var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");}catch(e){}
if(!gl){
alert("WebGL がサポートされていません。");
document.write("<img src='http://jsrun.it/assets/u/9/R/Q/u9RQx.png'>");
return -1;
}
// 頂点シェーダーの作成
var vshader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vshader, vshader_src);
gl.compileShader(vshader);
if(!gl.getShaderParameter(vshader, gl.COMPILE_STATUS)){
alert(gl.getShaderInfoLog(vshader));
return -1;
}
// フラグメントシェーダーの作成
var fshader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fshader, fshader_src);
gl.compileShader(fshader);
if(!gl.getShaderParameter(fshader, gl.COMPILE_STATUS)){
alert(gl.getShaderInfoLog(fshader));
return -1;
}
// プログラムオブジェクトを作成
this.shader = gl.createProgram();
gl.attachShader(this.shader, vshader);
gl.attachShader(this.shader, fshader);
// シェーダー内の変数を頂点属性に結びつける
gl.bindAttribLocation(this.shader, this.s_pos = 0, "vs_attr_pos");
gl.bindAttribLocation(this.shader, this.s_col = 1, "vs_attr_col");
gl.bindAttribLocation(this.shader, this.s_uvc = 2, "vs_attr_uvc");
// 頂点シェーダーとフラグメントシェーダーをリンクする
gl.linkProgram(this.shader);
if(!gl.getProgramParameter(this.shader, gl.LINK_STATUS)){
alert(gl.getProgramInfoLog(this.shader));
return -1;
}
// シェーダーパラメータのインデックスを取得保存
this.s_mat = gl.getUniformLocation(this.shader, "vs_unif_mat");
// opengl描画設定
gl.clearColor(0.5, 0.8, 1, 1);
gl.clearDepth(1000);
// カリング
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.BACK);
// アルファブレンド
//gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
//gl.enable(gl.BLEND);
// シェーダーを指定
gl.useProgram(this.shader);
this.gl = gl;
return 0;
}
// ----------------------------------------------------------------
// モデル作成
// VBO作成
this.createVBO = function(vertices){
var gl = this.gl;
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vertexBuffer;
}
// IBO作成
this.createIBO = function(indexes){
var gl = this.gl;
var indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Int16Array(indexes), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return indexBuffer;
}
// バッファ除去
this.deleteBuffer = function(buffer){
var gl = this.gl;
gl.deleteBuffer(buffer);
}
// テクスチャ読込み
this.loadTexture = function(url){
var gl = this.gl;
// テクスチャーオブジェクトを作成
var texture = gl.createTexture();
// 画像の読み込み完了時の処理
var image = new Image();
image.onload = function() {
gl.enable(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
// 画像の読み込みを開始
image.src = url;
return texture;
}
// ----------------------------------------------------------------
// 描画処理
// 描画のクリア
this.clear = function(){
this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
}
// デプステスト設定
this.setDepthMode = function(flag){
var gl = this.gl;
if(flag){
gl.enable(gl.DEPTH_TEST);
}else{
gl.disable(gl.DEPTH_TEST);
}
}
// 行列の設定
this.setMatrix = function(matrix){
var matrixArray = new Float32Array([
matrix._11, matrix._12, matrix._13, matrix._14,
matrix._21, matrix._22, matrix._23, matrix._24,
matrix._31, matrix._32, matrix._33, matrix._34,
matrix._41, matrix._42, matrix._43, matrix._44,
]);
this.gl.uniformMatrix4fv(this.s_mat, false, matrixArray);
}
// テクスチャを指定
this.bindTex = function(texture, type){
var gl = this.gl;
gl.enable(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, texture);
if(type == 1){
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
}else{
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
}
// VBO登録
this.bindBuf = function(vertVBO, clorVBO, texcVBO, faceIBO){
this.bindVertBuf(vertVBO);
this.bindClorBuf(clorVBO);
this.bindTexcBuf(texcVBO);
this.bindFaceBuf(faceIBO);
}
// VBO登録 頂点座標
this.bindVertBuf = function(vertVBO){
var gl = this.gl;
gl.enableVertexAttribArray(this.s_pos);
gl.bindBuffer(gl.ARRAY_BUFFER, vertVBO);
gl.vertexAttribPointer(this.s_pos, 3, gl.FLOAT, false, 0, 0);
}
// VBO登録 カラー
this.bindClorBuf = function(clorVBO){
var gl = this.gl;
gl.enableVertexAttribArray(this.s_col);
gl.bindBuffer(gl.ARRAY_BUFFER, clorVBO);
gl.vertexAttribPointer(this.s_col, 3, gl.FLOAT, false, 0, 0);
}
// VBO登録 テクスチャ座標
this.bindTexcBuf = function(texcVBO){
var gl = this.gl;
gl.enableVertexAttribArray(this.s_uvc);
gl.bindBuffer(gl.ARRAY_BUFFER, texcVBO);
gl.vertexAttribPointer(this.s_uvc, 2, gl.FLOAT, false, 0, 0);
}
// IBO登録 頂点インデックス
this.bindFaceBuf = function(faceIBO){
var gl = this.gl;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, faceIBO);
}
// 描画
this.draw = function(offset, count){
var gl = this.gl;
gl.drawElements(gl.TRIANGLES, count, gl.UNSIGNED_SHORT, offset * Uint16Array.BYTES_PER_ELEMENT);
}
// 描画の反映
this.flush = function(){
this.gl.flush();
}
// ----------------------------------------------------------------
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// 行列クラス
// openGLと同じ右手座標系のつもりだが...?
//[ x ][ _11, _12, _13, _14 ]
//[ y ][ _21, _22, _23, _24 ]
//[ z ][ _31, _32, _33, _34 ]
//[ w ][ _41, _42, _43, _44 ]
function Matrix(){
// ----------------------------------------------------------------
// 初期化
// 単位行列
this.identity = function(){
this._12 = this._13 = this._14 = 0;
this._21 = this._23 = this._24 = 0;
this._31 = this._32 = this._34 = 0;
this._41 = this._42 = this._43 = 0;
this._11 = this._22 = this._33 = this._44 = 1;
}
// 行列の複製
this.copy = function(m){
this._11 = m._11;
this._12 = m._12;
this._13 = m._13;
this._14 = m._14;
this._21 = m._21;
this._22 = m._22;
this._23 = m._23;
this._24 = m._24;
this._31 = m._31;
this._32 = m._32;
this._33 = m._33;
this._34 = m._34;
this._41 = m._41;
this._42 = m._42;
this._43 = m._43;
this._44 = m._44;
}
this.identity();
// ----------------------------------------------------------------
// 行列の掛け合わせ
// 行列の掛け合わせ m0 * m1
this.mul = function(m0, m1){
this._11 = m0._11 * m1._11 + m0._12 * m1._21 + m0._13 * m1._31 + m0._14 * m1._41;
this._12 = m0._11 * m1._12 + m0._12 * m1._22 + m0._13 * m1._32 + m0._14 * m1._42;
this._13 = m0._11 * m1._13 + m0._12 * m1._23 + m0._13 * m1._33 + m0._14 * m1._43;
this._14 = m0._11 * m1._14 + m0._12 * m1._24 + m0._13 * m1._34 + m0._14 * m1._44;
this._21 = m0._21 * m1._11 + m0._22 * m1._21 + m0._23 * m1._31 + m0._24 * m1._41;
this._22 = m0._21 * m1._12 + m0._22 * m1._22 + m0._23 * m1._32 + m0._24 * m1._42;
this._23 = m0._21 * m1._13 + m0._22 * m1._23 + m0._23 * m1._33 + m0._24 * m1._43;
this._24 = m0._21 * m1._14 + m0._22 * m1._24 + m0._23 * m1._34 + m0._24 * m1._44;
this._31 = m0._31 * m1._11 + m0._32 * m1._21 + m0._33 * m1._31 + m0._34 * m1._41;
this._32 = m0._31 * m1._12 + m0._32 * m1._22 + m0._33 * m1._32 + m0._34 * m1._42;
this._33 = m0._31 * m1._13 + m0._32 * m1._23 + m0._33 * m1._33 + m0._34 * m1._43;
this._34 = m0._31 * m1._14 + m0._32 * m1._24 + m0._33 * m1._34 + m0._34 * m1._44;
this._41 = m0._41 * m1._11 + m0._42 * m1._21 + m0._43 * m1._31 + m0._44 * m1._41;
this._42 = m0._41 * m1._12 + m0._42 * m1._22 + m0._43 * m1._32 + m0._44 * m1._42;
this._43 = m0._41 * m1._13 + m0._42 * m1._23 + m0._43 * m1._33 + m0._44 * m1._43;
this._44 = m0._41 * m1._14 + m0._42 * m1._24 + m0._43 * m1._34 + m0._44 * m1._44;
}
// 平行移動行列の掛け合わせ
//[ 1, 0, 0, 0 ][ _11, _12, _13, _14 ]
//[ 0, 1, 0, 0 ][ _21, _22, _23, _24 ]
//[ 0, 0, 1, 0 ][ _31, _32, _33, _34 ]
//[ x, y, z, 1 ][ _41, _42, _43, _44 ]
this.mulTranslate = function(x, y, z){
var temp41 = this._11 * x + this._21 * y + this._31 * z + this._41;
var temp42 = this._12 * x + this._22 * y + this._32 * z + this._42;
var temp43 = this._13 * x + this._23 * y + this._33 * z + this._43;
var temp44 = this._14 * x + this._24 * y + this._34 * z + this._44;
this._41 = temp41;
this._42 = temp42;
this._43 = temp43;
this._44 = temp44;
}
// 拡大縮小行列の掛け合わせ
//[ x, 0, 0, 0 ][ _11, _12, _13, _14 ]
//[ 0, y, 0, 0 ][ _21, _22, _23, _24 ]
//[ 0, 0, z, 0 ][ _31, _32, _33, _34 ]
//[ 0, 0, 0, 1 ][ _41, _42, _43, _44 ]
this.mulScale = function(x, y, z){
this._11 *= x;
this._12 *= x;
this._13 *= x;
this._14 *= x;
this._21 *= y;
this._22 *= y;
this._23 *= y;
this._24 *= y;
this._31 *= z;
this._32 *= z;
this._33 *= z;
this._34 *= z;
}
// x軸中心回転行列の掛け合わせ
//[ 1, 0, 0, 0 ][ _11, _12, _13, _14 ]
//[ 0, c, s, 0 ][ _21, _22, _23, _24 ]
//[ 0, -s, c, 0 ][ _31, _32, _33, _34 ]
//[ 0, 0, 0, 1 ][ _41, _42, _43, _44 ]
this.mulRotX = function(r){
var mr22 = Math.cos(r)
var mr23 = Math.sin(r)
var mr32 = -mr23;
var mr33 = mr22;
var temp21 = mr22 * this._21 + mr23 * this._31
var temp22 = mr22 * this._22 + mr23 * this._32
var temp23 = mr22 * this._23 + mr23 * this._33
var temp24 = mr22 * this._24 + mr23 * this._34
var temp31 = mr32 * this._21 + mr33 * this._31
var temp32 = mr32 * this._22 + mr33 * this._32
var temp33 = mr32 * this._23 + mr33 * this._33
var temp34 = mr32 * this._24 + mr33 * this._34
this._21 = temp21;
this._22 = temp22;
this._23 = temp23;
this._24 = temp24;
this._31 = temp31;
this._32 = temp32;
this._33 = temp33;
this._34 = temp34;
}
// y軸中心回転行列の掛け合わせ
//[ c, 0, -s, 0 ][ _11, _12, _13, _14 ]
//[ 0, 1, 0, 0 ][ _21, _22, _23, _24 ]
//[ s, 0, c, 0 ][ _31, _32, _33, _34 ]
//[ 0, 0, 0, 1 ][ _41, _42, _43, _44 ]
this.mulRotY = function(r){
var mr33 = Math.cos(r)
var mr31 = Math.sin(r)
var mr13 = -mr31;
var mr11 = mr33;
var temp11 = mr11 * this._11 + mr13 * this._31;
var temp12 = mr11 * this._12 + mr13 * this._32;
var temp13 = mr11 * this._13 + mr13 * this._33;
var temp14 = mr11 * this._14 + mr13 * this._34;
var temp31 = mr31 * this._11 + mr33 * this._31;
var temp32 = mr31 * this._12 + mr33 * this._32;
var temp33 = mr31 * this._13 + mr33 * this._33;
var temp34 = mr31 * this._14 + mr33 * this._34;
this._11 = temp11;
this._12 = temp12;
this._13 = temp13;
this._14 = temp14;
this._31 = temp31;
this._32 = temp32;
this._33 = temp33;
this._34 = temp34;
}
// z軸中心回転行列の掛け合わせ
//[ c, s, 0, 0 ][ _11, _12, _13, _14 ]
//[ -s, c, 0, 0 ][ _21, _22, _23, _24 ]
//[ 0, 0, 1, 0 ][ _31, _32, _33, _34 ]
//[ 0, 0, 0, 1 ][ _41, _42, _43, _44 ]
this.mulRotZ = function(r){
var mr11 = Math.cos(r)
var mr12 = Math.sin(r)
var mr21 = -mr12;
var mr22 = mr11;
var temp11 = mr11 * this._11 + mr12 * this._21;
var temp12 = mr11 * this._12 + mr12 * this._22;
var temp13 = mr11 * this._13 + mr12 * this._23;
var temp14 = mr11 * this._14 + mr12 * this._24;
var temp21 = mr21 * this._11 + mr22 * this._21;
var temp22 = mr21 * this._12 + mr22 * this._22;
var temp23 = mr21 * this._13 + mr22 * this._23;
var temp24 = mr21 * this._14 + mr22 * this._24;
this._11 = temp11;
this._12 = temp12;
this._13 = temp13;
this._14 = temp14;
this._21 = temp21;
this._22 = temp22;
this._23 = temp23;
this._24 = temp24;
}
// ----------------------------------------------------------------
// 行列の作成
// 透視射影行列作成
this.frustum = function(w, h, z_near, z_far){
this._12 = this._13 = this._14 = 0;
this._21 = this._23 = this._24 = 0;
this._31 = this._32 = 0;
this._41 = this._42 = 0;
this._11 = 2 * z_near / w;
this._22 = 2 * z_near / h;
this._33 = -(z_far + z_near) / (z_far - z_near);
this._34 = -1;
this._43 = -2 * z_near * z_far / (z_far - z_near);
this._44 = 0;
}
// 正射影行列作成
this.ortho = function(x, y, w, h){
this._12 = this._13 = this._14 = 0;
this._21 = this._23 = this._24 = 0;
this._31 = this._32 = this._34 = 0;
this._43 = 0;
this._33 = this._44 = 1;
this._11 = 2 / w;
this._22 = -2 / h;
this._41 = -2 * x / w - 1;
this._42 = 2 * y / h + 1;
}
// 4*4行列の逆行列作成
this.inverse = function(m){
this._11 = m._22 * (m._33 * m._44 - m._34 * m._43) + m._23 * (m._34 * m._42 - m._32 * m._44) + m._24 * (m._32 * m._43 - m._33 * m._42);
this._12 = -m._32 * (m._43 * m._14 - m._44 * m._13) - m._33 * (m._44 * m._12 - m._42 * m._14) - m._34 * (m._42 * m._13 - m._43 * m._12);
this._13 = m._42 * (m._13 * m._24 - m._14 * m._23) + m._43 * (m._14 * m._22 - m._12 * m._24) + m._44 * (m._12 * m._23 - m._13 * m._22);
this._14 = -m._12 * (m._23 * m._34 - m._24 * m._33) - m._13 * (m._24 * m._32 - m._22 * m._34) - m._14 * (m._22 * m._33 - m._23 * m._32);
this._21 = -m._23 * (m._34 * m._41 - m._31 * m._44) - m._24 * (m._31 * m._43 - m._33 * m._41) - m._21 * (m._33 * m._44 - m._34 * m._43);
this._22 = m._33 * (m._44 * m._11 - m._41 * m._14) + m._34 * (m._41 * m._13 - m._43 * m._11) + m._31 * (m._43 * m._14 - m._44 * m._13);
this._23 = -m._43 * (m._14 * m._21 - m._11 * m._24) - m._44 * (m._11 * m._23 - m._13 * m._21) - m._41 * (m._13 * m._24 - m._14 * m._23);
this._24 = m._13 * (m._24 * m._31 - m._21 * m._34) + m._14 * (m._21 * m._33 - m._23 * m._31) + m._11 * (m._23 * m._34 - m._24 * m._33);
this._31 = m._24 * (m._31 * m._42 - m._32 * m._41) + m._21 * (m._32 * m._44 - m._34 * m._42) + m._22 * (m._34 * m._41 - m._31 * m._44);
this._32 = -m._34 * (m._41 * m._12 - m._42 * m._11) - m._31 * (m._42 * m._14 - m._44 * m._12) - m._32 * (m._44 * m._11 - m._41 * m._14);
this._33 = m._44 * (m._11 * m._22 - m._12 * m._21) + m._41 * (m._12 * m._24 - m._14 * m._22) + m._42 * (m._14 * m._21 - m._11 * m._24);
this._34 = -m._14 * (m._21 * m._32 - m._22 * m._31) - m._11 * (m._22 * m._34 - m._24 * m._32) - m._12 * (m._24 * m._31 - m._21 * m._34);
this._41 = -m._21 * (m._32 * m._43 - m._33 * m._42) - m._22 * (m._33 * m._41 - m._31 * m._43) - m._23 * (m._31 * m._42 - m._32 * m._41);
this._42 = m._31 * (m._42 * m._13 - m._43 * m._12) + m._32 * (m._43 * m._11 - m._41 * m._13) + m._33 * (m._41 * m._12 - m._42 * m._11);
this._43 = -m._41 * (m._12 * m._23 - m._13 * m._22) - m._42 * (m._13 * m._21 - m._11 * m._23) - m._43 * (m._11 * m._22 - m._12 * m._21);
this._44 = m._11 * (m._22 * m._33 - m._23 * m._32) + m._12 * (m._23 * m._31 - m._21 * m._33) + m._13 * (m._21 * m._32 - m._22 * m._31);
var det = m._11 * this._11 + m._21 * this._12 + m._31 * this._13 + m._41 * this._14;
if(det == 0){return -1;}
var idet = 1 / det;
this._11 *= idet; this._12 *= idet; this._13 *= idet; this._14 *= idet;
this._21 *= idet; this._22 *= idet; this._23 *= idet; this._24 *= idet;
this._31 *= idet; this._32 *= idet; this._33 *= idet; this._34 *= idet;
this._41 *= idet; this._42 *= idet; this._43 *= idet; this._44 *= idet;
return 0;
}
// 四元数回転行列作成
this.qRotate = function(q){
var xx = q.x * q.x;
var yy = q.y * q.y;
var zz = q.z * q.z;
var xy = q.x * q.y;
var yz = q.y * q.z;
var zx = q.z * q.x;
var wx = q.w * q.x;
var wy = q.w * q.y;
var wz = q.w * q.z;
this._11 = 1 - 2 * (yy + zz);
this._12 = 2 * (xy + wz);
this._13 = 2 * (zx - wy);
this._21 = 2 * (xy - wz);
this._22 = 1 - 2 * (zz + xx);
this._23 = 2 * (yz + wx);
this._31 = 2 * (zx + wy);
this._32 = 2 * (yz - wx);
this._33 = 1 - 2 * (xx + yy);
this._14 = this._24 = this._34 = 0;
this._41 = this._42 = this._43 = 0;
this._44 = 1;
}
// ----------------------------------------------------------------
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// 四元数クラス
function Quaternion(){
// ----------------------------------------------------------------
// 初期化
// 単位四元数
this.identity = function(){
this.w = 1;
this.x = 0;
this.y = 0;
this.z = 0;
}
// 四元数の複製
this.copy = function(q){
this.w = q.w;
this.x = q.x;
this.y = q.y;
this.z = q.z;
}
this.identity();
// ----------------------------------------------------------------
// 四元数の掛け合わせ
// 四元数の掛け合わせ q0 * q1
this.mul = function(q0, q1){
this.w = q0.w * q1.w - q0.x * q1.x - q0.y * q1.y - q0.z * q1.z;
this.x = q0.w * q1.x + q0.x * q1.w - q0.y * q1.z + q0.z * q1.y;
this.y = q0.w * q1.y + q0.x * q1.z + q0.y * q1.w - q0.z * q1.x;
this.z = q0.w * q1.z - q0.x * q1.y + q0.y * q1.x + q0.z * q1.w;
}
// 回転の四元数の掛け合わせ
this.mulRot = function(r, x, y, z){
var s = Math.sin(r / 2) / Math.sqrt(x * x + y * y + z * z);
rw = Math.cos(r / 2);
rx = s * x;
ry = s * y;
rz = s * z;
var tw = this.w;
var tx = this.x;
var ty = this.y;
var tz = this.z;
this.w = tw * rw - tx * rx - ty * ry - tz * rz;
this.x = tw * rx + tx * rw - ty * rz + tz * ry;
this.y = tw * ry + tx * rz + ty * rw - tz * rx;
this.z = tw * rz - tx * ry + ty * rx + tz * rw;
}
// ----------------------------------------------------------------
// 四元数の作成
// 回転の四元数作成
this.rotate = function(r, x, y, z){
var s = Math.sin(r / 2) / Math.sqrt(x * x + y * y + z * z);
this.w = Math.cos(r / 2);
this.x = s * x;
this.y = s * y;
this.z = s * z;
}
// 球面線形補間
this.sleap = function(t, q0, q1){
var r = q0.w * q1.w + q0.x * q1.x + q0.y * q1.y + q0.z * q1.z;
var s = 1 - r * r;
if(s == 0){
this.w = q0.w;
this.x = q0.x;
this.y = q0.y;
this.z = q0.z;
}else{
var sp = Math.sqrt(s);
var ph = Math.acos(r);
var pt = ph * t;
var t1 = Math.sin(pt) / sp;
var t0 = Math.sin(ph - pt) / sp;
this.w = q0.w * t0 + q1.w * t1;
this.x = q0.x * t0 + q1.x * t1;
this.y = q0.y * t0 + q1.y * t1;
this.z = q0.z * t0 + q1.z * t1;
}
}
// ----------------------------------------------------------------
// ユーティリティ
// 正規化的な関数
this.hoge = function(){
}
// ----------------------------------------------------------------
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
var ctrl = new Controller();
// 簡易コントローラー
function Controller(){
// キャンバスサイズ
var w;
var h;
// ボタン状態
this.kup = false;
this.kdn = false;
this.krt = false;
this.klt = false;
this.k_z = false;
this.k_x = false;
this.k_s = false;
// マウス座標
this.mousex = 0;
this.mousey = 0;
// 回転
this.rotv = 0;
this.roth = 0;
this.roth_max = Math.PI / 180 * 60;
this.roth_min = Math.PI / 180 * -60;
this.size = 10;
this.size_max = 20;
this.size_min = 5;
// メニュー系
this.selectedLine = 0;
this.selectedChip = -1;
this.selectedx = -1;
this.selectedy = -1;
this.selectedz = -1;
// ----------------------------------------------------------------
// コントローラーの初期化 イベント登録
var vertBuffer;
var clorBuffer;
var texcBuffer;
var faceBuffer;
// バッファに画像の情報を登録
var pushBuffer = function(vert, texc, clor, face, w, h, tx, ty, vx, vy){
var vx0 = vx;
var vy0 = vy;
var vx1 = vx + w;
var vy1 = vy + h;
var tx0 = tx / 256;
var ty0 = ty / 128;
var tx1 = (tx + w) / 256;
var ty1 = (ty + h) / 128;
var index = vert.length / 3;
vert.push(vx1); vert.push(vy0); vert.push(0.0);
vert.push(vx0); vert.push(vy0); vert.push(0.0);
vert.push(vx0); vert.push(vy1); vert.push(0.0);
vert.push(vx1); vert.push(vy1); vert.push(0.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
texc.push(tx1); texc.push(ty0);
texc.push(tx0); texc.push(ty0);
texc.push(tx0); texc.push(ty1);
texc.push(tx1); texc.push(ty1);
face.push(index + 0);
face.push(index + 1);
face.push(index + 2);
face.push(index + 0);
face.push(index + 2);
face.push(index + 3);
}
// 初期化
this.init = function(e3d, canvas){
w = canvas.width;
h = canvas.height;
var vert = new Array();
var texc = new Array();
var clor = new Array();
var face = new Array();
// 矢印キー
pushBuffer(vert, texc, clor, face, 40, 48, 0, 0, 10 + 36, h - 122 + 0);
pushBuffer(vert, texc, clor, face, 40, 48, 88, 0, 10 + 36, h - 122 + 0);
pushBuffer(vert, texc, clor, face, 40, 48, 48, 40, 10 + 36, h - 122 + 64);
pushBuffer(vert, texc, clor, face, 40, 48, 136, 40, 10 + 36, h - 122 + 64);
pushBuffer(vert, texc, clor, face, 48, 40, 40, 0, 10 + 64, h - 122 + 36);
pushBuffer(vert, texc, clor, face, 48, 40, 128, 0, 10 + 64, h - 122 + 36);
pushBuffer(vert, texc, clor, face, 48, 40, 0, 48, 10 + 0, h - 122 + 36);
pushBuffer(vert, texc, clor, face, 48, 40, 88, 48, 10 + 0, h - 122 + 36);
// ZXボタン
pushBuffer(vert, texc, clor, face, 64, 64, 176, 0, w - 138, h - 84);
pushBuffer(vert, texc, clor, face, 64, 64, 176, 64, w - 138, h - 84);
pushBuffer(vert, texc, clor, face, 64, 64, 176, 0, w - 74, h - 116);
pushBuffer(vert, texc, clor, face, 64, 64, 176, 64, w - 74, h - 116);
pushBuffer(vert, texc, clor, face, 24, 24, 128, 88, w - 118, h - 64);
pushBuffer(vert, texc, clor, face, 24, 24, 152, 88, w - 54, h - 96);
// スペースボタン
pushBuffer(vert, texc, clor, face, 128, 16, 0, 88, w / 2 - 64, h - 16);
pushBuffer(vert, texc, clor, face, 128, 16, 0, 104, w / 2 - 64, h - 16);
// スクロールバー
pushBuffer(vert, texc, clor, face, 16, 96, 240, 0, w - 24, 40);
pushBuffer(vert, texc, clor, face, 16, 16, 240, 96, w - 24, 40);
// VBOとIBOを作成し、データを転送
vertBuffer = e3d.createVBO(vert);
clorBuffer = e3d.createVBO(clor);
texcBuffer = e3d.createVBO(texc);
faceBuffer = e3d.createIBO(face);
canvas.addEventListener("mousedown", mdnEvent, true);
canvas.addEventListener("mousemove", mmvEvent, true);
canvas.addEventListener("mouseup", mupEvent, true);
canvas.addEventListener("mouseout", mupEvent, true);
canvas.addEventListener("touchstart", mdnEvent, true);
canvas.addEventListener("touchmove", mmvEvent, true);
canvas.addEventListener("touchend", mupEvent, true);
document.addEventListener("keydown", kdnEvent, true);
document.addEventListener("keyup", kupEvent, true);
}
// ----------------------------------------------------------------
// コントローラーの描画
var tmpmat = new Matrix();
this.draw = function(e3d, mat){
// 行列作成
e3d.setMatrix(mat);
// 描画
e3d.bindBuf(vertBuffer, clorBuffer, texcBuffer, faceBuffer);
if(!this.kup){e3d.draw( 0, 6);}else{e3d.draw( 6, 6);}
if(!this.kdn){e3d.draw(12, 6);}else{e3d.draw(18, 6);}
if(!this.krt){e3d.draw(24, 6);}else{e3d.draw(30, 6);}
if(!this.klt){e3d.draw(36, 6);}else{e3d.draw(42, 6);}
if(!this.k_z){e3d.draw(48, 6);}else{e3d.draw(54, 6);} e3d.draw(72, 6);
if(!this.k_x){e3d.draw(60, 6);}else{e3d.draw(66, 6);} e3d.draw(78, 6);
//if(!this.k_s){e3d.draw(84, 6);}else{e3d.draw(90, 6);}
e3d.draw(96, 6);
tmpmat.copy(mat);
tmpmat.mulTranslate(0, 80 * (this.size - this.size_min) / (this.size_max - this.size_min), 0);
e3d.setMatrix(tmpmat);
e3d.draw(102, 6);
}
// ----------------------------------------------------------------
// 引数の座標を中心とするワールド行列を作成する
this.createWorldMatrix = function(mat, x, y, z){
mat.frustum(0.1, 0.1, 0.1, 100);
mat.mulTranslate(0, 0, -this.size);
mat.mulRotX(ctrl.roth);
mat.mulRotY(ctrl.rotv);
mat.mulTranslate(-x, -z, -y);
}
// ----------------------------------------------------------------
// マウスイベント
var mouseMode = 0;
var touchx;
var touchy;
// 回転
var touchrv;
var touchrh;
// コントローラーをクリック時の動作
var btnEvent = function(){
// 矢印キー
var x = ctrl.mousex - (10 + 56);
var y = ctrl.mousey - (h - 10 - 56);
if(x * x + y * y < 56 * 56){
if(-6 < x && x < 6 && -6 < y && y < 6){ctrl.kup = ctrl.kdn = ctrl.krt = ctrl.klt = 0;} // ど真ん中の空白地帯
else if(-18 < x && x < 18 && y < -18){ctrl.kup = 1; ctrl.kdn = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 上
else if(-18 < x && x < 18 && y > 18){ctrl.kdn = 1; ctrl.kup = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 下
else if(-18 < y && y < 18 && x > 18){ctrl.krt = 1; ctrl.kup = ctrl.kdn = ctrl.klt = 0; mouseMode = 1;} // 右
else if(-18 < y && y < 18 && x < -18){ctrl.klt = 1; ctrl.kup = ctrl.kdn = ctrl.krt = 0; mouseMode = 1;} // 左
else if(x > 18 && y < -18){ctrl.kup = ctrl.krt = 1; ctrl.kdn = ctrl.klt = 0; mouseMode = 1;} // 右上
else if(x > 18 && y > 18){ctrl.kdn = ctrl.krt = 1; ctrl.kup = ctrl.klt = 0; mouseMode = 1;} // 右下
else if(x < -18 && y < -18){ctrl.kup = ctrl.klt = 1; ctrl.kdn = ctrl.krt = 0; mouseMode = 1;} // 左上
else if(x < -18 && y > 18){ctrl.kdn = ctrl.klt = 1; ctrl.kup = ctrl.krt = 0; mouseMode = 1;} // 左下
else{
if(x > y && x < -y){ctrl.kup = 1; ctrl.kdn = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 内側上
if(x < y && x > -y){ctrl.kdn = 1; ctrl.kup = ctrl.krt = ctrl.klt = 0; mouseMode = 1;} // 内側下
if(x > y && x > -y){ctrl.krt = 1; ctrl.kup = ctrl.kdn = ctrl.klt = 0; mouseMode = 1;} // 内側右
if(x < y && x < -y){ctrl.klt = 1; ctrl.kup = ctrl.kdn = ctrl.krt = 0; mouseMode = 1;} // 内側左
}
}else{ctrl.kup = ctrl.kdn = ctrl.krt = ctrl.klt = 0;} // 押していない
// ZXボタン
x = ctrl.mousex - (w - 10 - 64);
y = ctrl.mousey - (h - 20 - 48);
if(-8 < x && x < 8 && -8 < y && y < 8){ctrl.k_z =ctrl.k_x = 1; mouseMode = 1;} // 同時押し
else if(-64 < x && x < 0 && -16 < y && y < 48){ctrl.k_z = 1; ctrl.k_x = 0; mouseMode = 1;} // z押し
else if( 0 < x && x < 64 && -48 < y && y < 16){ctrl.k_x = 1; ctrl.k_z = 0; mouseMode = 1;} // x押し
else{ctrl.k_z = ctrl.k_x = 0;}
// スペースボタン
x = ctrl.mousex - (w / 2);
y = ctrl.mousey - (h - 8);
if(-64 < x && x < 64 && -8 < y && y < 8){ctrl.k_s = 1; mouseMode = 1;}
else{ctrl.k_s = 0;}
// スクロールバー
x = ctrl.mousex - (w - 24);
y = ctrl.mousey - 40;
if(0 < x && x < 16 && 0 < y && y < 96){
if(y < 8){ctrl.size = ctrl.size_min;}
else if(y > 88){ctrl.size = ctrl.size_max;}
else{ctrl.size = (y - 8) * (ctrl.size_max - ctrl.size_min) / 80 + ctrl.size_min;}
mouseMode = 1;
}
}
// メニュー部分をクリック時の動作開始
var mnuEvent0 = function(){
if(ctrl.mousey < 32){
mouseMode = 2;
if(16 < ctrl.mousex && ctrl.mousex < 32){ctrl.selectedChip = 100;}
if(32 < ctrl.mousex && ctrl.mousex < 48){ctrl.selectedChip = 101;}
for(var i = 0; i < 9; i++){
if(54 + i * 24 < ctrl.mousex && ctrl.mousex < 74 + i * 24){ctrl.selectedChip = i;}
}
}else if(ctrl.mousey > 288){
}
}
// メニュー部分をクリック時の動作終了
var mnuEvent2 = function(){
if(ctrl.mousey < 32){
if(ctrl.selectedChip == 100 && 16 < ctrl.mousex && ctrl.mousex < 32){ctrl.selectedLine = (ctrl.selectedLine + 7) % 8;}
if(ctrl.selectedChip == 101 && 32 < ctrl.mousex && ctrl.mousex < 48){ctrl.selectedLine = (ctrl.selectedLine + 1) % 8;}
}else if(ctrl.mousey > 288){
}else{
// マップチップ配置と除去
if(map.getMapChip(ctrl.selectedx, ctrl.selectedz, ctrl.selectedy) >= 0 && 0 <= ctrl.selectedChip && ctrl.selectedChip <= 8){
var chip = (ctrl.selectedChip < 8) ? ctrl.selectedLine * 8 + ctrl.selectedChip + 1 : 0;
map.map[ctrl.selectedy][ctrl.selectedz][ctrl.selectedx] = chip;
map.update(e3d);
}
}
}
// 回転開始
var rotEvent0 = function(){
touchx = ctrl.mousex;
touchy = ctrl.mousey;
mouseMode = 3;
// 回転
touchrv = ctrl.rotv;
touchrh = ctrl.roth;
}
// 回転中
var rotEvent1 = function(){
// 回転
ctrl.rotv = touchrv + (ctrl.mousex - touchx) * 0.03;
ctrl.roth = touchrh + (ctrl.mousey - touchy) * 0.03;
if(ctrl.roth > ctrl.roth_max){ctrl.roth = ctrl.roth_max;}
if(ctrl.roth < ctrl.roth_min){ctrl.roth = ctrl.roth_min;}
}
// マウスを押す
var mdnEvent = function(e){
// コントローラークリックの確認
btnEvent();
if(mouseMode == 0){mnuEvent0();}
if(mouseMode == 0){rotEvent0();}
// マウスイベント終了
e.preventDefault();
}
// マウス移動
var mmvEvent = function(e){
// 座標を獲得する
var rect = e.target.getBoundingClientRect();
ctrl.mousex = e.clientX - rect.left;
ctrl.mousey = e.clientY - rect.top;
// マウス移動イベント
if(mouseMode == 1){btnEvent();}
else if(mouseMode == 3){rotEvent1();}
// マウスイベント終了
e.preventDefault();
}
// マウスボタンを離す
var mupEvent = function(e){
if(mouseMode == 2 && e.type == "mouseup"){mnuEvent2();}
mouseMode = 0;
ctrl.kup = ctrl.kdn = ctrl.krt = ctrl.klt = ctrl.k_z = ctrl.k_x = ctrl.k_s = false;
ctrl.selectedChip = -1;
// マウスイベント終了
e.preventDefault();
}
// ----------------------------------------------------------------
// キーイベント
// キーを押す
var kdnEvent = function(e){
var getkey = true;
switch (e.keyCode){
case 37: ctrl.klt = true; break;
case 38: ctrl.kup = true; break;
case 39: ctrl.krt = true; break;
case 40: ctrl.kdn = true; break;
case 88: ctrl.k_x = true; break;
case 90: ctrl.k_z = true; break;
case 32: ctrl.k_s = true; break;
default: getkey = false;
}
// キーイベント終了
if(getkey){
e.preventDefault();
}
}
// キーを離す
var kupEvent = function(e){
var getkey = true;
switch (e.keyCode){
case 37: ctrl.klt = false; break;
case 38: ctrl.kup = false; break;
case 39: ctrl.krt = false; break;
case 40: ctrl.kdn = false; break;
case 88: ctrl.k_x = false; break;
case 90: ctrl.k_z = false; break;
case 32: ctrl.k_s = false; break;
default: getkey = false;
}
// キーイベント終了
if(getkey){
e.preventDefault();
}
}
// ----------------------------------------------------------------
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// キャラクタクラス
function Character(){
this.vertBuffer;
this.clorBuffer;
this.texcBuffer;
this.faceBuffer;
this.faceNum;
// ----------------------------------------------------------------
// 初期化
var pushBuffer = function(vert, texc, clor, face, u0, v0){
var u1 = u0 + 0.25;
var v1 = v0 + 0.25;
var index = vert.length / 3;
vert.push( 0.5); vert.push( 1.0); vert.push( 0.0);
vert.push(-0.5); vert.push( 1.0); vert.push( 0.0);
vert.push(-0.5); vert.push( 0.0); vert.push( 0.0);
vert.push( 0.5); vert.push( 0.0); vert.push( 0.0);
texc.push(u1); texc.push(v0);
texc.push(u0); texc.push(v0);
texc.push(u0); texc.push(v1);
texc.push(u1); texc.push(v1);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
face.push(index + 0);
face.push(index + 1);
face.push(index + 2);
face.push(index + 0);
face.push(index + 2);
face.push(index + 3);
}
this.init = function(e3d){
var vert = new Array();
var clor = new Array();
var texc = new Array();
var face = new Array();
for(var i = 0; i < 4; i++){
for(var j = 0; j < 4; j++){
pushBuffer(vert, texc, clor, face, 0.25 * i, 0.25 * j);
}
}
this.faceNum = face.length;
// VBOとIBOを作成し、データを転送
this.vertBuffer = e3d.createVBO(vert);
this.clorBuffer = e3d.createVBO(clor);
this.texcBuffer = e3d.createVBO(texc);
this.faceBuffer = e3d.createIBO(face);
}
// ----------------------------------------------------------------
// 描画
var tmpmat = new Matrix();
this.draw = function(e3d, mat, rotate, type, x, y, z, size){
var index = type * 4;
// 回転
rotate = (rotate - ctrl.rotv) / Math.PI * 180;
while(rotate > 360 - 45){rotate -= 360;}
while(rotate <= 0 - 45){rotate += 360;}
if(rotate < 45){index += 3;}
else if(rotate <= 135){index += 0;}
else if(rotate < 225){index += 1;}
else{index += 2;}
// 行列作成
tmpmat.copy(mat);
tmpmat.mulTranslate(x, z, y);
tmpmat.mulRotY(-ctrl.rotv);
tmpmat.mulScale(size, size, size);
e3d.setMatrix(tmpmat);
// 描画
e3d.bindBuf(this.vertBuffer, this.clorBuffer, this.texcBuffer, this.faceBuffer);
e3d.draw(index * 6, 6);
}
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// 影クラス
function Shadow(texFile){
this.vertBuffer;
this.clorBuffer;
this.texcBuffer;
this.faceBuffer;
this.faceNum;
// ----------------------------------------------------------------
// 初期化
this.init = function(e3d){
var vert = new Array();
var clor = new Array();
var texc = new Array();
var face = new Array();
vert.push(-0.5); vert.push( 0.05); vert.push( 0.5);
vert.push( 0.5); vert.push( 0.05); vert.push( 0.5);
vert.push( 0.5); vert.push( 0.05); vert.push(-0.5);
vert.push(-0.5); vert.push( 0.05); vert.push(-0.5);
texc.push(1.0); texc.push(0.0);
texc.push(0.0); texc.push(0.0);
texc.push(0.0); texc.push(1.0);
texc.push(1.0); texc.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0);
face.push(0); face.push(1); face.push(2);
face.push(0); face.push(2); face.push(3);
this.faceNum = face.length;
// VBOとIBOを作成し、データを転送
this.vertBuffer = e3d.createVBO(vert);
this.clorBuffer = e3d.createVBO(clor);
this.texcBuffer = e3d.createVBO(texc);
this.faceBuffer = e3d.createIBO(face);
}
// ----------------------------------------------------------------
// 描画
var tmpmat = new Matrix();
this.draw = function(e3d, mat, x, y, z, size){
// 行列作成
tmpmat.copy(mat);
tmpmat.mulTranslate(x, z, y);
tmpmat.mulScale(size, 1, size);
e3d.setMatrix(tmpmat);
// 描画
e3d.bindBuf(this.vertBuffer, this.clorBuffer, this.texcBuffer, this.faceBuffer);
e3d.draw(0, this.faceNum);
}
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// 地形クラス
function Map(){
this.vertBuffer;
this.clorBuffer;
this.texcBuffer;
this.faceBuffer;
this.faceNum;
// 地形情報
this.x = 0;
this.y = 0;
this.z = 0;
this.map = null;
var invmat = new Matrix();
// ----------------------------------------------------------------
// マップチップの範囲外チェック
this.getMapChip = function(x, y, z){
x = Math.floor(parseInt(x));
y = Math.floor(parseInt(y));
z = Math.floor(parseInt(z));
if(isNaN(x) || x < 0 || this.x <= x){return -1;}
if(isNaN(y) || y < 0 || this.y <= y){return -1;}
if(isNaN(z) || z < 0 || this.z <= z){return -1;}
return this.map[z][y][x];
}
// ----------------------------------------------------------------
// マップチップの透過チェック
this.isMapChipVisible = function(x, y, z){
var chip = this.getMapChip(x, y, z);
return chip != -1 && chip != 0 && chip != 1 && !(57 <= chip && chip <= 64);
}
// ----------------------------------------------------------------
// マップチップの衝突チェック
this.isMapChipHit = function(x, y, z){
var chip = this.getMapChip(x, y, z);
return chip != 0;
}
// ----------------------------------------------------------------
// 初期化
this.init = function(e3d, map){
var vert = new Array();
var clor = new Array();
var texc = new Array();
var face = new Array();
this.map = map;
this.x = this.map[0][0].length;
this.y = this.map[0].length;
this.z = this.map.length;
// 頂点データを生成
for(var i = 0; i < this.x; i++){
for(var j = 0; j < this.y; j++){
for(var k = 0; k < this.z; k++){
if(this.map[k][j][i] > 0){
if(!this.isMapChipVisible(i, j, k + 1)){this.pushSurfaces(vert, clor, texc, i, j, k, 1);}
if(!this.isMapChipVisible(i, j, k - 1)){this.pushSurfaces(vert, clor, texc, i, j, k, 2);}
if(!this.isMapChipVisible(i, j + 1, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 3);}
if(!this.isMapChipVisible(i, j - 1, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 4);}
if(!this.isMapChipVisible(i + 1, j, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 5);}
if(!this.isMapChipVisible(i - 1, j, k)){this.pushSurfaces(vert, clor, texc, i, j, k, 6);}
}
}
}
}
// インデックスデータを生成
var num = vert.length / 12;
for(var i = 0; i < num; i++){
face.push(i * 4 + 0); face.push(i * 4 + 1); face.push(i * 4 + 2);
face.push(i * 4 + 0); face.push(i * 4 + 2); face.push(i * 4 + 3);
}
this.faceNum = face.length;
// VBOとIBOを作成し、データを転送
this.vertBuffer = e3d.createVBO(vert);
this.clorBuffer = e3d.createVBO(clor);
this.texcBuffer = e3d.createVBO(texc);
this.faceBuffer = e3d.createIBO(face);
}
// 更新
this.update = function(e3d){
e3d.deleteBuffer(this.vertBuffer);
e3d.deleteBuffer(this.clorBuffer);
e3d.deleteBuffer(this.texcBuffer);
e3d.deleteBuffer(this.faceBuffer);
this.init(e3d, this.map);
}
// 面の頂点配列作成
this.pushSurfaces = function(vert, clor, texc, x0, y0, z0, s){
var chip = this.map[z0][y0][x0] - 1;
var x1 = x0 + 1;
var y1 = y0 + 1;
var z1 = z0 + 1;
var xm = x0 - 1;
var ym = y0 - 1;
var zm = z0 - 1;
var u0 = (chip % 4) * 0.2500;
var v0 = Math.floor(chip / 4) * 0.0625;
var v1 = v0 + 0.0625;
switch(s){
case 1:
vert.push(x0); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, xm, y0, z1, xm, ym, z1);
vert.push(x0); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, xm, y0, z1, xm, y1, z1);
vert.push(x1); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, x1, y0, z1, x1, y1, z1);
vert.push(x1); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, x1, y0, z1, x1, ym, z1);
break;
case 2:
u0 = u0 + 0.1875;
vert.push(x0); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, xm, y0, zm, xm, y1, zm);
vert.push(x0); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, xm, y0, zm, xm, ym, zm);
vert.push(x1); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, x1, y0, zm, x1, ym, zm);
vert.push(x1); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, x1, y0, zm, x1, y1, zm);
break;
case 3:
u0 = u0 + 0.0625;
vert.push(x0); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, xm, y1, z0, xm, y1, z1);
vert.push(x0); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, xm, y1, z0, xm, y1, zm);
vert.push(x1); vert.push(z0); vert.push(y1); this.setTopColor(clor, x0, y1, zm, x1, y1, z0, x1, y1, zm);
vert.push(x1); vert.push(z1); vert.push(y1); this.setTopColor(clor, x0, y1, z1, x1, y1, z0, x1, y1, z1);
break;
case 4:
u0 = u0 + 0.0625;
vert.push(x1); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, x1, ym, z0, x1, ym, z1);
vert.push(x1); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, x1, ym, z0, x1, ym, zm);
vert.push(x0); vert.push(z0); vert.push(y0); this.setTopColor(clor, x0, ym, zm, xm, ym, z0, xm, ym, zm);
vert.push(x0); vert.push(z1); vert.push(y0); this.setTopColor(clor, x0, ym, z1, xm, ym, z0, xm, ym, z1);
break;
case 5:
u0 = u0 + 0.1250;
vert.push(x1); vert.push(z1); vert.push(y1); this.setTopColor(clor, x1, y0, z1, x1, y1, z0, x1, y1, z1);
vert.push(x1); vert.push(z0); vert.push(y1); this.setTopColor(clor, x1, y0, zm, x1, y1, z0, x1, y1, zm);
vert.push(x1); vert.push(z0); vert.push(y0); this.setTopColor(clor, x1, y0, zm, x1, ym, z0, x1, ym, zm);
vert.push(x1); vert.push(z1); vert.push(y0); this.setTopColor(clor, x1, y0, z1, x1, ym, z0, x1, ym, z1);
break;
case 6:
u0 = u0 + 0.1250;
vert.push(x0); vert.push(z1); vert.push(y0); this.setTopColor(clor, xm, y0, z1, xm, ym, z0, xm, ym, z1);
vert.push(x0); vert.push(z0); vert.push(y0); this.setTopColor(clor, xm, y0, zm, xm, ym, z0, xm, ym, zm);
vert.push(x0); vert.push(z0); vert.push(y1); this.setTopColor(clor, xm, y0, zm, xm, y1, z0, xm, y1, zm);
vert.push(x0); vert.push(z1); vert.push(y1); this.setTopColor(clor, xm, y0, z1, xm, y1, z0, xm, y1, z1);
break;
}
u1 = u0 + 0.0625;
texc.push(u0); texc.push(v0);
texc.push(u0); texc.push(v1);
texc.push(u1); texc.push(v1);
texc.push(u1); texc.push(v0);
}
// 影の確認
this.setTopColor = function(clor, x1, y1, z1, x2, y2, z2, x3, y3, z3){
var color = 1;
if(this.isMapChipVisible(x1, y1, z1)){color -= 0.2;}
if(this.isMapChipVisible(x2, y2, z2)){color -= 0.2;}
if(this.isMapChipVisible(x3, y3, z3)){color -= 0.2;}
clor.push(color); clor.push(color); clor.push(color);
}
// ----------------------------------------------------------------
// 描画
var tmpmat = new Matrix();
this.draw = function(e3d, mat, x, y, z){
// 行列作成
tmpmat.copy(mat);
tmpmat.mulTranslate(x, z, y);
e3d.setMatrix(tmpmat);
// 描画
e3d.bindBuf(this.vertBuffer, this.clorBuffer, this.texcBuffer, this.faceBuffer);
e3d.draw(0, this.faceNum);
// 逆行列
invmat.inverse(tmpmat);
this.select();
}
// ----------------------------------------------------------------
// マウス座標と逆行列からマップチップ選択
this.select = function(){
var mx = 2 * ctrl.mousex / 320 - 1;
var my = 1 - 2 * ctrl.mousey / 320;
var xyw1 = invmat._11 * mx + invmat._21 * my + invmat._41;
var xyw2 = invmat._12 * mx + invmat._22 * my + invmat._42;
var xyw3 = invmat._13 * mx + invmat._23 * my + invmat._43;
var xyw4 = invmat._14 * mx + invmat._24 * my + invmat._44;
var tempDepth = 1;
var tempx1 = -1, tempx2 = -1;
var tempy1 = -1, tempy2 = -1;
var tempz1 = -1, tempz2 = -1;
// マウス座標とx軸平面の交点
for(var x = 0; x <= this.x; x++){
var depth = -(xyw1 - xyw4 * x) / (invmat._31 - invmat._34 * x);
var w = xyw4 + invmat._34 * depth;
var y = Math.floor((xyw2 + invmat._32 * depth) / w);
var z = Math.floor((xyw3 + invmat._33 * depth) / w);
if(depth < tempDepth && ((this.getMapChip(x, z, y) > 0) ^ (this.getMapChip(x - 1, z, y) > 0))){
tempx1 = x; tempx2 = x - 1;
tempy1 = y; tempy2 = y;
tempz1 = z; tempz2 = z;
tempDepth = depth;
}
}
// マウス座標とy軸平面の交点
for(var y = 0; y <= this.z; y++){
var depth = -(xyw2 - xyw4 * y) / (invmat._32 - invmat._34 * y);
var w = xyw4 + invmat._34 * depth;
var x = Math.floor((xyw1 + invmat._31 * depth) / w);
var z = Math.floor((xyw3 + invmat._33 * depth) / w);
if(depth < tempDepth && ((this.getMapChip(x, z, y) > 0) ^ (this.getMapChip(x, z, y - 1) > 0))){
tempx1 = x; tempx2 = x;
tempy1 = y; tempy2 = y - 1;
tempz1 = z; tempz2 = z;
tempDepth = depth;
}
}
// マウス座標とz軸平面の交点
for(var z = 0; z <= this.y; z++){
var depth = -(xyw3 - xyw4 * z) / (invmat._33 - invmat._34 * z);
var w = xyw4 + invmat._34 * depth;
var x = Math.floor((xyw1 + invmat._31 * depth) / w);
var y = Math.floor((xyw2 + invmat._32 * depth) / w);
if(depth < tempDepth && ((this.getMapChip(x, z, y) > 0) ^ (this.getMapChip(x, z - 1, y) > 0))){
tempx1 = x; tempx2 = x;
tempy1 = y; tempy2 = y;
tempz1 = z; tempz2 = z - 1;
tempDepth = depth;
}
}
if((this.getMapChip(tempx1, tempz1, tempy1) > 0) ^ !(ctrl.selectedChip == 8)){
ctrl.selectedx = tempx1;
ctrl.selectedy = tempy1;
ctrl.selectedz = tempz1;
}else{
ctrl.selectedx = tempx2;
ctrl.selectedy = tempy2;
ctrl.selectedz = tempz2;
}
if(this.getMapChip(ctrl.selectedx, ctrl.selectedz, ctrl.selectedy) < 0){
ctrl.selectedx = -1;
ctrl.selectedy = -1;
ctrl.selectedz = -1;
}
}
// ----------------------------------------------------------------
// あたり判定
// mapとキャラクタ情報の衝突判定
this.isHit = function(px, py, pz, vx, vy, vz, radius, height){
var h_length = 2 + Math.floor(radius * 2);
var v_length = 2 + Math.floor(height);
// x軸を等分割してmap上の点を得る
var dx = new Array(h_length);
var temp0 = px + vx + radius;
var temp1 = px + vx - radius;
for(var i = 0; i < h_length; i++){
dx[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
}
// y軸を等分割してmap上の点を得る
var dy = new Array(h_length);
var temp0 = py + vy + radius;
var temp1 = py + vy - radius;
for(var i = 0; i < h_length; i++){
dy[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
}
// z軸を等分割してmap上の点を得る
var dz = new Array(v_length);
var temp0 = pz + vz + height;
var temp1 = pz + vz;
for(var i = 0; i < v_length; i++){
dz[i] = Math.floor(temp0 + (temp1 - temp0) * i / (v_length - 1));
}
// 各軸進行方向の点を得る
var x0 = vx > 0 ? dx[0] : vx < 0 ? dx[dx.length - 1] : Math.floor(px + vx);
var y0 = vy > 0 ? dy[0] : vy < 0 ? dy[dy.length - 1] : Math.floor(py + vy);
var z0 = vz > 0 ? dz[0] : dz[dz.length - 1];
// x軸進行方向の面
for(var i = 0; i < dy.length; i++){
for(var j = 0; j < dz.length; j++){
if(this.isMapChipHit(x0, dy[i], dz[j])){
return true;
}
}
}
// y軸進行方向の面
for(var i = 0; i < dz.length; i++){
for(var j = 0; j < dx.length; j++){
if(this.isMapChipHit(dx[j], y0, dz[i])){
return true;
}
}
}
// z軸進行方向の面
for(var i = 0; i < dx.length; i++){
for(var j = 0; j < dy.length; j++){
if(this.isMapChipHit(dx[i], dy[j], z0)){
return true;
}
}
}
return false;
}
// 地面までの距離
this.getHeight = function(character){
var h_length = 2 + Math.floor(character.radius * 2);
// x軸を等分割してmap上の点を得る
var dx = new Array(h_length);
var temp0 = character.x + character.vx + character.radius;
var temp1 = character.x + character.vx - character.radius;
for(var i = 0; i < h_length; i++){
dx[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
}
// y軸を等分割してmap上の点を得る
var dy = new Array(h_length);
var temp0 = character.y + character.vy + character.radius;
var temp1 = character.y + character.vy - character.radius;
for(var i = 0; i < h_length; i++){
dy[i] = Math.floor(temp0 + (temp1 - temp0) * i / (h_length - 1));
}
// キャラクタ下方向で最も近い地面の高さを調べる
var k0 = Math.floor(character.z + character.vz);
var ground = 0;
for(var i = 0; i < dx.length; i++){
for(var j = 0; j < dy.length; j++){
for(var k = k0; k > 0; k--){
if(this.isMapChipHit(dx[i], dy[j], k - 1) && ground < k){
ground = k;
}
}
}
}
// 地面までの距離を返す
return character.z + character.vz - ground - 0.01;
}
// mapとの衝突処理 衝突していた場合はキャラクタの位置と速度が変更される
// 引数であるcharacterに必要なフィールド
// x, y, z 位置
// vx, vy, vz 速度
// radius あたり判定の半径
// height あたり判定の高さ
this.collision = function(character){
var v0x, v0y, v0z;
var v1x, v1y, v1z;
var vx, vy;
// x軸方向で最初に衝突するマップチップ境界
if(character.vx > 0){
vx = Math.abs(Math.floor(character.x + character.radius + 1) - (character.x + character.radius));
if(vx == 1){vx = 0;}
}else{
vx = Math.abs(Math.floor(character.x - character.radius + 0.001) - (character.x - character.radius));
}
// y軸方向で最初に衝突するマップチップ境界
if(character.vy > 0){
vy = Math.abs(Math.floor(character.y + character.radius + 1) - (character.y + character.radius));
if(vy == 1){vy = 0;}
}else{
vy = Math.abs(Math.floor(character.y - character.radius + 0.001) - (character.y - character.radius));
}
// z軸上方向にシフトしたときに最初に現れるマップチップ境界
var pz = Math.floor(character.z + 1) - character.z;
if(pz == 1){pz = 0;}
// z軸上方向への最大乗り越えシフト量 高さの30%までなら乗り越えることができる
var pzmax = character.height * 0.3;
// xy軸方向衝突判定
var vxmax = Math.abs(character.vx);
var vymax = Math.abs(character.vy);
var hitFlagx = false;
var hitFlagy = false;
v0x = v0y = v1z = 0;
while(vx < vxmax || vy < vymax){
if(!hitFlagx && vx / vxmax < vy / vymax){
// x軸方向の衝突判定準備
var axis = 0;
var scale = vx / vxmax;
vx += 1;
}else if(!hitFlagy){
// y軸方向の衝突判定準備
var axis = 1;
var scale = vy / vymax;
vy += 1;
}else{
break;
}
if(!hitFlagx){v1x = v0x = character.vx * scale;}
if(!hitFlagy){v1y = v0y = character.vy * scale;}
// 衝突判定 判定する軸方向に0.5だけ進んだ状態で衝突するかを調べる
if(axis == 0){
v1x = v0x + (character.vx > 0 ? 0.5 : -0.5);
}else{
v1y = v0y + (character.vy > 0 ? 0.5 : -0.5);
}
if(this.isHit(character.x, character.y, character.z, v1x, v1y, v1z, character.radius, character.height)){
// 乗り越え判定
while(pz < pzmax){
var pz1 = character.z + pz;
if(character.vz >= 0 && !this.isHit(character.x, character.y, pz1, v1x, v1y, v1z, character.radius, character.height)){
character.z = pz1;
break;
}else{
pz += 1;
}
}
// 乗り越えしていなかったら衝突処理
if(pz >= pzmax){
if(axis == 0){
character.vx = v1x = v0x - (character.vx > 0 ? 0.01 : -0.01);
hitFlagx = true;
}else{
character.vy = v1y = v0y - (character.vy > 0 ? 0.01 : -0.01);
hitFlagy = true;
}
}
}
}
// z軸方向で最初に衝突するマップチップ境界
if(character.vz > 0){
v1z = Math.floor(character.z + character.height + 1) - (character.z + character.height) - 0.01;
}else{
v1z = Math.floor(character.z) - (character.z);
}
// z軸方向衝突判定
while(Math.abs(v1z) < Math.abs(character.vz)){
v0z = v1z;
v1z += character.vz > 0 ? 1 : -1;
if(this.isHit(character.x, character.y, character.z, character.vx, character.vy, v1z, character.radius, character.height)){
character.vz = v0z;
break;
}
}
// 最後に地面までの距離を返す
return this.getHeight(character);
}
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// メニュークラス
function Menu(){
this.vertBuffer1;
this.clorBuffer1;
this.texcBuffer1;
this.faceBuffer1;
this.vertBuffer2;
this.clorBuffer2;
this.texcBuffer2;
this.faceBuffer2;
// ----------------------------------------------------------------
// 初期化
var pushBuffer = function(vert, texc, clor, face, r, g, b, vx0, vy0, vx1, vy1, tx0, ty0, tx1, ty1){
var index = vert.length / 3;
vert.push(vx1); vert.push(vy0); vert.push(0.0);
vert.push(vx0); vert.push(vy0); vert.push(0.0);
vert.push(vx0); vert.push(vy1); vert.push(0.0);
vert.push(vx1); vert.push(vy1); vert.push(0.0);
clor.push(r); clor.push(g); clor.push(b);
clor.push(r); clor.push(g); clor.push(b);
clor.push(r); clor.push(g); clor.push(b);
clor.push(r); clor.push(g); clor.push(b);
texc.push(tx1); texc.push(ty0);
texc.push(tx0); texc.push(ty0);
texc.push(tx0); texc.push(ty1);
texc.push(tx1); texc.push(ty1);
face.push(index + 0);
face.push(index + 1);
face.push(index + 2);
face.push(index + 0);
face.push(index + 2);
face.push(index + 3);
}
this.init = function(e3d){
// 黒幕その他
var vert = new Array();
var clor = new Array();
var texc = new Array();
var face = new Array();
pushBuffer(vert, texc, clor, face, 0, 0, 0, 0, 0, 1, 1, 0.0625, 0.25, 0.0625, 0.25);
pushBuffer(vert, texc, clor, face, 1, 1, 1, -8, -8, 8, 8, 0.125, 0, 0.25, 0.5);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 16, 8, 32, 24, 0.750, 0, 0.875, 0.5);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 32, 8, 48, 24, 0.875, 0, 1.000, 0.5);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.000, 0.5, 0.125, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.125, 0.5, 0.250, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.250, 0.5, 0.375, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.375, 0.5, 0.500, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.500, 0.5, 0.625, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.625, 0.5, 0.750, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.750, 0.5, 0.875, 1);
pushBuffer(vert, texc, clor, face, 1, 1, 1, 0, 8, 16, 24, 0.875, 0.5, 1.000, 1);
this.vertBuffer1 = e3d.createVBO(vert);
this.clorBuffer1 = e3d.createVBO(clor);
this.texcBuffer1 = e3d.createVBO(texc);
this.faceBuffer1 = e3d.createIBO(face);
// キューブ
var vert = new Array();
var clor = new Array();
var face = new Array();
vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push(-1);
vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push( 1);
vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1);
vert.push( 1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1);
vert.push( 1); vert.push( 1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push( 1); vert.push(-1);
vert.push(-1); vert.push( 1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push(-1); vert.push( 1); vert.push(-1); vert.push( 1); vert.push( 1);
clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0); clor.push(1.0);
face.push( 0); face.push( 1); face.push( 2); face.push( 0); face.push( 2); face.push( 3);
face.push( 4); face.push( 5); face.push( 6); face.push( 4); face.push( 6); face.push( 7);
face.push( 8); face.push( 9); face.push(10); face.push( 8); face.push(10); face.push(11);
face.push(12); face.push(13); face.push(14); face.push(12); face.push(14); face.push(15);
face.push(16); face.push(17); face.push(18); face.push(16); face.push(18); face.push(19);
face.push(20); face.push(21); face.push(22); face.push(20); face.push(22); face.push(23);
this.vertBuffer2 = e3d.createVBO(vert);
this.clorBuffer2 = e3d.createVBO(clor);
this.faceBuffer2 = e3d.createIBO(face);
this.texcBuffer2 = new Array();
for(var i = 0; i < 64; i++){
var texc = new Array();
var v0 = Math.floor(i / 4) * 0.0625;
var v1 = v0 + 0.0625;
var u = (i % 4) * 0.2500;
var u0 = u + 0.0000; var u1 = u0 + 0.0625;
texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
var u0 = u + 0.1875; var u1 = u0 + 0.0625;
texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
var u0 = u + 0.0625; var u1 = u0 + 0.0625;
texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
var u0 = u + 0.1250; var u1 = u0 + 0.0625;
texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
texc.push(u0); texc.push(v0); texc.push(u0); texc.push(v1); texc.push(u1); texc.push(v1); texc.push(u1); texc.push(v0);
this.texcBuffer2[i] = e3d.createVBO(texc);
}
}
// ----------------------------------------------------------------
// 描画
var tmpmat = new Matrix();
this.draw1 = function(e3d, mat){
e3d.bindBuf(this.vertBuffer1, this.clorBuffer1, this.texcBuffer1, this.faceBuffer1);
// 黒幕
tmpmat.copy(mat);
tmpmat.mulScale(320, 32, 1);
e3d.setMatrix(tmpmat);
e3d.draw(0, 6);
tmpmat.copy(mat);
tmpmat.mulTranslate(0, 288, 0);
tmpmat.mulScale(320, 32, 1);
e3d.setMatrix(tmpmat);
e3d.draw(0, 6);
// バツ印
tmpmat.copy(mat);
if(ctrl.selectedChip == 8){
tmpmat.mulTranslate(ctrl.mousex, ctrl.mousey, 0);
}else{
tmpmat.mulTranslate(256, 16, 0);
}
e3d.setMatrix(tmpmat);
e3d.draw(6, 6);
// 矢印
e3d.setMatrix(mat);
e3d.draw(12, 6);
e3d.draw(18, 6);
// スクロールゲージ
e3d.draw(24 + ctrl.selectedLine * 6, 6);
}
this.draw2 = function(e3d, mat){
e3d.bindVertBuf(this.vertBuffer2);
e3d.bindClorBuf(this.clorBuffer2);
e3d.bindFaceBuf(this.faceBuffer2);
var fuga = 2;
for(var i = 0; i < 8; i++){
e3d.bindTexcBuf(this.texcBuffer2[i + ctrl.selectedLine * 8]);
tmpmat.copy(mat);
if(i == ctrl.selectedChip){
if(ctrl.selectedx >= 0){continue;}
tmpmat.mulTranslate(ctrl.mousex, ctrl.mousey, 0);
tmpmat.mulScale(1.3, 1.3, 0);
}else{
tmpmat.mulTranslate(64 + i * 24, 16, 0);
tmpmat.mulScale(1, 1, 0);
}
tmpmat.mulRotX(-ctrl.roth);
tmpmat.mulRotY(ctrl.rotv + Math.PI);
tmpmat.mulScale(-6, -6, -6);
e3d.setMatrix(tmpmat);
e3d.draw(0, 36);
}
}
this.draw3 = function(e3d, mat){
if(ctrl.selectedx < 0 || ctrl.selectedChip < 0 || 8 < ctrl.selectedChip){return;}
var texid = 0;
if(ctrl.selectedChip < 8){texid = ctrl.selectedLine * 8 + ctrl.selectedChip;}
e3d.bindBuf(this.vertBuffer2, this.clorBuffer2, this.texcBuffer2[texid], this.faceBuffer2);
tmpmat.copy(mat);
tmpmat.mulTranslate(ctrl.selectedx + 0.5, ctrl.selectedy + 0.5, ctrl.selectedz + 0.5);
if(ctrl.selectedChip < 8){
tmpmat.mulScale(0.3, 0.3, 0.3);
}else{
tmpmat.mulScale(0.55, 0.55, 0.55);
}
e3d.setMatrix(tmpmat);
e3d.draw(0, 36);
}
}
// ここまでライブラリ部分
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// グローバル変数
var e3d = new Engine3d();
var map = new Map();
var character = new Character();
var shadow = new Shadow();
var player = new Player();
var menu = new Menu();
// テクスチャ
var mapTexture;
var ctrlTexture;
var utilTexture;
var playerTexture;
var shadowTexture;
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
window.onload = function(){
// 初期化
e3d.init(document.getElementById("screen"));
ctrl.init(e3d, document.getElementById("screen"));
character.init(e3d);
shadow.init(e3d);
menu.init(e3d);
mapTexture = e3d.loadTexture("http://jsrun.it/assets/s/3/P/0/s3P04.png");
ctrlTexture = e3d.loadTexture("http://jsrun.it/assets/h/4/Q/Q/h4QQL.png");
utilTexture = e3d.loadTexture("http://jsrun.it/assets/1/G/6/u/1G6ua.png");
playerTexture = e3d.loadTexture("http://jsrun.it/assets/6/n/Q/g/6nQgc.png");
shadowTexture = e3d.loadTexture("http://jsrun.it/assets/y/u/C/2/yuC2U.png");
map.init(e3d, [[
[ 4, 4, 4, 4, 4],
[ 4, 4, 4, 4, 4],
[ 4, 4, 4, 4, 4],
[ 4, 4, 4, 4, 4],
[ 4, 4, 4, 4, 4],
],[
[ 0, 0, 0, 10, 10],
[ 0, 13, 0, 0, 10],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
],[
[ 0, 14, 0, 0, 10],
[14, 13, 14, 0, 0],
[ 0, 14, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
],[
[ 0, 14, 0, 0, 0],
[14, 13, 14, 0, 0],
[ 0, 14, 0, 0, 0],
[ 0, 0, 0, 17, 0],
[ 0, 0, 0, 0, 0],
],[
[ 0, 0, 0, 0, 0],
[ 0, 14, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
],[
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0],
]]);
ctrl.roth = Math.PI / 180 * 30;
// 描画処理を毎秒 30 回呼び出す
setInterval(redrawScene, 1000 / 30);
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// メインループ
function redrawScene(){
// 計算
player.calc();
// 3D描画
e3d.clear();
e3d.setDepthMode(true);
// カメラ
var mat = new Matrix();
ctrl.createWorldMatrix(mat, player.x, player.y, player.z);
// マップ
e3d.bindTex(mapTexture, 1);
map.draw(e3d, mat, 0, 0, 0);
menu.draw3(e3d, mat);
// キャラクター
e3d.bindTex(playerTexture, 0);
player.draw(character, e3d, mat);
// 影
e3d.bindTex(shadowTexture, 0);
shadow.draw(e3d, mat, player.x, player.y, player.z - player.altitude, player.radius * 2);
// 2D描画
e3d.setDepthMode(false);
mat.ortho(0, 0, 320, 320);
// メニュー
e3d.bindTex(utilTexture, 1);
menu.draw1(e3d, mat);
e3d.bindTex(mapTexture, 1);
menu.draw2(e3d, mat, map);
// コントローラ
e3d.bindTex(ctrlTexture, 0);
ctrl.draw(e3d, mat);
// ページに反映させる
e3d.flush();
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// プレイヤークラス
function Player(){
this.action = 0;
this.rotate = Math.PI / 180 * 90;
// あたり判定用キャラクタサイズ
this.radius = 0.3;
this.height = 1.0;
// キャラクタ画像倍率
this.size = 1.5;
// 位置
this.x = 2.5;
this.y = 2.5;
this.z = 1;
// 速度
this.vx = 0;
this.vy = 0;
this.vz = 0;
// 地面との距離
this.altitude = 0;
// 計算
this.calc = function(){
this.action++;
// 方向の計算
if(ctrl.kup){
if(ctrl.krt){this.rotate = Math.PI * 1.75 + ctrl.rotv;}
else if(ctrl.klt){this.rotate = Math.PI * 1.25 + ctrl.rotv;}
else{this.rotate = Math.PI * 1.50 + ctrl.rotv;}
}else if(ctrl.kdn){
if(ctrl.krt){this.rotate = Math.PI * 0.25 + ctrl.rotv;}
else if(ctrl.klt){this.rotate = Math.PI * 0.75 + ctrl.rotv;}
else{this.rotate = Math.PI * 0.50 + ctrl.rotv;}
}else if(ctrl.krt){this.rotate = Math.PI * 0.00 + ctrl.rotv;
}else if(ctrl.klt){this.rotate = Math.PI * 1.00 + ctrl.rotv;
}else{this.action = 0;}
// 水平軸方向速度の計算
if(this.action > 0){
var speed = 3 / 30;
this.vx = speed * Math.cos(this.rotate);
this.vy = speed * Math.sin(this.rotate);
}else{
this.vx = 0;
this.vy = 0;
}
// 垂直軸方向速度の計算
if(this.altitude > 0.1){
// 地面との距離がある場合は空中
this.action = 1;
this.vz -= 1.2 / 30;
if(ctrl.k_z && this.vz < 0){
// 多段ジャンプ
this.vz = 15 / 30;
}
}else if(ctrl.k_z){
// ジャンプ
this.vz = 15 / 30;
}else if(ctrl.k_x){
this.action = 1;
this.vx = 0;
this.vy = 0;
}
// あたり判定
this.altitude = map.collision(this);
// 位置の計算
this.x += this.vx;
this.y += this.vy;
this.z += this.vz;
}
// 描画
this.draw = function(character, e3d, mat){
// 歩行アクション
var type = 0;
if(this.action > 0){
switch(Math.floor(this.action / 4) % 4){
case 0: type = 1; break;
case 2: type = 3; break;
default: type = 2; break;
}
}
// 描画
character.draw(e3d, mat, this.rotate, type, this.x, this.y, this.z, this.size);
}
}
// ----------------------------------------------------------------
// ----------------------------------------------------------------
// ----------------------------------------------------------------
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer