用面向对象的方法写一个俄罗斯方块(一):设计思路

2018-10-29  本文已影响50人  HolidayPeng

俄罗斯方块的逻辑稍微有些复杂,实现的方法也有很多,这里分享其中一种。
首先我们得有数据驱动的思维,把这个游戏抽象成两组数据:
方块活动的范围是一组数据,方块可以在这个范围向左、向右、向下移动,我们可以把这个范围标记为一个二维数组,类似于一个xy坐标轴:

gameAreaData: [
  [0, 0, 0, 0, 1, 0, 0, 0, 0, 0] ,
  [0, 0, 0, 0, 1, 1, 1, 0, 0, 0] ,
  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ,
  [2, 2, 2, 2, 2, 2, 2, 2, 2, 0] 
  …
]

没有方块的时候该坐标单位的值为0,有方块并且方块可以移动的时候值为1,方块不能移动的时候值为2。
方块有不同的形状,每种形状又可以旋转,同样可以用一个二维数组来保存这些形状,比如长条:

teris: {
  origin: [
    [1, 1, 1, 1]
  ],
  rotate: [
    [
      [1, 1, 1, 1]
    ],
    [
      [1],
      [1],
      [1],
      [1]
    ],
    [
      [1, 1, 1, 1]
    ],
    [
      [1],
      [1],
      [1],
      [1]
    ]
  ]
  …
}

另外方块在移动时,我们需要知道方块移动的位置,是向下移动一个单位,还是向右/向左移动了一个单位。我们可以用一个对象来保存当前位置:

position: {
 x: 0,
 y: 0
};

现在两组数据我们都有了,要做的就是在方块位置移动的时候或者形状变化(旋转)的时候,把第二组数据的值赋给第一组数据:

function updateData() {
  for (let i = 0; i < teris.origin.length; i++) {
    for (let j = 0; j < teris.origin[0].length; j++) {
      gameAreaData[teris.position.x + 1][teris.position.y + j] = teris.origin[i][j];
    }
  }
}

这样俄罗斯方块的基本逻辑我们就有了,现在可以来考虑一下代码结构的问题。
首先七种方块由于形状不同,内部的数据也不同,我们可以把它们分成七个类:

class IBlock ;
class Square;
class RLblock;
class TBolck;
class Swagerly;
class RSwagerly;
class LinePiece;

操作这其中方块的方法是共享的,可以把这些方法放在一个共同的类里,并让这个类继承七种方块的属性(数据):

class Shapes() {
  constructor: {
    this.shapesData = [
      lBlock,
      Square,
      RLblock,
      TBolck,
      Swagerly,
      RSwagerly,
      LinePiece
    ]
  }
}

为了让Shapes每次被实例化的时候系统不必分配内存给它的方法,我们把这些方法写在原型链上:

class Shapes() {
  constructor: {
    this.shapesData = [
      lBlock,
      Square,
      RLblock,
      TBolck,
      Swagerly,
      RSwagerly,
      LinePiece
    ]
  }
}

Shapes.prototype.updateData = function() {
  for (let i = 0; i < teris.origin.length; i++) {
    for (let j = 0; j < teris.origin[0].length; j++) {
      gameAreaData[teris.position.x + 1][teris.position.y + j] = teris.origin[i][j];
    }
  }
}
……

最后到游戏的具体操作部分,我们把这些操作都放在一个JS文件里。这一篇先讲解思路,下一篇再续上完整的实现过程。

上一篇下一篇

猜你喜欢

热点阅读