欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

HTML5 实现的一个俄罗斯方块实例代码

程序员文章站 2023-12-03 09:21:58
示例简单,运行地址为:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5浏览器的环境。实现的功能:方块旋转(w键)、自动下落、移动(asd)...

示例简单,运行地址为:http://chendd.cn/demo/html/canvas/elsfk.html,得需要支持html5浏览器的环境。

实现的功能:方块旋转(w键)、自动下落、移动(asd)、消行、快速下落(空格键)、下落阴影、游戏结束。

为实现功能:消行时的计分、等级、以及不同等级的下落速度等。

学习了xiaoe的java版本的俄罗斯方块后,自己动手使用html5的canvas实现的,

参考效果图如下:

HTML5 实现的一个俄罗斯方块实例代码

详细代码如下:

<!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(); //游戏地图,二维数组
  var gametimer;
  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 overflag = canover();
  if(overflag){
   //如果不能向下移动了,将当前的方块坐标载入地图
   window.clearinterval(gametimer);
   add2gamemap();
   //清除游戏区域内的不同颜色的格子,使用单一颜色重新绘制地图堆积物
   redrawgamemap();
   return;//游戏结束
  }
  
  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 = "#abcdef";
   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 canover(){
  var flag = false;
  for (var i = 0; i < block.length; i++) {
   var point = block[i];
   var x = point.x;
   var y = point.y;
   if(isoverzone(x , y)){
   flag = true;
   break;
   }
  }
  return flag;
  }
  
  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;
  }
  }
  /**

  * 判定是否可以移动

  * @parammovex 横向移动的个数

  * @parammovey 纵向移动的个数

  */
  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;
  }
  /**

  * 判定是否可以移动

  * @paramx 预移动后的横坐标

  * @paramy 预移动后的纵坐标

  */
  function isoverzone(x, y) {
  return x < minx || x >= maxx || y < miny || y >= maxy || gamemap[y][x];
  }
  document.body.click();
  
  gametimer = window.setinterval(movedown , 800);
  
  /**

  * 初始化方块的基础数据

  */
  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];
  }
  /**

  * 根据编号返回指定编号的方块

  * @paramtypecodeindex 方块编号索引

  */
  function getpointbycode(typecodeindex) {
  var arrays = basicblocktype();
  return arrays[typecodeindex];
  }
  /**

  * 获取随即出现方块的范围值

  * @paramlens 随机数的范围

  */
  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;
  }
  /**

  * 根据坐标清除指定格子的内容

  * @paramx 横坐标

  * @paramy 纵坐标

  */
  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);
   }
   }
  }
  }
  /**

  * 绘制网格线

  * @paramcontext 绘图对象

  */
  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>

以上就是html5 实现的一个俄罗斯方块的实例,有兴趣的小伙伴可以参考下,谢谢大家对本站的支持!