您的位置:首页 > 其它

MFC实现俄罗斯方块二

2008-12-03 20:17 274 查看
1>生成物体
大家想的都过于复杂了.生成物体只是为几个小方块生成几个 行列值,当然这个行列值不是随意的.而是有限制的.假如我们让第一个方块的行列值为 <-1,4> 然后依据这个方块在它的上下左右四个方向随机生成第二个方块,然后再根据第二个生成第三....根据第三个生成第四个.每个方块都是上一个方块的上下左右四个方向中非上一个方块的地方,那这个生成的物体正是我们要的!!!不信在纸上画一下! 根据这个思路进行改变.可以生成任何你要的形状!! 但是这样生成的却没有 T 形状的...(下面给出的是可以生成这个形状的代码)

知道了上一个方块的位置,我们只要一个相对于上一个方块位置的偏移就好了
(0,1) ---- 右
(-1,0) ---- 上
(1,0) ---- 下
(0,-1) -- 左
我们随机在这四个偏移量中拿出一个,生成下一个物体,但是又不能和上一个物体重叠 ,其实这次生成的偏移量不等于上一次生成偏移量的取反就满足要求.(在纸上画一下.任何时候你在纸上画画都能很快想明白一些问题,有时会得到不同的灵感)

// 随机的产生物体

void CRBlock::GenerateObject(struct tagObject &obj)

{

obj.object[0].row = obj.object[3].row = -1;

obj.object[0].col = obj.object[3].col = 4;

int x = -2,y = -2; // x,y 为偏移量

for (int c = 1; c <= 2; c++)

{

MakeRandomOffset(x,y); // 每次产生的位移不能是上一个方块的位置

obj.object[c].row = obj.object[c-1].row + x;

obj.object[c].col = obj.object[c-1].col + y;

x=-x,y=-y; // 上次生成的偏移量的取反

}

UpdateLimit(obj);

MakeRandomOffset(x,y);

/// 这个只是为了要得到一个 T 形状的物体而做的.否则把下面的代码写到上面的循环中就完成任务了

if (obj.r-obj.l == 2 || obj.b-obj.t == 2)

{

obj.object[c].row = obj.object[1].row + x;

obj.object[c].col = obj.object[1].col + y;

}

else

{

obj.object[c].row = obj.object[2].row + x;

obj.object[c].col = obj.object[2].col + y;

}

obj.color = RANDOM_COLOR;

UpdateLimit(obj);

}

// 随即产生一个偏移量.这个偏移量不能是 参数x和y相同的

// 随即值只有4种可取,即是x和y的绝对值不相同的.(0,0) (+-1,+-1) 的偏移都是不合法的.

void CRBlock::MakeRandomOffset(int &offsetX, int &offsetY)

{

static const int offset[] = {-1,0, 1,0, 0,-1, 0,1};

int oldX = offsetX;

int oldY = offsetY;

do

{

int _i = (rand()%4)*2;

offsetX = offset[_i];

offsetY = offset[_i+1];

} while (offsetX == oldX && offsetY == offsetY);

}

上面有一个函数还没有定义 下面就是:

// 更新物体的上下左右边界

// 左和上取最小

// 右和下取最大

void CRBlock::UpdateLimit(struct tagObject &obj)

{

obj.l = obj.object[0].col;

obj.r = obj.object[0].col;

obj.t = obj.object[0].row;

obj.b = obj.object[0].row;

for (int i = 1; i <= 3; i++)

{

if (obj.l > obj.object[i].col)

{

obj.l = obj.object[i].col;

}

if (obj.r < obj.object[i].col)

{

obj.r = obj.object[i].col;

}

if (obj.t > obj.object[i].row)

{

obj.t = obj.object[i].row;

}

if (obj.b < obj.object[i].row)

{

obj.b = obj.object[i].row;

}

}

}

假如你不想要这样的形状,你可以调整生成的四个小方块的相对位置.就这样简单几步你就可以生成任何你想要的形状.

爽否?

三>变形
上面是吃豆芽,下面就是啃骨头了.这是本程序的第二个难点
真的那么难么?你认为变形会如何解决?
说出来真让人失望.但又不得不说.这个骨头如此的脆弱,以至于当初摩拳擦掌准备下一翻苦功夫,栽几个大跟头的决心后备都用不上了,像是 下了老劲而一拳打在了棉花上.用钱钟书在<围城>里形容李梓梅见到"情敌"方鸿渐的时候的话说:这是快意的失望!(最近在看<围城>,钱钟书真是人才.写的书太好了.)

假如我们先找出这四个小方块最中间的一个,让它保持位置不变.而让其余的三个方块围着他向右做90度的旋转.是不是就是变形了?
估计有人在这个时候该骂 "他妈的" 了...我当时就是.在纸上坐标啊.角啊,余弦啊,比划了半天.结果就是这样就变形了. 真 "他妈的".但是我想用三角函数和角 在一个 x轴向右为正方向,y轴向下为正方向的坐标象限内(二维数组的逻辑)进行变形.就只是套用几个三角函数的公式就能完成了.这样程序将会简洁许多了.谁数学好,可以做一下,做好别忘了告诉我啊.(恨当初不该花那么多的时间跑出去玩通宵,数学没学好,真是后悔的我肠子都青了.童鞋们引以为戒).现在是0点48分.每这个时候大脑都会脱离我的精神独立控制四肢,因此废话多了些.说话意识流了点儿.不要介意.--!!
下面是变形的代码:

变形的过程中要注意的事情是:变形后不能覆盖住原来已经存在的方块位置.不能超出游戏区域边界.
因此一旦变形失败就重建到原来的状态.

// 方块变形

// 变形的实现步骤:

// 找出4个方块的中心方块..

// 其他3个方块围绕这个方块向右旋转90度.

// 其他3个方块相对于这个中心方块的位置只可能时 8中情况,

// 即是它的八个方向(包括对角线上的和水平垂直)

// 这个算法对物体变形的同时可能会造成物体左移,因此规定连续两次变形就右移一列

void CRBlock::Transform()

{

// 假如变形后失败,则重建到原来状态

struct tagObject objTemp = Object;

// 以(row,col)为中心旋转

int l = Object.l;

int ri = Object.r;

int t = Object.t;

int b = Object.b;

if (ri-l == b-t) // 正方形方块不变形,这个判断依据是,只有正方形的长和宽是相等的

{

return;

}

const int r = (t + b)/2;

const int c = (l + ri)/2;

// 变形实现,对4个小方块依次判断重新设定位置

for (int i = 0; i < 4; i++)

{

int &row = Object.object[i].row;

int &col = Object.object[i].col;

if ( row== r && col == c) // 中心方块不旋转

continue;

int offsetX = col - c;

int offsetY = row - r;

// 分八种情况分别变化

if (offsetX > 0) // 在中心方块右边

{

if (offsetY == 0) // 正右方

{ // 到正下方

row = r + offsetX;

col = c;

}

else if (offsetY > 0) // 在右下方

{ // 到左下方

col = c - offsetX;

}

else // 右上方

{ // 到右下方

// 列不变

row = r - offsetY;

}

}

else if (offsetX == 0) // 和中心点在同一列,offsetY有正负号,恰好可以写成一个式子

{

row = r;

col = c - offsetY;

}

else // 在中心方块左边

{

if (offsetY > 0) // 左下

{// 到左上

//列不变

row = r - offsetY;

}

else if (offsetY == 0)// 正左方

{// 到正上方

row = r + offsetX;

col = c;

}

else // 左上

{// 到右上

// 行不变

col = c - offsetX;

}

}

if (col < 0 || col >= 10 || (row > 0 && block[row][col].bSet)) // 变形失败

{

Object = objTemp;

return;

}

}

UpdateLimit(Object); // 更新方块的边界

if (m_nTimesTransform == 2) // 连续变形了两次

{

Move(RIGHT); // 右移一个单位

m_nTimesTransform = 0;

}

}

下次就是控制了.

c,c++,mfc 编程群: 58698324 欢迎加入
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: