簡易版 デモ
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>vue.js 落ち物パズルゲーム ver.2</title>
<style>
table {background-color:gray;}
td {width: 30px;height: 30px;border-radius: 15px;}
.box{display: flex;}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.7/vue.min.js"></script>
</head>
<body>
<div id="app">
<h3>vue.js 落ち物パズルゲーム ver.2</h3>
<p>startを押してからキーボードの矢印キーで操作します</p>
<input type="button" @click="startFn" value="START" v-if="!gameStart">
<input type="button" @click="restartFn" value="RESTART" v-if="gameOver">
<div class="box" v-if="gameStart">
<table>
<tr v-for="i in H">
<td v-for="j in W" :style="{ backgroundColor:colors[yx[i-1][j-1]] }"></td>
</tr>
</table>
<table>
<tr v-for="i in 2">
<td :style="{ backgroundColor: colors[next[i - 1]] }"></td>
</tr>
</table>
</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
H: 13,
W: 6,
yx: [],
block: [],
blockX: 0,
blockY: 0,
blockMemo: [],
blockColor: [],
next : [Math.floor(Math.random() * 5) + 1, Math.floor(Math.random() * 5) + 1],
timerID: null,
otitaFlag:false,
gameStart: false,
gameOver: false,
colors: ['gray', 'red', 'blue', 'green', 'yellow', 'purple'],
saveData : null,
},
methods: {
startFn: function() {
this.saveData = JSON.stringify(this.$data);
for (var i = 0; i < this.H; i++) {
this.yx[i] = [];
for (var j = 0; j < this.W; j++) this.yx[i][j] = 0;
}
this.gameStart = true;
this.createFn();
this.timerID = setInterval(this.fallFn, 500);
},
createFn: function() {
this.blockMemo = [];
this.blockX = 2;
this.blockY = 1;
this.block = [[0, 0], [0, -1]];
this.blockColor = [this.next[1], this.next[0]];
this.next = [Math.floor(Math.random() * 5) + 1, Math.floor(Math.random() * 5) + 1];
this.drawFn(false, 0, 0);
},
fallFn: function() {
if (this.isMoveFn(false, 0, 1)) this.drawFn(false, 0, 1);
else {
this.otitaFlag = true;
clearInterval(this.timerID);
this.timerID = setInterval(this.rensaFn, 200);
}
},
isMoveFn: function(rotate, dx, dy) {
var yx = this.yx.map(v => v.slice());
var block = this.block.map(v => v.slice());
this.blockMemo.forEach(v => {
yx[v[1]][v[0]] = 0;
});
if (rotate) block = block.map(v => [v[1] * -1, v[0]]);
var flag = block.every(v => {
var x = v[0] + this.blockX + dx;
var y = v[1] + this.blockY + dy;
return (y >= 0 && y < this.H && x >= 0 && x < this.W && yx[y][x] == 0);
});
return flag;
},
drawFn: function(rotate, dx, dy) {
this.blockMemo.forEach(v => {
this.yx[v[1]][v[0]] = 0;
});
this.blockMemo = [];
if (rotate) this.block = this.block.map(v => [v[1] * -1, v[0]]);
this.blockX += dx;
this.blockY += dy;
this.block.forEach((v, i) => {
var x = v[0] + this.blockX;
var y = v[1] + this.blockY;
if (this.yx[y][x] != 0) this.gameOver = true;
this.yx[y][x] = this.blockColor[i];
this.blockMemo.push([x, y]);
});
if (this.gameOver) clearInterval(this.timerID);
this.$forceUpdate();
},
rensaFn:function(){
if (this.kuzureruFn() || this.removeFn()) this.$forceUpdate();
else {
clearInterval(this.timerID);
this.timerID = setInterval(this.fallFn, 500);
this.createFn();
this.otitaFlag = false;
}
},
kuzureruFn: function() {
var flag= false;
for (var i = this.H - 2; i >= 0; i--) for (var j = 0; j < this.W; j++) {
if (this.yx[i + 1][j] == 0 && this.yx[i][j] != 0) {
this.yx[i + 1][j] = this.yx[i][j];
this.yx[i][j] = 0;
flag = true;
}
}
return flag;
},
removeFn: function() {
var flag = false;
var dydx = [[-1, 0], [0, 1], [1, 0], [0, -1]];
for (var i = 0; i < this.H; i++) for (var j = 0; j < this.W; j++) {
var iro = this.yx[i][j];
if (iro == 0) continue;
var yx = this.yx.map(v => v.slice());
yx[i][j] = 0;
var onazi = 1;
var memo = [[i, j]];
while (memo.length != 0) {
var m = memo.shift();
dydx.forEach(v => {
var y = m[0] + v[0];
var x = m[1] + v[1];
if (y >= 0 && y < this.H && x >= 0 && x < this.W && yx[y][x] == iro) {
onazi++;
memo.push([y, x]);
yx[y][x] = 0;
}
});
}
if (onazi >= 4) {
flag = true;
this.yx = yx.map(v => v.slice());
}
}
return flag;
},
keydownFn: function(rotate, dx, dy) {
if (!this.gameOver && !this.otitaFlag && this.isMoveFn(rotate, dx, dy)) this.drawFn(rotate, dx, dy);
},
restartFn: function() {
var obj = JSON.parse(this.saveData);
for (var k in obj) this[k] = obj[k];
this.startFn();
},
}
});
document.onkeydown = function(e) {
if (e.keyCode == 38) vm.keydownFn(true, 0, 0); //up
else if (e.keyCode == 37) vm.keydownFn(false, -1, 0); //left
else if (e.keyCode == 40) vm.keydownFn(false, 0, 1); //down
else if (e.keyCode == 39) vm.keydownFn(false, 1, 0); //right
};
</script>
</body>
</html>
CSS3 ぷよぷよ
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>CSS3 ぷよぷよ</title>
<style>
.box {
width: 50px;
height: 50px;
animation: bounce 1.0s infinite ease-in-out;
box-shadow: 5px 5px 15px 5px rgba(0,0,0,0.6) inset;
font-size: 15px;
color:white;
font-weight: bold;
text-align: center;
}
@keyframes bounce {
0%, 100% { transform: scale(0.9) }
50% { transform: scale(1.0) }
}
.red {background-color:red;border-radius: 20px;}
.blue {background-color:blue;border-radius: 10px 20px 10px 25px / 10px 30px 10px 40px;}
.green {background-color:green;border-radius: 20px;}
.yellow {background-color:yellow;border-radius: 25px 25px 10px 10px / 50px 50px 10px 10px;}
.purple {background-color:purple;border-radius: 20px;}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.7/vue.min.js"></script>
</head>
<body>
<div id="app">
<div v-for="i in 5" :class="['box', arr[i-1]]">0_0</div>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
arr : ["red","blue","green","yellow","purple"]
}
});
</script>
</body>
</html>