- 文字列表示・スコア表示を追加
- ES6ジェネレータによるゲームフローの実装
Last active
October 23, 2016 10:46
-
-
Save sfpgmr/af963e21286cc88d5937 to your computer and use it in GitHub Desktop.
ゲームとしての体裁を整える
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>スカッシュゲームを作る - スコア表示・ゲームスタート・ゲームオーバーの追加</title> | |
<meta name="keywords" content="WebGL,HTML5,three.js" /> | |
<meta name="description" content="WebGL,HTML5,three.js" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no" /> | |
<meta charset="UTF-8"> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r71/three.js"></script> | |
<style> | |
html { | |
width: 100%; | |
height: 100%; | |
margin: 0; | |
padding: 0; | |
} | |
body { | |
width: 100%; | |
height: 100%; | |
margin: 4px; | |
padding: 0; | |
border: 0; | |
text-align: center; | |
margin-left: auto; | |
margin-right: auto; | |
} | |
#console { | |
margin-left: auto; | |
margin-right: auto; | |
border: 0; | |
padding: 0; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="content"></div> | |
<script type="text/javascript"> | |
const ASCII_CHARS = [ | |
[ | |
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,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,0,0,0, | |
0,0,1,0,0 | |
], | |
[ | |
0,1,0,1,0, | |
0,1,0,1,0, | |
0,0,0,0,0, | |
0,0,0,0,0, | |
0,0,0,0,0 | |
], | |
[ | |
0,1,0,1,0, | |
1,1,1,1,1, | |
0,1,0,1,0, | |
1,1,1,1,1, | |
0,1,0,1,0 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,1,0,0, | |
1,1,1,1,1, | |
0,0,1,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,0,0,1, | |
1,1,0,1,0, | |
0,0,1,0,0, | |
0,1,0,1,1, | |
1,0,0,1,1 | |
], | |
[ | |
1,1,1,0,0, | |
1,0,1,0,0, | |
0,1,1,0,1, | |
1,0,0,1,0, | |
1,1,1,0,1 | |
], | |
[ | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,0,0,0, | |
0,0,0,0,0, | |
0,0,0,0,0 | |
], | |
[ | |
0,0,1,1,0, | |
0,1,0,0,0, | |
0,1,0,0,0, | |
0,1,0,0,0, | |
0,0,1,1,0 | |
], | |
[ | |
0,1,1,0,0, | |
0,0,0,1,0, | |
0,0,0,1,0, | |
0,0,0,1,0, | |
0,1,1,0,0 | |
], | |
[ | |
1,0,1,0,1, | |
0,1,1,1,0, | |
1,1,1,1,1, | |
0,1,1,1,0, | |
1,0,1,0,1 | |
], | |
[ | |
0,0,1,0,0, | |
0,0,1,0,0, | |
1,1,1,1,1, | |
0,0,1,0,0, | |
0,0,1,0,0 | |
], | |
[ | |
0,0,0,0,0, | |
0,0,0,0,0, | |
0,0,0,0,0, | |
0,0,1,0,0, | |
0,1,0,0,0 | |
], | |
[ | |
0,0,0,0,0, | |
0,0,0,0,0, | |
1,1,1,1,1, | |
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,1,0,0 | |
], | |
[ | |
0,0,0,0,1, | |
0,0,0,1,0, | |
0,0,1,0,0, | |
0,1,0,0,0, | |
1,0,0,0,0 | |
], | |
[1,1,1,1,1, | |
1,1,0,0,1, | |
1,0,1,0,1, | |
1,0,0,1,1, | |
1,1,1,1,1], | |
[0,1,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,1,1,1,0], | |
[1,1,1,1,1, | |
1,0,0,0,1, | |
0,0,1,1,0, | |
0,1,0,0,0, | |
1,1,1,1,1], | |
[1,1,1,1,1, | |
0,0,0,0,1, | |
1,1,1,1,1, | |
0,0,0,0,1, | |
1,1,1,1,1], | |
[1,0,0,1,0, | |
1,0,0,1,0, | |
1,0,0,1,0, | |
1,1,1,1,1, | |
0,0,0,1,0], | |
[1,1,1,1,1, | |
1,0,0,0,0, | |
1,1,1,1,1, | |
0,0,0,0,1, | |
1,1,1,1,1], | |
[1,1,1,1,1, | |
1,0,0,0,0, | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1], | |
[1,1,1,1,1, | |
1,0,0,1,0, | |
0,0,1,0,0, | |
0,1,0,0,0, | |
1,0,0,0,0], | |
[1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1], | |
[1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1, | |
0,0,0,0,1, | |
1,1,1,1,1], | |
[ | |
0,0,0,0,0, | |
0,0,1,0,0, | |
0,0,0,0,0, | |
0,0,1,0,0, | |
0,0,0,0,0 | |
], | |
[ | |
0,0,0,0,0, | |
0,0,1,0,0, | |
0,0,0,0,0, | |
0,0,1,0,0, | |
0,1,0,0,0 | |
], | |
[ | |
0,0,0,1,0, | |
0,0,1,0,0, | |
0,1,0,0,0, | |
0,0,1,0,0, | |
0,0,0,1,0 | |
], | |
[ | |
0,0,0,0,0, | |
1,1,1,1,1, | |
0,0,0,0,0, | |
1,1,1,1,1, | |
0,0,0,0,0 | |
], | |
[ | |
0,1,0,0,0, | |
0,0,1,0,0, | |
0,0,0,1,0, | |
0,0,1,0,0, | |
0,1,0,0,0 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
0,0,1,1,1, | |
0,0,0,0,0, | |
0,0,1,0,0 | |
], | |
[ | |
0,1,1,1,0, | |
1,0,0,0,1, | |
1,0,1,1,1, | |
1,0,0,0,0, | |
0,1,1,1,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,0,0,0,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,0, | |
1,0,0,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,0,0,0,0, | |
1,0,0,0,0, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,1,1,0, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,1,1,1,0 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,0,0,0,0 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,0,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,0,0,0,1 | |
], | |
[ | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0 | |
], | |
[ | |
1,1,1,1,1, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
1,0,1,0,0, | |
1,1,1,0,0 | |
], | |
[ | |
1,0,0,,1, | |
1,0,0,1,0, | |
1,1,1,0,0, | |
1,0,0,1,0, | |
1,0,0,0,1 | |
], | |
[ | |
1,0,0,0,0, | |
1,0,0,0,0, | |
1,0,0,0,0, | |
1,0,0,0,0, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,0,1,1, | |
1,0,1,0,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,0,0,0,1 | |
], | |
[ | |
1,0,0,0,1, | |
1,1,0,0,1, | |
1,0,1,0,1, | |
1,0,0,1,1, | |
1,0,0,0,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,0,0,0,0 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,0,0,1,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,1, | |
1,1,1,1,0, | |
1,0,0,0,1, | |
1,0,0,0,1 | |
], | |
[ | |
1,1,1,1,1, | |
1,0,0,0,0, | |
1,1,1,1,1, | |
0,0,0,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,1,1,1,1, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0 | |
], | |
[ | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,0,0,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,0,0,0,1, | |
1,0,0,0,1, | |
0,1,0,1,0, | |
0,1,0,1,0, | |
0,0,1,0,0 | |
], | |
[ | |
1,0,1,0,1, | |
1,0,1,0,1, | |
1,0,1,0,1, | |
1,0,1,0,1, | |
1,1,1,1,1 | |
], | |
[ | |
1,0,0,0,1, | |
0,1,0,1,0, | |
0,0,1,0,0, | |
0,1,0,1,0, | |
1,0,0,0,1 | |
], | |
[ | |
1,0,0,0,1, | |
0,1,0,1,0, | |
0,0,1,0,0, | |
0,0,1,0,0, | |
0,0,1,0,0 | |
], | |
[ | |
1,1,1,1,1, | |
0,0,0,1,0, | |
0,0,1,0,0, | |
0,1,0,0,0, | |
1,1,1,1,1 | |
] | |
]; | |
window.addEventListener('load', | |
function () { | |
'use strict'; | |
const WIDTH = 192; | |
const HEIGHT = 256; | |
var screen_width; | |
var screen_height; | |
var remain = 3; | |
var score = 0; | |
var renderer; | |
var x = 0; | |
var y = 0; | |
var dx = 3; | |
var dy = 3; | |
var px;// paddle x pos | |
function calcScreenSize() { | |
screen_width = document.body.clientWidth - 8; | |
screen_height = document.body.clientHeight - 8; | |
if (screen_width >= screen_height) { | |
screen_width = screen_height * WIDTH / HEIGHT; | |
} else { | |
screen_height = screen_width * HEIGHT / WIDTH; | |
} | |
} | |
calcScreenSize(); | |
renderer = new THREE.WebGLRenderer({ antialias: false /*, sortObjects: true */ }); | |
renderer.setSize(screen_width, screen_height); | |
renderer.setClearColor(0x000000, 1); | |
renderer.domElement.id = 'console'; | |
renderer.domElement.style.zIndex = 0; | |
document.body.appendChild(renderer.domElement); | |
renderer.clear(); | |
// カメラを工夫し、Z座標が0の時座標指定が仮想画面サイズの位置となるようにする | |
var camera = new THREE.PerspectiveCamera(90, WIDTH / HEIGHT, 0.1, 1000); | |
camera.position.z = HEIGHT / 2; | |
var scene = new THREE.Scene(); | |
var geometry = new THREE.PlaneBufferGeometry(4, 4); | |
var material = new THREE.MeshBasicMaterial({ color: 0xffffff }); | |
var ball = new THREE.Mesh(geometry, material); | |
var paddle = new THREE.Mesh(new THREE.PlaneBufferGeometry(32, 4), new THREE.MeshBasicMaterial({ color: 0xffffff })); | |
paddle.position.y = -100; | |
// 文字コード -> mesh 変換 | |
var asciiCharObjs4 = []; | |
var asciiCharObjs2 = []; | |
var asciiGeometry2 = new THREE.PlaneBufferGeometry(2, 2); | |
var asciiGeometry4 = new THREE.PlaneBufferGeometry(4,4); | |
for(var i = 0,l = ASCII_CHARS.length;i < l;++i ){ | |
var c2 = new THREE.Object3D(); | |
var c4 = new THREE.Object3D(); | |
asciiCharObjs2.push(c2); | |
asciiCharObjs4.push(c4); | |
for(var cy = 0;cy < 5;++cy){ | |
for(var cx = 0;cx < 5;++cx){ | |
if(ASCII_CHARS[i][cy * 5 + cx]){ | |
var mesh = new THREE.Mesh(asciiGeometry2,material); | |
mesh.position.x = cx * 2; | |
mesh.position.y = 10 - cy * 2; | |
c2.add(mesh); | |
var mesh = new THREE.Mesh(asciiGeometry4,material); | |
mesh.position.x = cx * 4; | |
mesh.position.y = 10 - cy * 4; | |
c4.add(mesh); | |
} | |
} | |
} | |
} | |
function createStringMesh(str,size){ | |
if(!size) size = 2; | |
var strObj = new THREE.Object3D(); | |
var asciiChars = size == 4?asciiCharObjs4:asciiCharObjs2; | |
for(var i = 0,l = str.length;i < l;++i){ | |
var sx = i * 6 * size; | |
var c = str.charCodeAt(i) - 0x20; | |
var co = asciiChars[c].clone(); | |
co.position.x = sx; | |
strObj.add(co); | |
} | |
return strObj; | |
} | |
// PRESS_MOUSE 文字列 | |
const PRESS_MOUSE = 'PRESS MOUSE BTN'; | |
var pressMouse = createStringMesh(PRESS_MOUSE); | |
pressMouse.position.x = - PRESS_MOUSE.length * 2 * 6 / 2; | |
pressMouse.position.y = 0; | |
scene.add(pressMouse); | |
// Title | |
const TITLE = 'SQUASH'; | |
var titleObj = createStringMesh(TITLE,4); | |
titleObj.position.x = - TITLE.length * 4 * 6 / 2; | |
titleObj.position.y = 70; | |
scene.add(titleObj); | |
// GAME OVER | |
const GAME_OVER = 'GAME OVER'; | |
var gameOverObj = createStringMesh(GAME_OVER,2); | |
gameOverObj.position.x = - GAME_OVER.length * 2 * 6 / 2; | |
gameOverObj.position.y = 40; | |
scene.add(gameOverObj); | |
// スコア表示用 | |
var scoreObj = new THREE.Object3D(); | |
for(var i = 0;i < 5;++i){ | |
var sx = i * 6 * 2; | |
var digit = new THREE.Object3D(); | |
scoreObj.add(digit); | |
for(var j = 0;j < 10;++j){ | |
var n = asciiCharObjs2[0x10 + j].clone(); | |
n.position.x = sx; | |
n.visible = false; | |
digit.add(n); | |
} | |
} | |
scoreObj.position.y = 110; | |
scoreObj.position.x = - 6 * 2 * 5 / 2; | |
scoreObj.children[0].children[0].visible = true; | |
scoreObj.children[1].children[0].visible = true; | |
scoreObj.children[2].children[0].visible = true; | |
scoreObj.children[3].children[0].visible = true; | |
scoreObj.children[4].children[0].visible = true; | |
scene.add(scoreObj); | |
var scoreBackup = score; | |
function updateScore(){ | |
if(score > 99999){ | |
score = 99999; | |
} | |
var c5 = parseInt(score / 10000) % 10; | |
var c4 = parseInt(score / 1000) % 10; | |
var c3 = parseInt(score / 100) % 10; | |
var c2 = parseInt(score / 10) % 10; | |
var c1 = parseInt(score) % 10; | |
var b5 = parseInt(scoreBackup / 10000) % 10; | |
var b4 = parseInt(scoreBackup / 1000) % 10; | |
var b3 = parseInt(scoreBackup / 100) % 10; | |
var b2 = parseInt(scoreBackup / 10) % 10; | |
var b1 = parseInt(scoreBackup) % 10; | |
scoreObj.children[0].children[b5].visible = false; | |
scoreObj.children[0].children[c5].visible = true; | |
scoreObj.children[1].children[b4].visible = false; | |
scoreObj.children[1].children[c4].visible = true; | |
scoreObj.children[2].children[b3].visible = false; | |
scoreObj.children[2].children[c3].visible = true; | |
scoreObj.children[3].children[b2].visible = false; | |
scoreObj.children[3].children[c2].visible = true; | |
scoreObj.children[4].children[b1].visible = false; | |
scoreObj.children[4].children[c1].visible = true; | |
scoreBackup = score; | |
} | |
// 残数表示 | |
var remainObj = new THREE.Object3D(); | |
for(var j = 0;j < 10;++j){ | |
var n = asciiCharObjs2[j + 0x10].clone(); | |
n.visible = false; | |
remainObj.add(n); | |
} | |
remainObj.position.y = -124; | |
remainObj.position.x = 70; | |
var remainBackup = 0; | |
function updateRemain(){ | |
remainObj.children[remain].visible = true; | |
remainObj.children[remainBackup].visible = false; | |
remainBackup = remain; | |
} | |
scene.add(remainObj); | |
renderer.domElement.addEventListener('mousemove', function (e) { | |
var ex = e.clientX; | |
var ey = e.clientY; | |
var rect = e.target.getBoundingClientRect(); | |
ex -= rect.left; | |
ey -= rect.top; | |
px = ex * WIDTH / screen_width - WIDTH / 2; | |
//paddle.position.x = x * WIDTH / screen_width - WIDTH / 2; | |
}); | |
var mousedown = false; | |
renderer.domElement.addEventListener('mousedown',function(e){ | |
mousedown = true; | |
}); | |
function mouseCheck(){ | |
var ret = mousedown; | |
mousedown = false; | |
return ret; | |
} | |
window.addEventListener('resize', function () { | |
calcScreenSize(); | |
renderer.setSize(screen_width, screen_height); | |
}); | |
scene.add(ball); | |
scene.add(paddle); | |
// ジェネレータによるゲームメインの実装 | |
function* game(){ | |
while(true){ | |
// init | |
remain = 3; | |
updateRemain(); | |
x = 0; | |
y = 0; | |
dx = 2; | |
dy = 2; | |
mousedown = false; | |
titleObj.visible = true; | |
paddle.visible = false; | |
ball.visible = false; | |
pressMouse.visible = true; | |
remainObj.visible = false; | |
gameOverObj.visible = false; | |
// game start wait | |
var start = false; | |
while(!mouseCheck() && !start){ | |
for(var i = 0;i < 10;++i ){ | |
if(mouseCheck()){ | |
start = true; | |
break; | |
} | |
yield; | |
} | |
pressMouse.visible = !pressMouse.visible; | |
} | |
score = 0; | |
updateScore(); | |
titleObj.visible = false; | |
pressMouse.visible = false; | |
paddle.visible = true; | |
ball.visible = true; | |
remainObj.visible = true; | |
// game play | |
while(remain > 0){ | |
if(!play()){ | |
x = 0; | |
y = 0; | |
dx = 2; | |
dy = 2; | |
remain--; | |
updateRemain(); | |
} else { | |
yield; | |
}; | |
} | |
// game over | |
gameOverObj.visible = true; | |
for(var i = 0;i < 5 * 20;++i){ | |
yield; | |
} | |
gameOverObj.visible =false; | |
continue; | |
} | |
} | |
function play(){ | |
// ボールの動き | |
var bx = x, by = y; | |
x += dx; | |
y += dy; | |
if (x > (WIDTH / 2) || x < (-WIDTH / 2)) { | |
dx = -dx; | |
x += dx; | |
} | |
if (y > (HEIGHT / 2) ) { | |
dy = -dy; | |
y += dy; | |
} | |
if(y < (-HEIGHT / 2)){ | |
return false; | |
} | |
ball.position.x = x; | |
ball.position.y = y; | |
// パドルとの衝突判定 | |
var sx, sy, ex, ey; | |
if (x >= bx) { | |
sx = bx - 2; | |
ex = x + 2; | |
} else { | |
sx = x - 2; | |
ex = bx + 2; | |
} | |
if (y <= by) { | |
sy = by - 2; | |
ey = y + 2; | |
} else { | |
sy = y - 2; | |
ey = by + 2; | |
} | |
paddle.position.x = px; | |
var psx = paddle.position.x - 16, pex = paddle.position.x + 16, psy = paddle.position.y - 2, pey = paddle.position.y + 2; | |
if (sy <= pey && psy <= ey && sx <= pex && psx <= sx) { | |
var cx = -100 * dy / dx; | |
var cy = -100; | |
y += 2; | |
dy = -dy; | |
y += dy; | |
++score; | |
updateScore(); | |
} | |
return true; | |
} | |
// | |
var g = game(); | |
function render() { | |
requestAnimationFrame(render); | |
renderer.render(scene, camera); | |
g.next(); | |
} | |
render(); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment