(四)使用HTML5实现的俄罗斯方块
俄罗斯方块admin 发布于:2016-04-10 01:14:42
阅读:loading
从java版俄罗斯方块之后,总想着使用html5的canvas也来实现一下,除了一些运算之外就剩下一些表格的绘制了,所以觉得html5写一个出来是可行的,这不最近终于开始写了。
首先分析一下本次实现的功能点:
1、游戏布局面板格子绘制;
2、 7种方块的绘制;
3、方块的上、下、左、右 (字母WASD键)控制,上为旋转,左右下分别为移动,空格键为快速下落(下落到最底部);
4、方块最终的可下落位置预览提示;
5、方块的消行操作(本次消除N行);
以上这些功能为核心功能,与之前java版的功能实现相比,少了下列几个功能:
1)消行计分,等级提升,背景切换;
2)方块自动下落,按照级别方块下落速度的提升;
3)游戏开始的手动执行,结束提示提示,游戏暂停,继续等;
4)下一个方块的提前预览;
。。。。。。突然发现以前的这个功能实现还是稍微有点完善的。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>俄罗斯方块</title>
<style type="text/css">
/*整个画布*/
#tetris{
border: 6px solid grey;
}
/*游戏面板*/
</style>
</head>
<body>
<canvas id="tetris" width="565" height="576"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("tetris");
var context = canvas.getContext("2d");
var padding = 6 , size = 32 , minX = 0 , maxX = 10 , minY = 0 , maxY = 18 , score = 0 , level = 1;
var gameMap = new Array();//游戏地图,二维数组
initGameMap();
//绘制垂直线条
drawGrid();
var arrays = basicBlockType();
var blockIndex = getRandomIndex();
//随机画一个方块意思意思
var block = getPointByCode(blockIndex);
context.fillStyle = getBlockColorByIndex(blockIndex);
drawBlock(block);
/**
* 初始化游戏地图
*/
function initGameMap(){
for(var i=0 ; i < maxY ; i++){
var row = new Array();
for(var j=0 ; j < maxX ; j++){
row[j] = false;
}
gameMap[i] = row;
}
}
/**
* 方块旋转
* 顺时针:
* A.x = O.y + O.x - B.y
* A.y = O.y - O.x + B.x
*/
function round(){
//正方形的方块不响应旋转
if(blockIndex == 4){
return;
}
//循环处理当前的方块,找新的旋转点
for(var i=1 ; i < block.length; i++){
var o = block[0];
var point = block[i];
//旋转后的位置不能与现有格子的方块冲突
var tempX = o.y + o.x - point.y;
var tempY = o.y - o.x + point.x;
if(isOverZone(tempX , tempY)){
return;//不可旋转
}
}
clearBlock();
//可以旋转,设置新的旋转后的坐标
for(var i=1 ; i < block.length; i++){
var o = block[0];
var point = block[i];
//旋转后的位置不能与现有格子的方块冲突
var tempX = o.y + o.x - point.y;
var tempY = o.y - o.x + point.x;
block[i] = {x: tempX , y: tempY};
}
drawBlock();
}
function moveDown(){
var flag = moveTo(0 , 1);
//如果可以移动,则继续移动
if(flag){
return ;
}
//如果不能向下移动了,将当前的方块坐标载入地图
add2GameMap();
//进行消行动作
clearLines();
//清除游戏区域内的不同颜色的格子,使用单一颜色重新绘制地图堆积物
redrawGameMap();
//如果不能向下移动,则继续下一个方块
nextBlock();
}
/**
* 消行动作,返回消除的行数
*/
function clearLines(){
var clearRowList = new Array();
for(var i=0 ; i < maxY ; i++){
var flag = true;
for(var j=0 ; j < maxX ; j++){
if(gameMap[i][j] == false){
flag = false;
break;
}
}
if(flag){
clearRowList.push(i);//记录消除行号的索引
}
}
var clearRows = clearRowList.length;
//所谓的消行就是将待消除行的索引,下方所有的格子上移动
for(var x=0 ; x < clearRows ; x++){
var index = clearRowList[x];
for(var i=index ; i > 0 ; i--){
for(var j=0 ; j < maxX; j++){
gameMap[i][j] = gameMap[i-1][j];
}
}
}
if(clearRows > 0){
for(var i=0 ; i < maxY ; i++){
//此处可以限制满足相关条件的方块进行清除操作 && j < clearRowList[clearRows - 1]
for(var j=0 ; j < maxX ; j++){
if(gameMap[i][j] == false){
clearBlockByPoint(i, j);
}
}
}
}
}
/**
* 重绘游戏地图
*/
function redrawGameMap(){
drawGrid();
for(var i=0 ; i < maxY ; i++){
for(var j=0 ; j < maxX ; j++){
if(gameMap[i][j]){
roadBlock(j , i);
}
}
}
}
/**
* 打印阴影地图
*/
function drawShadowBlock(){
var currentBlock = block;
var shadowPoints = getCanMoveDown();
if(shadowPoints != null && shadowPoints.length > 0){
for (var i=0 ; i < shadowPoints.length ; i++) {
var point = shadowPoints[i];
if(point == null){
continue;
}
var start = point.x * size;
var end = point.y * size;
context.fillStyle = "chartreuse";
context.fillRect(start , end , size ,size);
context.strokeStyle = "black";
context.strokeRect(start , end , size ,size);
}
}
}
/**
* 返回最多可移动到的坐标位置(统计总共可以下落多少步骤)
* @return 最多可移动到的坐标位置
*/
function getCanMoveDown(){
var nps = canMove(0, 1 , block);
var last = null;
if(nps != null){
last = new Array();
while((nps = canMove(0, 1, nps)) != null){
if(nps != null){
last = nps;
}
}
}
return last;
}
function drawLevelScore(){
}
/**
* 将不能移动的各种填充至地图
*/
function add2GameMap(){
for(var i=0 ; i < block.length; i++){
var point = block[i];
var x = point.x;
var y = point.y;
var gameMapRow = gameMap[y];//获取到地图的一行
gameMapRow[x] = true;//将此行中的某个格子标记为堆积物
gameMap[y] = gameMapRow;//再将行给设置回来
}
}
function moveLeft(){
moveTo(-1 , 0);
}
function moveRight(){
moveTo(1 , 0);
}
function quickDown(){
while(moveTo(0, 1));
}
function moveTo(moveX , moveY){
var move = canMove(moveX , moveY , block);//判定是否可以移动
if(move == null){
return false;
}
clearBlock();
for(var i=0 ; i < block.length; i++){
var point = block[i];
point.x = point.x + moveX;
point.y = point.y + moveY;
}
drawBlock();
return true;
}
/**
* 下一个方块
*/
function nextBlock(){
blockIndex = getRandomIndex();
block = getPointByCode(blockIndex);
context.fillStyle = getBlockColorByIndex(blockIndex);
drawBlock();
}
document.onkeypress = function(evt){
var key = window .event ? evt.keyCode : evt.which;
switch(key){
case 119://向上旋转 W
round();
break;
case 115://向下移动 S
moveDown();
break;
case 97://向左移动 A
moveLeft();
break;
case 100://向右移动 D
moveRight();
break;
case 32://空格键快速下落到底
quickDown();
break;
}
}
/**
* 判定是否可以移动
* @param moveX 横向移动的个数
* @param moveY 纵向移动的个数
*/
function canMove(moveX , moveY , currentBlock){
var flag = true;
var newPoints = new Array();
for(var i=0 ; i < currentBlock.length; i++){
var point = currentBlock[i];
var tempX = point.x + moveX;
var tempY = point.y + moveY;
if(isOverZone(tempX , tempY)){
flag = false;
break;
}
}
if(flag){
for(var i=0 ; i < currentBlock.length; i++){
var point = currentBlock[i];
var tempX = point.x + moveX;
var tempY = point.y + moveY;
newPoints[i] = {x : tempX , y : tempY};
}
return newPoints;
}
return null;
}
/**
* 判定是否可以移动
* @param x 预移动后的横坐标
* @param y 预移动后的纵坐标
*/
function isOverZone(x , y){
return x < minX || x >= maxX || y < minY || y >= maxY || gameMap[y][x];
}
document.body.click();
/**
* 初始化方块的基础数据
*/
function basicBlockType(){
var arrays = new Array();
arrays[0] = [{x:4,y:0},{x:3,y:0},{x:5,y:0},{x:6,y:0}];
arrays[1] = [{x:4,y:0},{x:3,y:0},{x:5,y:0},{x:4,y:1}];
arrays[2] = [{x:4,y:0},{x:3,y:0},{x:5,y:0},{x:3,y:1}];
arrays[3] = [{x:4,y:0},{x:5,y:0},{x:3,y:1},{x:4,y:1}];
arrays[4] = [{x:4,y:0},{x:5,y:0},{x:4,y:1},{x:5,y:1}];
arrays[5] = [{x:4,y:0},{x:3,y:0},{x:5,y:0},{x:5,y:1}];
arrays[6] = [{x:4,y:0},{x:3,y:0},{x:4,y:1},{x:5,y:1}];
return arrays;
}
function basicBlockColor(){
return ["#A00000" , "#A05000" , "#A0A000" , "#00A000" , "#00A0A0" , "#0000A0" , "#A000A0"];
}
function getBlockColorByIndex(typeCodeIndex){
var arrays = basicBlockColor();
return arrays[typeCodeIndex];
}
/**
* 根据编号返回指定编号的方块
* @param typeCodeIndex 方块编号索引
*/
function getPointByCode(typeCodeIndex){
var arrays = basicBlockType();
return arrays[typeCodeIndex];
}
/**
* 获取随即出现方块的范围值
* @param lens 随机数的范围
*/
function getRandomIndex(){
return parseInt(Math.random() * (arrays.length - 1) ,10);
}
/**
* 绘制方块,按格子单个绘制
*/
function drawBlock(){
drawGrid();
for(var i=0 ; i < block.length; i++){
var point = block[i];
var start = point.x * size;
var end = point.y * size;
context.fillStyle = getBlockColorByIndex(blockIndex);
context.fillRect(start , end , size , size);
context.strokeStyle = "black";
context.strokeRect(start , end , size , size);
}
drawShadowBlock();
}
/**
* 绘制障碍物
*/
function roadBlock(x , y){
context.fillStyle = "darkgray";
var start = x * size;
var end = y * size;
context.fillRect(start , end , size , size);
}
/**
* 绘制新的方块先清除之前的方块
*/
function clearBlock(){
for(var i=0 ; i < block.length; i++){
var point = block[i];
var start = point.x * size;
var end = point.y * size;
context.clearRect(start , end , size , size);
}
}
/**
* 初始化一个新的行
*/
function initGameMapRow(){
var array = new Array();
for(var i=0 ; i < maxX ; i++){
array[i] = false;
}
return array;
}
/**
* 根据坐标清除指定格子的内容
* @param x 横坐标
* @param y 纵坐标
*/
function clearBlockByPoint(x , y){
var start = y * size;
var end = x * size;
context.clearRect(start , end , size , size);
}
/**
* 清掉所有位置的空白格的绘图
*/
function clearAllNullPoint(){
for(var i=0 ; i < maxY ; i++){
for(var j=0 ; j < maxX ; j++){
if(gameMap[i][j] == false){
clearBlockByPoint(i, j);
}
}
}
}
/**
* 绘制网格线
* @param context 绘图对象
*/
function drawGrid(){
clearAllNullPoint();//清除掉当前方块下落位置造成的阴影
context.strokeStyle = "grey";//画笔颜色
for(var i=0 ; i <= maxX ; i++){
var start = i * size;
var end = start + size;
context.beginPath();
context.moveTo(start , 0);
context.lineTo(size * i , size * maxY);
context.stroke();
context.closePath();
}
//绘制水平线条
for(var i=0 ; i <= maxY ; i++){
var start = i * size;
var end = start + size;
context.beginPath();
context.moveTo(0 , size * i);
context.lineTo(size * maxX , size * i );
context.stroke();
context.closePath();
}
}
</script>
</body>
</html>
点赞