js实现简单的俄罗斯方块小游戏

开始

1. 创建一个宽为 200px,高为 360px 的背景容器

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>俄罗斯方块</title>
  8. <style>
  9. .container {
  10. position: relative;
  11. width: 200px;
  12. height: 360px;
  13. background-color: #000;
  14. }
  15. </style>
  16. </head>
  17.  
  18. <body>
  19. <!-- 背景容器 -->
  20. <div class="container"></div>
  21. </body>
  22.  
  23. </html>

2. 在该容器上创建一个 20 * 20 的块元素

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>俄罗斯方块</title>
  8. <style>
  9. .container {
  10. position: relative;
  11. width: 200px;
  12. height: 360px;
  13. background-color: #000;
  14. }
  15.  
  16. .activity-model {
  17. width: 20px;
  18. height: 20px;
  19. background-color: cadetblue;
  20. border: 1px solid #eeeeee;
  21. box-sizing: border-box;
  22. position: absolute;
  23. }
  24. </style>
  25. </head>
  26.  
  27. <body>
  28. <!-- 背景容器 -->
  29. <div class="container">
  30. <!-- 块元素 -->
  31. <div class="activity-model"></div>
  32. </div>
  33. </body>
  34.  
  35. </html>

3. 控制该元素的移动,每次移动 20px

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>俄罗斯方块</title>
  8. <style>
  9. .container {
  10. position: relative;
  11. width: 200px;
  12. height: 360px;
  13. background-color: #000;
  14. }
  15.  
  16. .activity-model {
  17. width: 20px;
  18. height: 20px;
  19. background-color: cadetblue;
  20. border: 1px solid #eeeeee;
  21. box-sizing: border-box;
  22. position: absolute;
  23. }
  24. </style>
  25. </head>
  26.  
  27. <body>
  28. <!-- 背景容器 -->
  29. <div class="container">
  30. <!-- 块元素 -->
  31. <div class="activity-model"></div>
  32. </div>
  33. <script>
  34. // 常量
  35. // 每次移动的距离 步长
  36. const STEP = 20
  37.  
  38. init()
  39. // 入口方法
  40. function init() {
  41. onKeyDown()
  42. }
  43.  
  44. // 监听用户的键盘事件
  45. function onKeyDown() {
  46. document.onkeydown = event => {
  47. switch (event.keyCode) {
  48. case 38: // 上
  49. move(0, -1)
  50. break;
  51. case 39: // 右
  52. move(1, 0)
  53. break;
  54. case 40: // 下
  55. move(0, 1)
  56. break;
  57. case 37: // 左
  58. move(-1, 0)
  59. break;
  60. default:
  61. break;
  62. }
  63. }
  64. }
  65.  
  66. // 移动
  67. function move(x, y) {
  68. // 控制块元素进行移动
  69. const activityModelEle = document.getElementsByClassName("activity-model")[0]
  70. activityModelEle.style.top = parseInt(activityModelEle.style.top || 0) + y * STEP + "px"
  71. activityModelEle.style.left = parseInt(activityModelEle.style.left || 0) + x * STEP + "px"
  72. }
  73. </script>
  74. </body>
  75.  
  76. </html>

构建 L 形状的模型

1. 将容器进行分割,分割为 18 行,10 列。行高,列高均为20

  1. // 常量
  2. // 每次移动的距离 步长
  3. const STEP = 20
  4. // 分割容器
  5. // 18行 10列
  6. const ROW_COUNT = 18, COL_COUNT = 10

2. 以 16宫格 为基准,定义 L 形状的 4 个方块的位置

  1. // 分割容器
  2. // 18行 10列
  3. const ROW_COUNT = 18, COL_COUNT = 10
  4. // 创建每个模型的数据源
  5. const MODELS = [
  6. // 第1个模型数据源(L型)
  7. {
  8. 0: {
  9. row: 2,
  10. col: 0
  11. },
  12. 1: {
  13. row: 2,
  14. col: 1
  15. },
  16. 2: {
  17. row: 2,
  18. col: 2
  19. },
  20. 3: {
  21. row: 1,
  22. col: 2
  23. }
  24. }]

3. 创建 L 型模型,根据 16 宫格中的数据将模型渲染到页面上

  1. // 分割容器
  2. // 18行 10列
  3. const ROW_COUNT = 18, COL_COUNT = 10
  4. // 创建每个模型的数据源
  5. const MODELS = [
  6. // 第1个模型数据源(L型)
  7. {
  8. 0: {
  9. row: 2,
  10. col: 0
  11. },
  12. 1: {
  13. row: 2,
  14. col: 1
  15. },
  16. 2: {
  17. row: 2,
  18. col: 2
  19. },
  20. 3: {
  21. row: 1,
  22. col: 2
  23. }
  24. }]
  25. // 变量
  26. // 当前使用的模型
  27. let currentModel = {}
  28. init()
  29. // 入口方法
  30. function init() {
  31. createModel()
  32. onKeyDown()
  33. }
  34.  
  35. // 根据模型使用的数据创建对应的块元素
  36. function createModel() {
  37. // 确定当前使用哪一个模型
  38. currentModel = MODELS[0]
  39. // 生成对应数量的块元素
  40. for (const key in currentModel) {
  41. const divEle = document.createElement('div')
  42. divEle.className = "activity-model"
  43. document.getElementById("container").appendChild(divEle)
  44. }
  45. // 定位块元素位置
  46. locationBlocks()
  47. }
  48.  
  49. // 根据数据源定位块元素的位置
  50. function locationBlocks() {
  51. // 1 拿到所有的块元素
  52. const eles = document.getElementsByClassName("activity-model")
  53. for (let i = 0; i < eles.length; i++) {
  54. // 单个块元素
  55. const activityModelEle = eles[i]
  56. // 2 找到每个块元素对应的数据 (行、列)
  57. const blockModel = currentModel[i]
  58. // 3 根据每个块元素对应的数据来指定块元素的位置
  59. activityModelEle.style.top = blockModel.row * STEP + "px"
  60. activityModelEle.style.left = blockModel.col * STEP + "px"
  61. }
  62. }

控制该模型进行移动

  • 本质是控制 16 宫格 进行移动

  1. // 根据数据源定位块元素的位置
  2. function locationBlocks() {
  3. // 1 拿到所有的块元素
  4. const eles = document.getElementsByClassName("activity-model")
  5. for (let i = 0; i < eles.length; i++) {
  6. // 单个块元素
  7. const activityModelEle = eles[i]
  8. // 2 找到每个块元素对应的数据 (行、列)
  9. const blockModel = currentModel[i]
  10. // 3 根据每个块元素对应的数据来指定块元素的位置
  11. // 每个块元素的位置由2个值确定:
  12. // a. 16 宫格所在的位置
  13. // b. 块元素在 16 宫格中的位置
  14. activityModelEle.style.top = (currentY + blockModel.row) * STEP + "px"
  15. activityModelEle.style.left = (currentX + blockModel.col) * STEP + "px"
  16. }
  17. }
  18.  
  19. // 移动
  20. function move(x, y) {
  21. // 控制16宫格元素进行移动
  22. currentX += x
  23. currentY += y
  24. // 根据16宫格的位置来重新定位块元素
  25. locationBlocks()
  26. }

控制模型旋转

规律

  • 以 16宫格 的中心点为基准进行旋转

  • 观察上图中旋转后每个块元素发生的位置的变化

  • 以第1,2个L模型为例,可以观察到:…

    • 块元素1的坐标(列, 行)变化:(0, 2) -> (1, 0)
    • 块元素2的坐标(列, 行)变化:(1, 2) -> (1, 1)
    • 块元素3的坐标(列, 行)变化:(2, 2) -> (1, 2)
    • 块元素4的坐标(列, 行)变化:(2, 1) -> (2, 2)
  • 其基本变化规律是

    • 移动后的行 = 移动前的列
    • 移动后的列 = 3 - 移动前的行

旋转模型

  1. // 监听用户的键盘事件
  2. function onKeyDown() {
  3. document.onkeydown = event => {
  4. switch (event.keyCode) {
  5. case 38: // 上
  6. // move(0, -1)
  7. rotate()
  8. break;
  9. case 39: // 右
  10. move(1, 0)
  11. break;
  12. case 40: // 下
  13. move(0, 1)
  14. break;
  15. case 37: // 左
  16. move(-1, 0)
  17. break;
  18. default:
  19. break;
  20. }
  21. }
  22. }
  23.  
  24. // 旋转模型
  25. function rotate() {
  26. // 算法
  27. // 旋转后的行 = 旋转前的列
  28. // 旋转后的列 = 3 - 旋转前的行
  29.  
  30. // 遍历模型数据源
  31. for (const key in currentModel) {
  32. // 块元素的数据
  33. const blockModel = currentModel[key]
  34. // 实现算法
  35. let temp = blockModel.row
  36. blockModel.row = blockModel.col
  37. blockModel.col = 3 - temp
  38. }
  39. locationBlocks()
  40. }

控制模型只在容器中移动

  1. // 根据数据源定位块元素的位置
  2. function locationBlocks() {
  3. // 判断一下块元素的越界行为
  4. checkBound()
  5. // 1 拿到所有的块元素
  6. const eles = document.getElementsByClassName("activity-model")
  7. for (let i = 0; i < eles.length; i++) {
  8. // 单个块元素
  9. const activityModelEle = eles[i]
  10. // 2 找到每个块元素对应的数据 (行、列)
  11. const blockModel = currentModel[i]
  12. // 3 根据每个块元素对应的数据来指定块元素的位置
  13. // 每个块元素的位置由2个值确定:
  14. // a. 16 宫格所在的位置
  15. // b. 块元素在 16 宫格中的位置
  16. activityModelEle.style.top = (currentY + blockModel.row) * STEP + "px"
  17. activityModelEle.style.left = (currentX + blockModel.col) * STEP + "px"
  18. }
  19. }
  20.  
  21. // 控制模型只能在容器中
  22. function checkBound() {
  23. // 定义模型可以活动的边界
  24. let leftBound = 0, rightBound = COL_COUNT, bottomBound = ROW_COUNT
  25. // 当块元素超出了边界之后,让 16 宫格后退1格
  26. for (const key in currentModel) {
  27. // 块元素的数据
  28. const blockModel = currentModel[key]
  29. // 左侧越界
  30. if ((blockModel.col + currentX) < 0) {
  31. currentX++
  32. }
  33. // 右侧越界
  34. if ((blockModel.col + currentX) >= rightBound) {
  35. currentX--
  36. }
  37. // 底部越界
  38. if ((blockModel.row + currentY) >= bottomBound) {
  39. currentY--
  40. }
  41. }
  42. }

当模型触底时,将块元素变为灰色固定在底部,同时生成一个新的模型

声明样式类

  1. .fixed-model {
  2. width: 20px;
  3. height: 20px;
  4. background-color: #fefefe;
  5. border: 1px solid #333333;
  6. box-sizing: border-box;
  7. position: absolute;
  8. }

触底时固定,生成新模型

  • 需要注意的是:当模型触底被固定后,我们需要重新再生成一个新的模型,再生成新模型的时候,需要重置 16宫格 的位置,否则新创建的模型的位置会出现在底部,并将上一模型覆盖掉

  1. // 根据模型使用的数据创建对应的块元素
  2. function createModel() {
  3. // 确定当前使用哪一个模型
  4. currentModel = MODELS[0]
  5. // 重置16宫格的位置
  6. currentY = 0
  7. currentY = 0
  8. // 生成对应数量的块元素
  9. for (const key in currentModel) {
  10. const divEle = document.createElement('div')
  11. divEle.className = "activity-model"
  12. document.getElementById("container").appendChild(divEle)
  13. }
  14. // 定位块元素位置
  15. locationBlocks()
  16. }
  17.  
  18. // 控制模型只能在容器中
  19. function checkBound() {
  20. // 定义模型可以活动的边界
  21. let leftBound = 0, rightBound = COL_COUNT, bottomBound = ROW_COUNT
  22. // 当块元素超出了边界之后,让 16 宫格后退1格
  23. for (const key in currentModel) {
  24. // 块元素的数据
  25. const blockModel = currentModel[key]
  26. // 左侧越界
  27. if ((blockModel.col + currentX) < 0) {
  28. currentX++
  29. }
  30. // 右侧越界
  31. if ((blockModel.col + currentX) >= rightBound) {
  32. currentX--
  33. }
  34. // 底部越界
  35. if ((blockModel.row + currentY) >= bottomBound) {
  36. currentY--
  37. fixedBottomModel() // 把模型固定在底部
  38. }
  39. }
  40. }
  41.  
  42. // 把模型固定在底部
  43. function fixedBottomModel() {
  44. // 1 改变模型的样式
  45. // 2 禁止模型再进行移动
  46. const activityModelEles = document.getElementsByClassName('activity-model')
  47. ;[...activityModelEles].forEach((ele, i) => {
  48. // 更改块元素类名
  49. ele.className = "fixed-model"
  50. // 把该块元素放入变量中
  51. const blockModel = currentModel[i]
  52. fixedBlocks[`${currentY + blockModel.row}_${currentX + blockModel.col}`] = ele
  53. })
  54. // 3 创建新的模型
  55. createModel()
  56. }

判断块元素与块元素之间的碰撞,分为左右接触底部接触

记录所有块元素的位置

  1. // 记录所有块元素的位置
  2. // key=行_列 : V=块元素
  3. const fixedBlocks = {}

当块元素被固定到底部的时候,将块元素存储在fixedBlocks 中

  1. // 把模型固定在底部
  2. function fixedBottomModel() {
  3. // 1 改变模型的样式
  4. // 2 禁止模型再进行移动
  5. const activityModelEles = document.getElementsByClassName('activity-model')
  6. ;[...activityModelEles].forEach((ele, i) => {
  7. // 更改块元素类名
  8. ele.className = "fixed-model"
  9. // 把该块元素放入变量中
  10. const blockModel = currentModel[i]
  11. fixedBlocks[`${currentY + blockModel.row}_${currentX + blockModel.col}`] = ele
  12. })
  13. // 3 创建新的模型
  14. createModel()
  15. }

处理模型之间的碰撞(左右接触)

  1. // 移动
  2. function move(x, y) {
  3. // 16宫格移动
  4. if (isMeet(currentX + x, currentY + y, currentModel)) {
  5. return
  6. }
  7. currentX += x
  8. currentY += y
  9. // 根据16宫格的位置来重新定位块元素
  10. locationBlocks()
  11. }
  12.  
  13. // 旋转模型
  14. function rotate() {
  15. // 算法
  16. // 旋转后的行 = 旋转前的列
  17. // 旋转后的列 = 3 - 旋转前的行
  18.  
  19. // 克隆一下 currentModel 深拷贝
  20. const cloneCurrentModel = JSON.parse(JSON.stringify(currentModel))
  21.  
  22. // 遍历模型数据源
  23. for (const key in cloneCurrentModel) {
  24. // 块元素的数据
  25. const blockModel = cloneCurrentModel[key]
  26. // 实现算法
  27. let temp = blockModel.row
  28. blockModel.row = blockModel.col
  29. blockModel.col = 3 - temp
  30. }
  31. // 如果旋转之后会发生触碰,那么就不需要进行旋转了
  32. if (isMeet(currentX, currentY, cloneCurrentModel)) {
  33. return
  34. }
  35. // 接受了这次旋转
  36. currentModel = cloneCurrentModel
  37. locationBlocks()
  38. }
  39.  
  40. // 判断模型之间的触碰问题
  41. // x, y 表示16宫格《将要》移动的位置
  42. // model 表示当前模型数据源《将要》完成的变化
  43. function isMeet(x, y, model) {
  44. // 所谓模型之间的触碰,在一个固定的位置已经存在一个被固定的块元素时,那么
  45. // 活动中的模型不可以再占用该位置
  46. // 判断触碰,就是在判断活动中的模型《将要移动到的位置》是否已经存在被固定
  47. // 的块元素
  48. // 返回 true 表示将要移动到的位置会发生触碰 否则返回 false
  49. for (const key in model) {
  50. const blockModel = model[key]
  51. // 该位置是否已经存在块元素?
  52. if (fixedBlocks[`${y + blockModel.row}_${x + blockModel.col}`]) {
  53. return true
  54. }
  55. }
  56. return false
  57. }

处理模型之间的碰撞(底部接触)

  1. // 移动
  2. function move(x, y) {
  3. if (isMeet(currentX + x, currentY + y, currentModel)) {
  4. // 底部的触碰发生在移动16宫格的时候,并且此次移动是因为 Y 轴的变化而引起的
  5. if (y != 0) {
  6. // 模型之间发生触碰了
  7. fixedBottomModel()
  8. }
  9. return
  10. }
  11. // 控制16宫格元素进行移动
  12. currentX += x
  13. currentY += y
  14. // 根据16宫格的位置来重新定位块元素
  15. locationBlocks()
  16. }

处理被铺满的行

判断一行是否被铺满

  1. // 把模型固定在底部
  2. function fixedBottomModel() {
  3. // 1 改变模型的样式
  4. // 2 禁止模型再进行移动
  5. const activityModelEles = document.getElementsByClassName('activity-model')
  6. ;[...activityModelEles].forEach((ele, i) => {
  7. ele.className = "fixed-model"
  8. // 把该块元素放入变量中
  9. const blockModel = currentModel[i]
  10. fixedBlocks[`${currentY + blockModel.row}_${currentX + blockModel.col}`] = ele
  11. })
  12. // 判断某一行是否要清理
  13. isRemoveLine()
  14. // 3 创建新的模型
  15. createModel()
  16. }
  17.  
  18. // 判断一行是否被铺满
  19. function isRemoveLine() {
  20. // 在一行中,每一列都存在块元素,那么该行就需要被清理了
  21. // 遍历所有行中的所有列
  22. // 遍历所有行
  23. for (let i = 0; i < ROW_COUNT; i++) {
  24. // 标记符 假设当前行已经被铺满了
  25. let flag = true
  26. // 遍历当前行中的所有列
  27. for (let j = 0; j < COL_COUNT; j++) {
  28. // 如果当前行中有一列没有数据,那么就说明当前行没有被铺满
  29. if (!fixedBlocks[`${i}_${j}`]) {
  30. flag = false
  31. break
  32. }
  33. }
  34. if (flag) {
  35. // 该行已经被铺满了
  36. console.log("该行已经被铺满了")
  37. }
  38. }
  39. }

清理被铺满的一行

  1. function isRemoveLine() {
  2. // 在一行中,每一列都存在块元素,那么该行就需要被清理了
  3. // 遍历所有行中的所有列
  4. // 遍历所有行
  5. for (let i = 0; i < ROW_COUNT; i++) {
  6. // 标记符 假设当前行已经被铺满了
  7. let flag = true
  8. // 遍历当前行中的所有列
  9. for (let j = 0; j < COL_COUNT; j++) {
  10. // 如果当前行中有一列没有数据,那么就说明当前行没有被铺满
  11. if (!fixedBlocks[`${i}_${j}`]) {
  12. flag = false
  13. break
  14. }
  15. }
  16. if (flag) {
  17. // 该行已经被铺满了
  18. removeLine(i)
  19. }
  20. }
  21. }
  22.  
  23. // 清理被铺满的这一行
  24. function removeLine(line) {
  25. // 1 删除该行中所有的块元素
  26. // 2 删除该行所有块元素的数据源
  27. // 遍历该行中的所有列
  28. for (let i = 0; i < COL_COUNT; i++) {
  29. // 1 删除该行中所有的块元素
  30. document.getElementById("container").removeChild(fixedBlocks[`${line}_${i}`])
  31. // 2 删除该行所有块元素的数据源
  32. fixedBlocks[`${line}_${i}`] = null
  33. }
  34. }

让被清理行之上的块元素下落

  1. // 清理被铺满的这一行
  2. function removeLine(line) {
  3. // 1 删除该行中所有的块元素
  4. // 2 删除该行所有块元素的数据源
  5. // 遍历该行中的所有列
  6. for (let i = 0; i < COL_COUNT; i++) {
  7. // 1 删除该行中所有的块元素
  8. document.getElementById("container").removeChild(fixedBlocks[`${line}_${i}`])
  9. // 2 删除该行所有块元素的数据源
  10. fixedBlocks[`${line}_${i}`] = null
  11. }
  12. downLine(line)
  13. }
  14.  
  15. // 让被清理行之上的块元素下落
  16. function downLine(line) {
  17. // 1 被清理行之上的所有块元素数据源所在行数 + 1
  18. // 2 让块元素在容器中的位置下落
  19. // 3 清理之前的块元素
  20. // 遍历被清理行之上的所有行
  21. for (let i = line - 1; i >= 0; i--) {
  22. // 该行中的所有列
  23. for (let j = 0; j < COL_COUNT; j++) {
  24. if (!fixedBlocks[`${i}_${j}`]) continue
  25. // 存在数据
  26. // 1 被清理行之上的所有块元素数据源所在行数 + 1
  27. fixedBlocks[`${i + 1}_${j}`] = fixedBlocks[`${i}_${j}`]
  28. // 2 让块元素在容器中的位置下落
  29. fixedBlocks[`${i + 1}_${j}`].style.top = (i + 1) * STEP + "px"
  30. // 3 清理之前的块元素
  31. fixedBlocks[`${i}_${j}`] = null
  32. }
  33. }
  34. }

创建多种模型样式

定义模型样式

  1. // 创建每个模型的数据源
  2. const MODELS = [
  3. // 第1个模型数据源(L型)
  4. {
  5. 0: {
  6. row: 2,
  7. col: 0
  8. },
  9. 1: {
  10. row: 2,
  11. col: 1
  12. },
  13. 2: {
  14. row: 2,
  15. col: 2
  16. },
  17. 3: {
  18. row: 1,
  19. col: 2
  20. }
  21. },
  22. // 第2个模型数据源(凸)
  23. {
  24. 0: {
  25. row: 1,
  26. col: 1
  27. },
  28. 1: {
  29. row: 0,
  30. col: 0
  31. },
  32. 2: {
  33. row: 1,
  34. col: 0
  35. },
  36. 3: {
  37. row: 2,
  38. col: 0
  39. }
  40. },
  41. // 第3个模型数据源(田)
  42. {
  43. 0: {
  44. row: 1,
  45. col: 1
  46. },
  47. 1: {
  48. row: 2,
  49. col: 1
  50. },
  51. 2: {
  52. row: 1,
  53. col: 2
  54. },
  55. 3: {
  56. row: 2,
  57. col: 2
  58. }
  59. },
  60. // 第4个模型数据源(一)
  61. {
  62. 0: {
  63. row: 0,
  64. col: 0
  65. },
  66. 1: {
  67. row: 0,
  68. col: 1
  69. },
  70. 2: {
  71. row: 0,
  72. col: 2
  73. },
  74. 3: {
  75. row: 0,
  76. col: 3
  77. }
  78. },
  79. // 第5个模型数据源(Z)
  80. {
  81. 0: {
  82. row: 1,
  83. col: 1
  84. },
  85. 1: {
  86. row: 1,
  87. col: 2
  88. },
  89. 2: {
  90. row: 2,
  91. col: 2
  92. },
  93. 3: {
  94. row: 2,
  95. col: 3
  96. }
  97. }
  98. ]

创建模型的时候随机选取不同的模型样式

  1. // 根据模型使用的数据创建对应的块元素
  2. function createModel() {
  3. // 确定当前使用哪一个模型
  4. const randow = Math.floor(Math.random() * MODELS.length) // 取0~4之间的随机数
  5. currentModel = MODELS[randow]
  6. // 重置16宫格的位置
  7. currentY = 0
  8. currentY = 0
  9. // 生成对应数量的块元素
  10. for (const key in currentModel) {
  11. const divEle = document.createElement('div')
  12. divEle.className = "activity-model"
  13. document.getElementById("container").appendChild(divEle)
  14. }
  15. // 定位块元素位置
  16. locationBlocks()
  17. }

模型自动降落

  1. // 定时器
  2. let mInterval = null
  3.  
  4. // 根据模型使用的数据创建对应的块元素
  5. function createModel() {
  6. // 确定当前使用哪一个模型
  7. // 确定当前使用哪一个模型
  8. const randow = Math.floor(Math.random() * MODELS.length) // 取0~4之间的随机数
  9. currentModel = MODELS[randow]
  10. // 重置16宫格的位置
  11. currentY = 0
  12. currentY = 0
  13. // 生成对应数量的块元素
  14. for (const key in currentModel) {
  15. const divEle = document.createElement('div')
  16. divEle.className = "activity-model"
  17. document.getElementById("container").appendChild(divEle)
  18. }
  19. // 定位块元素位置
  20. locationBlocks()
  21. // 模型自动下落
  22. autoDown()
  23. }
  24.  
  25. // 让模型自动下落
  26. function autoDown() {
  27. if (mInterval) {
  28. clearInterval(mInterval)
  29. }
  30. mInterval = setInterval(() => {
  31. move(0, 1)
  32. }, 600)
  33. }

游戏结束

判断游戏结束

  1. // 根据模型使用的数据创建对应的块元素
  2. function createModel() {
  3. // 判断游戏是否结束
  4. if (isGameOver()) {
  5. console.log("游戏结束!")
  6. return
  7. }
  8. // 确定当前使用哪一个模型
  9. const randow = Math.floor(Math.random() * MODELS.length) // 取0~4之间的随机数
  10. currentModel = MODELS[randow]
  11. // 重置16宫格的位置
  12. currentY = 0
  13. currentY = 0
  14. // 生成对应数量的块元素
  15. for (const key in currentModel) {
  16. const divEle = document.createElement('div')
  17. divEle.className = "activity-model"
  18. document.getElementById("container").appendChild(divEle)
  19. }
  20. // 定位块元素位置
  21. locationBlocks()
  22. // 模型自动下落
  23. autoDown()
  24. }
  25.  
  26. // 判断游戏结束
  27. function isGameOver() {
  28. // 当第0行存在块元素的时候,表示游戏结束了
  29. for (let i = 0; i < COL_COUNT; i++) {
  30. if (fixedBlocks[`0_${i}`]) return true
  31. }
  32. return false
  33. }

结束游戏

  1. // 根据模型使用的数据创建对应的块元素
  2. function createModel() {
  3. // 判断游戏是否结束
  4. if (isGameOver()) {
  5. gameOver() // 结束游戏
  6. return
  7. }
  8. // 确定当前使用哪一个模型
  9. const randow = Math.floor(Math.random() * MODELS.length) // 取0~4之间的随机数
  10. currentModel = MODELS[randow]
  11. // 重置16宫格的位置
  12. currentY = 0
  13. currentY = 0
  14. // 生成对应数量的块元素
  15. for (const key in currentModel) {
  16. const divEle = document.createElement('div')
  17. divEle.className = "activity-model"
  18. document.getElementById("container").appendChild(divEle)
  19. }
  20. // 定位块元素位置
  21. locationBlocks()
  22. // 模型自动下落
  23. autoDown()
  24. }
  25.  
  26. // 结束掉游戏
  27. function gameOver() {
  28. // 1 停止定时器
  29. if (mInterval) {
  30. clearInterval(mInterval)
  31. }
  32. // 2 弹出对话框
  33. alert("大吉大利,今晚吃鸡!")
  34. }

扩展:计分 + 最高分 + 重新开始游戏

结构 + 样式

  1. body {
  2. display: flex;
  3. }
  4. #scores {
  5. margin-left: 20px;
  6. }
  1. <!-- 背景容器 -->
  2. <div id="container" class="container">
  3. <!-- 块元素 -->
  4. <!-- <div class="activity-model"></div> -->
  5. </div>
  6. <div id="scores">
  7. <p>最高分:<span id="max-score">0</span></p>
  8. <p>分数:<span id="current-score">0</span></p>
  9. <button onclick="reset()">重新开始</button>
  10. </div>

逻辑

  1. // 最高分
  2. let maxScore = 0
  3. // 当前分数
  4. let score = 0
  5.  
  6. // 清理被铺满的这一行
  7. function removeLine(line) {
  8. // 1 删除该行中所有的块元素
  9. // 2 删除该行所有块元素的数据源
  10. // 遍历该行中的所有列
  11. for (let i = 0; i < COL_COUNT; i++) {
  12. // 1 删除该行中所有的块元素
  13. document.getElementById("container").removeChild(fixedBlocks[`${line}_${i}`])
  14. // 2 删除该行所有块元素的数据源
  15. fixedBlocks[`${line}_${i}`] = null
  16. }
  17. // 更新当前分数
  18. score += COL_COUNT
  19. document.getElementById("current-score").innerHTML = score
  20. downLine(line)
  21. }
  22.  
  23. // 结束掉游戏
  24. function gameOver() {
  25. // 1 停止定时器
  26. if (mInterval) {
  27. clearInterval(mInterval)
  28. }
  29. // 重置最高分数
  30. maxScore = Math.max(maxScore, score)
  31. document.getElementById("max-score").innerHTML = maxScore
  32. // 2 弹出对话框
  33. alert("大吉大利,今晚吃鸡!")
  34. }
  35.  
  36. // 重新开始
  37. function reset() {
  38. const container = document.getElementById("container")
  39. const childs = container.childNodes;
  40. for (let i = childs.length - 1; i >= 0; i--) {
  41. container.removeChild(childs[i]);
  42. }
  43. fixedBlocks = {}
  44. score = 0
  45. document.getElementById("current-score").innerHTML = score
  46. init()
  47. }

完整代码

  1. <!DOCTYPE html>
  2. <html lang="en">
  3.  
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>俄罗斯方块</title>
  8. <style>
  9. body {
  10. display: flex;
  11. }
  12.  
  13. .container {
  14. position: relative;
  15. width: 200px;
  16. height: 360px;
  17. background-color: #000;
  18. }
  19.  
  20. .activity-model {
  21. width: 20px;
  22. height: 20px;
  23. background-color: cadetblue;
  24. border: 1px solid #eeeeee;
  25. box-sizing: border-box;
  26. position: absolute;
  27. }
  28.  
  29. .fixed-model {
  30. width: 20px;
  31. height: 20px;
  32. background-color: #fefefe;
  33. border: 1px solid #333333;
  34. box-sizing: border-box;
  35. position: absolute;
  36. }
  37.  
  38. #scores {
  39. margin-left: 20px;
  40. }
  41. </style>
  42. </head>
  43.  
  44. <body>
  45. <!-- 背景容器 -->
  46. <div id="container" class="container">
  47. <!-- 块元素 -->
  48. <!-- <div class="activity-model"></div> -->
  49. </div>
  50. <div id="scores">
  51. <p>最高分:<span id="max-score">0</span></p>
  52. <p>分数:<span id="current-score">0</span></p>
  53. <button onclick="reset()">重新开始</button>
  54. </div>
  55. <script>
  56. // 常量
  57. // 每次移动的距离 步长
  58. const STEP = 20
  59. // 分割容器
  60. // 18行 10列
  61. const ROW_COUNT = 18, COL_COUNT = 10
  62. // 创建每个模型的数据源
  63. const MODELS = [
  64. // 第1个模型数据源(L型)
  65. {
  66. 0: {
  67. row: 2,
  68. col: 0
  69. },
  70. 1: {
  71. row: 2,
  72. col: 1
  73. },
  74. 2: {
  75. row: 2,
  76. col: 2
  77. },
  78. 3: {
  79. row: 1,
  80. col: 2
  81. }
  82. },
  83. // 第2个模型数据源(凸)
  84. {
  85. 0: {
  86. row: 1,
  87. col: 1
  88. },
  89. 1: {
  90. row: 0,
  91. col: 0
  92. },
  93. 2: {
  94. row: 1,
  95. col: 0
  96. },
  97. 3: {
  98. row: 2,
  99. col: 0
  100. }
  101. },
  102. // 第3个模型数据源(田)
  103. {
  104. 0: {
  105. row: 1,
  106. col: 1
  107. },
  108. 1: {
  109. row: 2,
  110. col: 1
  111. },
  112. 2: {
  113. row: 1,
  114. col: 2
  115. },
  116. 3: {
  117. row: 2,
  118. col: 2
  119. }
  120. },
  121. // 第4个模型数据源(一)
  122. {
  123. 0: {
  124. row: 0,
  125. col: 0
  126. },
  127. 1: {
  128. row: 0,
  129. col: 1
  130. },
  131. 2: {
  132. row: 0,
  133. col: 2
  134. },
  135. 3: {
  136. row: 0,
  137. col: 3
  138. }
  139. },
  140. // 第5个模型数据源(Z)
  141. {
  142. 0: {
  143. row: 1,
  144. col: 1
  145. },
  146. 1: {
  147. row: 1,
  148. col: 2
  149. },
  150. 2: {
  151. row: 2,
  152. col: 2
  153. },
  154. 3: {
  155. row: 2,
  156. col: 3
  157. }
  158. }
  159. ]
  160. // 变量
  161. // 当前使用的模型
  162. let currentModel = {}
  163. // 标记16宫格的位置
  164. let currentX = 0, currentY = 0
  165. // 记录所有块元素的位置
  166. // key=行_列 : V=块元素
  167. let fixedBlocks = {}
  168. // 定时器
  169. let mInterval = null
  170. // 最高分
  171. let maxScore = 0
  172. // 当前分数
  173. let score = 0
  174. // 入口方法
  175. function init() {
  176. createModel()
  177. onKeyDown()
  178. }
  179.  
  180. init()
  181.  
  182. // 根据模型使用的数据创建对应的块元素
  183. function createModel() {
  184. // 判断游戏是否结束
  185. if (isGameOver()) {
  186. gameOver()
  187. return
  188. }
  189. // 确定当前使用哪一个模型
  190. const randow = Math.floor(Math.random() * MODELS.length) // 取0~4之间的随机数
  191. currentModel = MODELS[randow]
  192. // 重置16宫格的位置
  193. currentY = 0
  194. currentY = 0
  195. // 生成对应数量的块元素
  196. for (const key in currentModel) {
  197. const divEle = document.createElement('div')
  198. divEle.className = "activity-model"
  199. document.getElementById("container").appendChild(divEle)
  200. }
  201. // 定位块元素位置
  202. locationBlocks()
  203. // 模型自动下落
  204. autoDown()
  205. }
  206.  
  207. // 根据数据源定位块元素的位置
  208. function locationBlocks() {
  209. // 判断一些块元素的越界行为
  210. checkBound()
  211. // 1 拿到所有的块元素
  212. const eles = document.getElementsByClassName("activity-model")
  213. for (let i = 0; i < eles.length; i++) {
  214. // 单个块元素
  215. const activityModelEle = eles[i]
  216. // 2 找到每个块元素对应的数据 (行、列)
  217. const blockModel = currentModel[i]
  218. // 3 根据每个块元素对应的数据来指定块元素的位置
  219. // 每个块元素的位置由2个值确定:
  220. // 1 16 宫格所在的位置
  221. // 2 块元素在 16 宫格中的位置
  222. activityModelEle.style.top = (currentY + blockModel.row) * STEP + "px"
  223. activityModelEle.style.left = (currentX + blockModel.col) * STEP + "px"
  224. }
  225. }
  226.  
  227. // 监听用户键盘事件
  228. function onKeyDown() {
  229. document.onkeydown = event => {
  230. switch (event.keyCode) {
  231. case 38:
  232. // move(0, -1)
  233. rotate()
  234. break;
  235. case 39:
  236. move(1, 0)
  237. break;
  238. case 40:
  239. move(0, 1)
  240. break;
  241. case 37:
  242. move(-1, 0)
  243. break;
  244. default:
  245. break;
  246. }
  247. }
  248. }
  249.  
  250. // 移动
  251. function move(x, y) {
  252. // 控制块元素进行移动
  253. // const activityModelEle = document.getElementsByClassName("activity-model")[0]
  254. // activityModelEle.style.top = parseInt(activityModelEle.style.top || 0) + y * STEP + "px"
  255. // activityModelEle.style.left = parseInt(activityModelEle.style.left || 0) + x * STEP + "px"
  256. // 16宫格移动
  257. if (isMeet(currentX + x, currentY + y, currentModel)) {
  258. // 底部的触碰发生在移动16宫格的时候,并且此次移动是因为 Y 轴的变化而引起的
  259. if (y != 0) {
  260. // 模型之间发生触碰了
  261. fixedBottomModel()
  262. }
  263. return
  264. }
  265. currentX += x
  266. currentY += y
  267. // 根据16宫格的位置来重新定位块元素
  268. locationBlocks()
  269. }
  270. // 旋转模型
  271. function rotate() {
  272. // 算法
  273. // 旋转后的行 = 旋转前的列
  274. // 旋转后的列 = 3 - 旋转前的行
  275.  
  276. // 克隆一下 currentModel 深拷贝
  277. const cloneCurrentModel = JSON.parse(JSON.stringify(currentModel))
  278.  
  279. // 遍历模型数据源
  280. for (const key in cloneCurrentModel) {
  281. // 块元素的数据
  282. const blockModel = cloneCurrentModel[key]
  283. // 实现算法
  284. let temp = blockModel.row
  285. blockModel.row = blockModel.col
  286. blockModel.col = 3 - temp
  287. }
  288. // 如果旋转之后会发生触碰,那么就不需要进行旋转了
  289. if (isMeet(currentX, currentY, cloneCurrentModel)) {
  290. return
  291. }
  292. // 接受了这次旋转
  293. currentModel = cloneCurrentModel
  294. locationBlocks()
  295. }
  296.  
  297. // 控制模型只能在容器中
  298. function checkBound() {
  299. // 定义模型可以活动的边界
  300. let leftBound = 0, rightBound = COL_COUNT, bottomBound = ROW_COUNT
  301. // 当块元素超出了边界之后,让 16 宫格后退1格
  302. for (const key in currentModel) {
  303. // 块元素的数据
  304. const blockModel = currentModel[key]
  305. // 左侧越界
  306. if ((blockModel.col + currentX) < 0) {
  307. currentX++
  308. }
  309. // 右侧越界
  310. if ((blockModel.col + currentX) >= rightBound) {
  311. currentX--
  312. }
  313. // 下侧越界
  314. if ((blockModel.row + currentY) >= bottomBound) {
  315. currentY--
  316. fixedBottomModel()
  317. }
  318. }
  319. }
  320.  
  321. // 把模型固定在底部
  322. function fixedBottomModel() {
  323. // 1 改变模型的样式
  324. // 2 禁止模型再进行移动
  325. const activityModelEles = document.getElementsByClassName('activity-model')
  326. ;[...activityModelEles].forEach((ele, i) => {
  327. ele.className = "fixed-model"
  328. // 把该块元素放入变量中
  329. const blockModel = currentModel[i]
  330. fixedBlocks[`${currentY + blockModel.row}_${currentX + blockModel.col}`] = ele
  331. })
  332. // for (let i = activityModelEles.length - 1; i >= 0; i--) {
  333. // // 拿到每个块元素
  334. // const activityModelEle = activityModelEles[i]
  335. // // 更改块元素的类名
  336. // activityModelEle.className = "fixed-model"
  337. // }
  338. // 判断某一行是否要清理
  339. isRemoveLine()
  340. // 3 创建新的模型
  341. createModel()
  342. }
  343. // 判断模型之间的触碰问题
  344. // x, y 表示16宫格《将要》移动的位置
  345. // model 表示当前模型数据源《将要》完成的变化
  346. function isMeet(x, y, model) {
  347. // 所谓模型之间的触碰,在一个固定的位置已经存在一个被固定的块元素时,那么
  348. // 活动中的模型不可以再占用该位置
  349. // 判断触碰,就是在判断活动中的模型《将要移动到的位置》是否已经存在被固定
  350. // 的块元素
  351. // 返回 true 表示将要移动到的位置会发生触碰 否则返回 false
  352. for (const key in model) {
  353. const blockModel = model[key]
  354. // 该位置是否已经存在块元素?
  355. if (fixedBlocks[`${y + blockModel.row}_${x + blockModel.col}`]) {
  356. return true
  357. }
  358. }
  359. return false
  360. }
  361.  
  362. // 判断一行是否被铺满
  363. function isRemoveLine() {
  364. // 在一行中,每一列都存在块元素,那么该行就需要被清理了
  365. // 遍历所有行中的所有列
  366. // 遍历所有行
  367. for (let i = 0; i < ROW_COUNT; i++) {
  368. // 标记符 假设当前行已经被铺满了
  369. let flag = true
  370. // 遍历当前行中的所有列
  371. for (let j = 0; j < COL_COUNT; j++) {
  372. // 如果当前行中有一列没有数据,那么就说明当前行没有被铺满
  373. if (!fixedBlocks[`${i}_${j}`]) {
  374. flag = false
  375. break
  376. }
  377. }
  378. if (flag) {
  379. // 该行已经被铺满了
  380. removeLine(i)
  381. }
  382. }
  383. }
  384.  
  385. // 清理被铺满的这一行
  386. function removeLine(line) {
  387. // 1 删除该行中所有的块元素
  388. // 2 删除该行所有块元素的数据源
  389. // 遍历该行中的所有列
  390. for (let i = 0; i < COL_COUNT; i++) {
  391. // 1 删除该行中所有的块元素
  392. document.getElementById("container").removeChild(fixedBlocks[`${line}_${i}`])
  393. // 2 删除该行所有块元素的数据源
  394. fixedBlocks[`${line}_${i}`] = null
  395. }
  396. // 更新当前分数
  397. score += COL_COUNT
  398. document.getElementById("current-score").innerHTML = score
  399. downLine(line)
  400. }
  401.  
  402. // 让被清理行之上的块元素下落
  403. function downLine(line) {
  404. // 1 被清理行之上的所有块元素数据源所在行数 + 1
  405. // 2 让块元素在容器中的位置下落
  406. // 3 清理之前的块元素
  407. // 遍历被清理行之上的所有行
  408. for (let i = line - 1; i >= 0; i--) {
  409. // 该行中的所有列
  410. for (let j = 0; j < COL_COUNT; j++) {
  411. if (!fixedBlocks[`${i}_${j}`]) continue
  412. // 存在数据
  413. // 1 被清理行之上的所有块元素数据源所在行数 + 1
  414. fixedBlocks[`${i + 1}_${j}`] = fixedBlocks[`${i}_${j}`]
  415. // 2 让块元素在容器中的位置下落
  416. fixedBlocks[`${i + 1}_${j}`].style.top = (i + 1) * STEP + "px"
  417. // 3 清理之前的块元素
  418. fixedBlocks[`${i}_${j}`] = null
  419. }
  420. }
  421. }
  422.  
  423. // 让模型自动下落
  424. function autoDown() {
  425. if (mInterval) {
  426. clearInterval(mInterval)
  427. }
  428. mInterval = setInterval(() => {
  429. move(0, 1)
  430. }, 600)
  431. }
  432.  
  433. // 判断游戏结束
  434. function isGameOver() {
  435. // 当第0行存在块元素的时候,表示游戏结束了
  436. for (let i = 0; i < COL_COUNT; i++) {
  437. if (fixedBlocks[`0_${i}`]) return true
  438. }
  439. return false
  440. }
  441.  
  442. // 结束掉游戏
  443. function gameOver() {
  444. // 1 停止定时器
  445. if (mInterval) {
  446. clearInterval(mInterval)
  447. }
  448. // 重置最高分数
  449. maxScore = Math.max(maxScore, score)
  450. document.getElementById("max-score").innerHTML = maxScore
  451. // 2 弹出对话框
  452. alert("大吉大利,今晚吃鸡!")
  453. }
  454.  
  455. // 重新开始
  456. function reset() {
  457. const container = document.getElementById("container")
  458. const childs = container.childNodes;
  459. for (let i = childs.length - 1; i >= 0; i--) {
  460. container.removeChild(childs[i]);
  461. }
  462. fixedBlocks = {}
  463. score = 0
  464. document.getElementById("current-score").innerHTML = score
  465. init()
  466. }
  467. </script>
  468. </body>
  469.  
  470. </html>

转载于:https://blog.csdn.net/wanghuan1020/article/details/111473709

js实现简单的俄罗斯方块小游戏的更多相关文章

  1. JS练习实例--编写经典小游戏俄罗斯方块

    最近在学习JavaScript,想编一些实例练练手,之前编了个贪吃蛇,但是实现时没有注意使用面向对象的思想,实现起来也比较简单所以就不总结了,今天就总结下俄罗斯方块小游戏的思路和实现吧(需要下载代码也 ...

  2. C#俄罗斯方块小游戏程序设计与简单实现

    C#俄罗斯方块小游戏程序设计与简单实现 相信90后或者80后都玩过这款小游戏,一直想干一票,琢磨一下,但又不太懂,于是网上搜集修改就有了以下效果!bug较多,多多包涵! 1.效果展示 2.实现方法 参 ...

  3. html+css+js实现狼吃羊小游戏

    html+css+js实现狼吃羊小游戏 一.总结 一句话总结:给动的元素下标记,这里表现为将要活动的标签动态增加class,这是一种很好的思想. 1.如何实现棋子走动的时候简单精确定位? 用重构坐标系 ...

  4. Three.js 实现3D开放世界小游戏:阿狸的多元宇宙 🦊

    声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 2545光年之外的开普勒1028星系,有一颗色彩斑斓的宜居星球 ,星际移民 ...

  5. 初学JS——实现基于计时器的小游戏。

    这几天一直在看网易云课堂上免费的JS课程,正好今天看到讲了计时器setInterval,第一感觉就是像C#里的TIMER.然后课程里举得例子正好通过计时器改变新生成窗口的位置, 然后就突然有了灵感!可 ...

  6. d3.js 制作简单的俄罗斯方块

    d3.js是一个不错的可视化框架,同时对于操作dom也是十分方便的.今天我们使用d3.js配合es6的类来制作一个童年小游戏--俄罗斯方块.话不多说先上图片. 1. js tetris类 由于方法拆分 ...

  7. Three.js 实现3D全景侦探小游戏🕵️

    背景 你是嘿嘿嘿侦探社实习侦探️,接到上级指派任务,到甄开心小镇调查市民甄不戳宝石失窃案,根据线人流浪汉老石‍提供的线索,小偷就躲在小镇,快把他找出来,帮甄不戳寻回失窃的宝石吧! 本文使用 Three ...

  8. js、jQuery实现2048小游戏

    2048小游戏 一.游戏简介:  2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...

  9. 使用 App Inventor 2 开发简单的安卓小游戏

    App Inventor2 是一个简单的在线开发安卓应用程序的工具,通过此工具,我们可以很轻松地开发安卓应用. 这里介绍的是笔者自己写的一个小游戏,游戏中玩家通过左右倾斜手机控制“水库”的左右移动,收 ...

随机推荐

  1. Animate..css的一些属性使用

    使用基本的代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <t ...

  2. vue API 知识点(3) --- 实例 总结

    一.实例 property 1.vm.$data Vue 实例观察的数据对象,Vue 实例代理了对其 data 对象 property 的的访问 2.vm.$props 当前组件接收到的 props ...

  3. Python利用openpyxl带格式统计数据(1)- 处理excel数据

    统计数据的随笔写了两篇了,再来一篇,这是第三篇,前面第一篇是用xlwt写excel数据,第二篇是用xlwt写mysql数据.先贴要处理的数据截图: 再贴最终要求的统计格式截图: 第三贴代码: 1 '' ...

  4. PHP简单的计算位数的函数

    一个简单的PHP计算位数的函数: 1 <?php 2 //一个简单的计算字符串有长度的函数 3 #开始定义函数 4 function count_digit($number){ 5 $count ...

  5. JavaWeb基础总结:Servlet专题

    最近工作中有部分整改老接口的任务,大部分与Spring的拦截器,Tomcat相关,改到一些底层的代码发现,对基础J2EE的知识有些遗忘,需要频繁查阅,索性从头系统的整理一下Servlet和Filter ...

  6. 【mybatis-plus】CRUD必备良药,mybatis的好搭档

    做开发,免不了对数据进行增删改查,那么mybatis-plus我觉得很适合我这个java新手,简单好用. 官网在这 一.什么是mybatis-plus MyBatis-Plus(简称 MP),是一个M ...

  7. .NETCore使用EntityFrameworkCore连接数据库生成实体

    EF Core 通过数据库提供程序插件模型与 SQL Server/SQL Azure.SQLite.Azure Cosmos DB.MySQL.PostgreSQL 和更多数据库配合使用. 使用EF ...

  8. 各开源协议BSD、Apache Licence 2.0、GPL

    以下是上述协议的简单介绍:BSD开源协议BSD开源协议是一个给于使用者很大自由的协议.基本上使用者可以"为所欲为",可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有 ...

  9. Spring Cloud Hystrix原理篇(十一)

    一.Hystrix处理流程 Hystrix流程图如下: Hystrix整个工作流如下: 构造一个 HystrixCommand或HystrixObservableCommand对象,用于封装请求,并在 ...

  10. github与svn的区别

      github与svn都属于版本控件系统,但是两者不同于,github是分布式的,svn不是分布的是属于集中式的.   1) 最核心的区别Git是分布式的,而Svn不是分布的.能理解这点,上手会很容 ...