자바스크립트로 테트리스를 만들어 보았다.
Javascript Tetris
← : left, → : right, ↑ : rotate, ↓ down, space: drop
Level:Score:
Javascript code - expand
<script type="text/javascript">
var VK_LEFT = 37;
var VK_RIGHT = 39;
var VK_DOWN = 40;
var VK_UP = 38;
var VK_SPACE = 32;
function get(obj) {
return (typeof obj == "string") ? document.getElementById(obj) : obj;
}
function Tetris(eltId, levelElt, scoreElt, gameoverElt, nextElt) {
this.init(eltId, levelElt, scoreElt, gameoverElt, nextElt);
}
Tetris.prototype.init = function(eltId, levelElt, scoreElt, gameoverElt, nextElt) {
// map size
this.MAP_WIDTH = 12;
this.MAP_HEIGHT = 20;
// current block
this.curTet = 0;
this.curRot = 0;
this.curPos = {x:0, y:0};
// tet
this.tet = new Array(7);
this.tet[0] = new Array(2);
this.tet[0][0] = new Array({x:0,y:0},{x:1,y:0},{x:2,y:0},{x:3,y:0});
this.tet[0][1] = new Array({x:0,y:0},{x:0,y:1},{x:0,y:2},{x:0,y:3});
this.tet[1] = new Array(2);
this.tet[1][0] = new Array({x:0,y:0},{x:1,y:0},{x:1,y:1},{x:2,y:1});
this.tet[1][1] = new Array({x:1,y:0},{x:1,y:1},{x:0,y:1},{x:0,y:2});
this.tet[2] = new Array(2);
this.tet[2][0] = new Array({x:0,y:1},{x:1,y:1},{x:1,y:0},{x:2,y:0});
this.tet[2][1] = new Array({x:0,y:0},{x:0,y:1},{x:1,y:1},{x:1,y:2});
this.tet[3] = new Array(4);
this.tet[3][2] = new Array({x:0,y:0},{x:1,y:0},{x:2,y:0},{x:2,y:1});
this.tet[3][3] = new Array({x:1,y:0},{x:1,y:1},{x:1,y:2},{x:0,y:2});
this.tet[3][0] = new Array({x:0,y:0},{x:0,y:1},{x:1,y:1},{x:2,y:1});
this.tet[3][1] = new Array({x:1,y:0},{x:0,y:0},{x:0,y:1},{x:0,y:2});
this.tet[4] = new Array(4);
this.tet[4][2] = new Array({x:0,y:0},{x:1,y:0},{x:2,y:0},{x:0,y:1});
this.tet[4][3] = new Array({x:1,y:0},{x:1,y:1},{x:1,y:2},{x:0,y:0});
this.tet[4][0] = new Array({x:2,y:0},{x:0,y:1},{x:1,y:1},{x:2,y:1});
this.tet[4][1] = new Array({x:1,y:2},{x:0,y:0},{x:0,y:1},{x:0,y:2});
this.tet[5] = new Array(4);
this.tet[5][0] = new Array({x:0,y:1},{x:1,y:1},{x:2,y:1},{x:1,y:0});
this.tet[5][1] = new Array({x:0,y:0},{x:0,y:1},{x:0,y:2},{x:1,y:1});
this.tet[5][2] = new Array({x:0,y:0},{x:1,y:0},{x:2,y:0},{x:1,y:1});
this.tet[5][3] = new Array({x:1,y:0},{x:1,y:1},{x:1,y:2},{x:0,y:1});
this.tet[6] = new Array(1);
this.tet[6][0] = new Array({x:0,y:0},{x:1,y:0},{x:0,y:1},{x:1,y:1});
// map
this.map = new Array(this.MAP_HEIGHT);
for (var i = 0,limit = this.map.length; i < limit; i++) {
this.map[i] = new Array(this.MAP_WIDTH);
for (var x = 0, xlimit = this.map[i].length; x < xlimit; x++) {
this.map[i][x] = 0;
}
}
this.empty_line = new Array(this.MAP_WIDTH);
for (var x = 0, xlimit = this.MAP_WIDTH; x < xlimit; x++) {this.empty_line[x] = 0;}
// screen
this.elt = get(eltId);
this.inspire(this.elt);
// level
this.level_map = new Array(1000, 900, 800, 700, 600, 500, 400, 300, 200, 100);
this.level = 0;
this.levelElt = get(levelElt);
// score
this.score = 0;
this.scoreElt = get(scoreElt);
// game over
this.gameoverElt = get(gameoverElt);
// next
this.next = null;
this.nextElt = get(nextElt);
this.inspireNext(this.nextElt);
// status
this.state = "ready";
}
Tetris.prototype.inspire = function (elt) {
this.elt = elt;
this.elt.innerHTML = "";
for (var y = 0, ylimit = this.map.length; y < ylimit; y++) {
this.elt.innerHTML += "<div class='line'>";
for (var x = 0, xlimit = this.map[y].length; x < xlimit; x++) {
this.elt.innerHTML += "<span id='" + (x + "_" + y) + "' class='block'>0</span>";
}
this.elt.innerHTML += "</div>";
}
}
Tetris.prototype.inspireNext = function(nextElt) {
this.nextElt = nextElt;
this.nextElt.innerHTML = "";
for (var y = 0; y < 4; y++) {
this.nextElt.innerHTML += "<div class='line'>";
for (var x = 0; x < 4; x++) {
this.nextElt.innerHTML += "<span id='next" + (x + "_" + y) + "' class='block'>0</span>";
}
this.nextElt.innerHTML += "</div>";
}
}
Tetris.prototype.getMapBlock = function(x, y) {
return this.map[y][x];
}
Tetris.prototype.setMapBlock = function(x, y, type) {
this.map[y][x] = type;
}
Tetris.prototype.clearMap = function() {
// clear map
for (var y = 0; y < this.MAP_HEIGHT; y++) {
for (var x = 0; x < this.MAP_WIDTH; x++) {
this.setMapBlock(x, y, 0);
}
}
}
Tetris.prototype.gen = function() {
this.curPos = {x:(this.MAP_WIDTH / 2) - 2,y:0};
this.curRot = 0;
if (this.next == null) {
this.next = Math.floor(Math.random() * 10) % 7;
}
this.curTet = this.next;
var n = Math.floor(Math.random() * 10) % 7;
this.next = (n == this.curTet) ? ((n + (Math.floor(Math.random() * 10) % 6) + 1) % 7) : n;
this.dropDelay(1000);
if (this.checkCollid(this.curPos, this.curTet, this.curRot)) {
this.gameOver();
}
}
Tetris.prototype.sideWalk = function(offset) {
var nextPos = {x:(this.curPos.x + offset), y:this.curPos.y};
if (!this.checkCollid(nextPos, this.curTet, this.curRot))
this.curPos = nextPos;
}
Tetris.prototype.down = function() {
var nextPos = {x:this.curPos.x, y:(this.curPos.y + 1)};
if (!this.checkCollid(nextPos, this.curTet, this.curRot)) {
this.curPos = nextPos;
this.dropDelay(this.level_map[this.level]);
return true;
} else {
this.addToMap();
this.removeFull();
this.gen();
return false;
}
}
Tetris.prototype.rotate = function(offset) {
var cnt = this.tet[this.curTet].length;
var nextRot = (this.curRot + offset) % cnt;
if (!this.checkCollid(this.curPos, this.curTet, nextRot))
this.curRot = nextRot;
}
Tetris.prototype.checkCollid = function(pos, type, rot) {
var b = this.tet[type][rot];
for (var i = 0, limit = b.length; i < limit; i++) {
var x = pos.x + b[i].x;
var y = pos.y + b[i].y;
if (x < 0 || x >= this.MAP_WIDTH) {
return true;
} else if (y < 0 || y >= this.MAP_HEIGHT) {
return true;
} else if (this.getMapBlock(x, y) != 0) {
return true;
}
}
return false;
}
Tetris.prototype.addToMap = function() {
var elt = this.tet[this.curTet][this.curRot];
for (var i = 0, limit = elt.length; i < limit; i++) {
this.setMapBlock(this.curPos.x + elt[i].x, this.curPos.y + elt[i].y, this.curTet + 1);
}
}
Tetris.prototype.removeFull = function() {
for (var y = this.MAP_HEIGHT - 1; y >= 0; y--) {
var cnt = 0;
for (var x = 0; x < this.MAP_WIDTH; x++) {
if (this.getMapBlock(x, y) == 0)
break;
cnt++;
}
if (cnt == this.MAP_WIDTH) {
for (var cy = y; cy > 0; cy--) {
this.map[cy] = this.map[cy-1].slice();
}
this.map[0] = this.empty_line.slice();
this.score += 25;
this.level = Math.min(Math.floor((this.score / 250)), this.level_map.length - 1);
y++;
}
}
}
Tetris.prototype.dropTimer = null;
Tetris.prototype.drop = function(interval) {
if (this.state == "start") {
var ret = this.down();
this.update();
if (ret) {
var me = this;
clearTimeout(this.dropTimer);
this.dropTimer = setTimeout(function() {me.drop(interval);}, interval);
}
}
}
Tetris.prototype.dropDelay = function(interval) {
var me = this;
clearTimeout(this.dropTimer);
this.dropTimer = setTimeout(function() {me.drop(me.level_map[me.level]);}, interval);
}
Tetris.prototype.start = function() {
this.clearMap();
this.inspire(this.elt);
this.inspireNext(this.nextElt);
this.score = 0;
this.level = 0;
this.gen();
this.state = "start";
this.gameoverElt.innerHTML = "";
this.update();
var me = this;
document.onkeydown = function(e) {me.handleInput(e);}
}
Tetris.prototype.gameOver = function() {
// gray map
for (var y = 0; y < this.MAP_HEIGHT; y++) {
for (var x = 0; x < this.MAP_WIDTH; x++) {
if (this.getMapBlock(x, y) != 0) {
this.setMapBlock(x, y, 8);
}
}
}
clearTimeout(this.dropTimer);
document.onkeydown = null;
this.state = "gameover";
this.update();
}
Tetris.prototype.stop = function() {
this.clearMap();
for (var y = 0; y < 4; y++) {
for (var x = 0; x < 4; x++) {
get("next" + (x + "_" + y)).className = "block";
}
}
this.next = null;
clearTimeout(this.dropTimer);
this.score = 0;
this.state = "stop";
document.onkeydown = null;
this.gameoverElt.innerHTML = "";
this.update();
}
Tetris.prototype.preventDefault = function(e) {
(e.preventDefault) ? e.preventDefault() : e.returnValue = false;
}
Tetris.prototype.handleInput = function(e) {
var ev = (window.event) ? window.event : e;
var keycode = (window.event) ? window.event.keyCode : e.which;
switch (keycode) {
case VK_LEFT:
this.sideWalk(-1);
this.preventDefault(ev);
break;
case VK_RIGHT:
this.sideWalk(1);
this.preventDefault(ev);
break;
case VK_UP:
this.rotate(1);
this.preventDefault(ev);
break;
case VK_DOWN:
this.down();
this.preventDefault(ev);
break;
case VK_SPACE:
while (this.down()){}
this.preventDefault(ev);
break;
default:
break;
}
this.update();
}
Tetris.prototype.render = function() {
for (var y = 0, ylimit = this.map.length; y < ylimit; y++) {
for (var x = 0, xlimit = this.map[y].length; x < xlimit; x++) {
var type = this.getMapBlock(x, y);
get(x + "_" + y).innerHTML = "0";
get(x + "_" + y).className = "block col" + type;
}
}
if (this.state == "start") {
this.drawTet(this.curPos, this.curTet, this.curRot);
} else if (this.state == "gameover") {
this.gameoverElt.innerHTML = "Game Over!!";
}
this.scoreElt.innerHTML = this.score;
this.levelElt.innerHTML = this.level + 1;
if (this.next != null)
this.drawNext(this.next);
}
Tetris.prototype.drawBlock = function(x, y, type) {
get(x + "_" + y).className = "block col" + type;
}
Tetris.prototype.drawTet = function(pos, type, rot) {
var t = this.tet[type][rot];
for (var i = 0, limit = t.length; i < limit; i++) {
this.drawBlock(pos.x + t[i].x, pos.y + t[i].y, type + 1);
}
}
Tetris.prototype.drawNext = function(type) {
for (var y = 0; y < 4; y++) {
for (var x = 0; x < 4; x++) {
get("next" + (x + "_" + y)).className = "block";
}
}
var t = this.tet[type][0];
for (var i = 0, limit = t.length; i < limit; i++) {
var n = get("next" + (t[i].x + "_" + t[i].y));
n.innerHTML = "0";
n.className = "block col" + (type + 1);
}
}
Tetris.prototype.update = function() {
this.render();
}
</script>
소스를 통해서 공부를 해볼려고 합니다.
답글삭제좋은 글 감사합니다.