VC 6.0 面向对象的俄罗斯方块尝试(部分注释)

本文详细介绍了使用面向对象的方法设计俄罗斯方块游戏的过程。通过创建矩阵类、形状类和底盘类,逐步构建游戏的核心逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  游戏在一个m*n的矩形框内进行。游戏开始时,矩形框的顶部会随机出现一个由四个小方块构成的形状,每过一个很短的时间(我们称这个时间为一个tick),它就会下落一格,直到它碰到矩形框的底部,然后再过一个tick它就会固定在矩形框的底部,成为固定块。接着再过一个tick顶部又会出现下一个随机形状,同样每隔一个tick都会下落,直到接触到底部或者接触到下面的固定块时,再过一个tick它也会成为固定块,再过一个tick之后会进行检查,发现有充满方块的行则会消除它,同时顶部出现下一个随机形状。直到顶部出现的随机形状在刚出现时就与固定块重叠,表示游戏结束。

  说的有点罗嗦,但是细细分析一下每隔tick之间发生事情的顺序对理清程序思路有好处。

  接下来开始分析程序的设计了。

  照理应该从大的设计一步一步往下细分的,但由于时间有限,我就反过来从小的往大的讲了,请谅解。我会尽量把问题说明白。

  显然俄罗斯方块是一个简单的游戏,因为它都是基于矩阵的。既然是面向对象的方法来写,那么我们首先应该封装一个矩阵类,权且叫做CMatrix吧。

  class CMatrix //矩阵类,这是一个整形矩阵类型

  {

  public:

  //默认构造函数。

  CMatrix();

  //根据构造函数参数创建指定大小的矩阵

  CMatrix(int width, int height);

  //根据构造函数参数创建指定大小的矩阵,并为矩阵的每个元素统一分配一个初始值。

  CMatrix(int width, int height, int initValue);

  virtual ~CMatrix();

  //重新设置矩阵的尺寸。

  void ResetSize(int width, int height);

  //将左右元素设置为一个值。

  void SetAll(int value);

  //设置row行col列的元素值为value。

  void SetAt(int row, int col, int value);

  //获取矩阵宽度。

  int GetWidth() const;

  //获取矩阵高度。

  int GetHeight() const;

  //获取row行col列元素的值。

  int GetAt(int row, int col) const;

  //旋转矩阵,参数为是否顺时针。

  bool Rotate(bool clockWise = true);

  //获取第row行指针,调用者可以通过“(CMatrix对象)[行][列]”来获取或设置元素。

  int* operator[](int row) const;

  //重载等号运算符,其实也可以写拷贝构造函数。

  CMatrix& operator=(CMatrix &srcMat);

  protected:

  //这些都是私有的成员数据,意义可以从名字上看出。

  int *m_pData;

  int m_width;

  int m_height;

  protected:

  //这里都些私有的函数,都是被上面的公共函数所使用的。

  //释放数据资源。

  void ReleaseData();

  //为数据分配资源。

  void InitData(int width, int height);

  //设置数据内容。

  void SetData(int initValue);

  //内存块拷贝。

  static void MemCopy(int *dest, int *src, int len);

  };

  接下来需要把下落的随机形状也封装成一个类,命名为CShape。

  class CShape //该类实际上是把一个CMatrix类的对象封装了起来,并且组织了一些操作。

  {

  public:

  CShape();

  virtual ~CShape();

  //创建一个随机形状,注意这里随机其实是指在俄罗斯方块中的7种形状中的某一种。参数是该形状的左上角坐标,默认(0,0)。

  void CreateRandomShape(int posX = 0, int posY = 0);

  //设置该形状的左上角坐标。

  void SetPos(int posX, int posY);

  //旋转形状,众所周知,俄罗斯方块游戏中的形状是可以旋转的。默认就是顺时针的旋转。

  void Rotate();

  //取消前次旋转,这个函数有它的用处,代码读下去就会明白的。

  void CancelRotate();

  //使形状向下移动一格。

  void MoveDown();

  //使形状向上移动一格。

  void MoveUp();

  //左一格。

  void MoveLeft();

  //右一格。

  void MoveRight();

  //获取当前形状的类型ID,分别代表7种形状。(0~6)

  int GetShapeType() const;

  //获取当前形状的左上角坐标。

  POINT GetPos() const;

  //获取形状占用的宽度。

  int GetWidth() const;

  //..............高度。

  int GetHeight() const;

  //重载[]操作符。

  const int* operator[](int row) const;

  //重载等号,也可以写一个拷贝构造函数。

  CShape& operator=(CShape& srcShape);

  protected:

  //被封装的CMatrix对象。

  CMatrix m_mat;

  //形状的类型ID。

  int m_type;

  //一个比较微妙的值,暂时不解释,读代码会明白的。关系到形状的旋转,有些形状可以旋转出四种样子,但有些是由两种样子。

  bool m_needJump;

  //左上角X坐标。

  int m_posX;

  //......Y....。

  int m_posY;

  protected:

  //这里都些私有的函数,都是被上面的公共函数所使用的。

  //随机创建一个形状。

  void RandCreate();

  //随机旋转几次。

  void RandRotate();

  //旋转形状,参数表示是否顺时针。

  void RotateShape(bool clockwise);

  };

  有了形状类之后,我们还需要一个底盘类,用来表示游戏中除了当前下落的形状之外的背景部分和已经固定的块。我们称这部分为底盘,类名为CBoard。

  class CBoard //此类其实也是对一个CMatrix的对象进行了封装。

  {

  public:

  //构造函数时默认的底盘大小是10*20。

  CBoard();

  virtual ~CBoard();

  //重新设置底盘的大小,并且底盘被清空。这个函数好像没用到。但是整个编写过程用的是面向对象的思想,所以在写这个类的时候我把外面可能会调用的方法都写成了公共接口。

  void ResetSize(int width, int height);

  //设置row行col列的值为value。value的取值为两个宏,R_EMPTY和R_BLOCK,分别表示“空”和“有方块”状态。

  void SetAt(int row, int col, int value);

  //将形状shape结合到底盘中,成为底盘的一部分。

  void UniteShape(const CShape& shape);

  //清除所有排满方块的行中的方块,并使这些行上面的方块们下落下来。

  int ClearRows();

  //获取底盘宽度。

  int GetWidth() const;

  //........高度。

  int GetHeight() const;

  //获取row行col列的格子的内容,两种值:R_EMPTY和R_BLOCK。

  int GetAt(int row, int col) const;

  //获取底盘数据到指针的destBuffer所指的空间。该空间至少要有GetWidth()*GetHeight()*sizeof(int)个字节大小。

  void GetBoardData(int *destBuffer) const;

  //独立性检查,检查形状shape是否独立。shape如果和底盘上的固定块有部分重叠则不独立返回false,否则独立返回true。

  bool SingleTest(const CShape& shape) const;

  bjbjz.howbk.com

  shbjz.howbk.com

  tjbjz.howbk.com

  cqbjz.howbk.com

  hebbjz.howbk.com

  jlbjz.howbk.com

  sybjz.howbk.com

  dlbjz.howbk.com

  asbjz.howbk.com

  jnbjz.howbk.com

  qdrbjz.howbk.com

  zbbjz.howbk.com

  dybjz.howbk.com

  ytbjz.howbk.com

  wfbjz.howbk.com

  tybjz.howbk.com

  xabjz.howbk.com

  sjzbjz.howbk.com

  tsbjz.howbk.com

  qhdbjzz.howbk.com

  lybjz.howbk.com

  zzbjz.howbk.com

  whbjz.howbk.com

  csbjz.howbk.com

  wxbjz.howbk.com

  njbjzz.howbk.com

  lczem.howbk.com

  wzme.howbk.com

  labjz.howbk.com

  czme.howbk.com

  lfbjz.howbk.com

  whmi.howbk.com

  qdmt.howbk.com

  ycme.howbk.com

  ylme.howbk.com

  csme.howbk.com

  hebjz.howbk.com

  ncme.howbk.com

  ykme.howbk.com

  xyme.howbk.com

  xmme.howbk.com

  fzme.howbk.com

  wzcm.howbk.com

  sxcm.howbk.com

  hzme.howbk.com

  jnme.howbk.com

  dyme.howbk.com

  hfme.howbk.com

  hfme.howbk.com

  czce.howbk.com

  czmt.howbk.com

  zzmi.howbk.com

  jcbjz.howbk.com

  nbme.howbk.com

  nbzj.howbk.com

  wzbze.howbk.com

  sxzje.howbk.com

  hzzj.howbk.com

  jhbjz.howbk.com

  jnbzm.howbk.com

  lyjz.howbk.com

  qdzjb.howbk.com

  whait.howbk.com

  dyzj.howbk.com

  ytjz.howbk.com

  wfjz.howbk.com

  heze.howbk.com

  //边界检查,检查形状shape是否在边界内。在界内返回true,出界则返回false。

  bool RangeTest(const CShape& shape) const;

  //重载[]运算符。

  const int* operator[](int index) const;

  protected:

  //被封装的矩阵对象。

  CMatrix m_mat;

  protected:

  //这里都些私有的函数,都是被上面的公共函数所使用的。

  //检查第index行是否全满。

  bool IsRowFull(int index) const;

  //检查第index行是否全空。

  bool IsRowEmpty(int index) const;

  //检查第index行是否全X。当full为trye时X=满,否则X=空。此函数为上面两个函数服务。

  bool IsRowInStatus(int index, bool full) const;

  //清除第index行中的所有方块。

  void ClearRow(int index);

  //使所有漂浮在半空的固定块下落。

  void FallDown();

  //拷贝第srcRow行到第destRow行。

  void CopyRow(int destRow, int srcRow);

  //状态检测,服务于SingleTest函数和RangeTest函数。

  bool ShapeTest(const CShape& shape, bool coverTest) const;

  };

  现在有了形状类和底盘类,应该可以做游戏的逻辑部分了。我们把整个游戏逻辑封装在一个叫做CRussia的类中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值