关于边界碰撞和方块碰撞
完成了下落对象基本的移动和旋转还不够,在很多情况下下落对象是不能移动和旋转的。
第一种情况,我们不能让对象超出边界
第二种情况,在周围存在已经固定的方块时,我们不能让对象和这些方块重合
为了解决这个问题,我想到了办法:
在玩家按下按键后,先生成一个GameObject
检验这个临时对象能不能存在,即检验x,y是否在0-9,0-23(有四行不在界面范围内,给玩家反应时间和方便检验失败)内(第一种情况)
把坐标带入staticblock数组内验证是否为true(第二种情况)
public bool CrachCheck(Tpoint[] point4)
{
for(byte i=0;i<4;i++)
{
if(point4[i].x<0|| point4[i].x>9 || point4[i].y == 24)
{
return false;
}
if(point4[i].y>4&& point4[i].y<23)
{
if (staticBlock[point4[i].y - 4, point4[i].x])
return false;
}
}
return true;
}
刚开始我是这样想的,以上判定为假的话,直接锁住按键,然后不做任何行为,自然下落,不就行了吗?
然而,思考之后我发现不行。玩过俄罗斯方块的人都知道,如果在边界按旋转的话,依然是可以旋转的,只不过旋转中心不是原来的旋转中心,所以以上判断只能验证方块是否存在,判断能否移动可以,判断旋转还要另想办法
经过几节英语课摸鱼的思考(哈哈哈),我想到了三种方法,最后我用了最简单的方法,且听我一一道来
第一种方法(复杂,但完美)
我们之前做了一个中心坐标和他的三个矢量坐标来实现旋转,如果我们把临时对象的每个方块都匹配三个矢量坐标,收到旋转命令时把每一个都试一下,(当然存在优先级,中间的优先级高,周围的优先级低)如果有满足的,就执行,如果没有,就不执行(太完美了,可以解决周围有固定方块的情形,我后面两个方法均不能解决此问题,我强烈怀疑真正的游戏源码就是采用的这个方法)
最先想到的方法,但每个方块都要算矢量坐标,一个方块3个坐标,一个对象就是12个坐标,七个对象加起来一共是84个坐标,太麻烦,当然也可以编个程序算,但是我懒的编
第二种方法
当临时对象的四个方块坐标存在负数时,给中心对象加上这个负数的绝对值,然后生成这个新对象,再检验,如果通过,则采用新对象对象,不通过,则采用初始对象
我一开始用的是这个方法,但由于本人代码不精,出现了bug,老消不掉,气得我把这段全删了
第三种方法
我用了这个最简单的方法,这个方法特别简单,也特别巧妙。当四个坐标有x=0或者x=9时(即有对象处于边缘时。注意!不是临时对象,是按键还没有按下的时候的初始对象)直接锁死左或右键,(在0锁死左键,反之亦然)并且如果玩家按下旋转键,这里以在左边缘举例,执行下落对象向右移动的命令,然后旋转,此时即等同于玩家按下了右键和旋转键
if (Keypress!=Keypress.NULL)
{
response = 0;
switch (Keypress)
{
case Keypress.A: tempcenturePoint.x--; break;
case Keypress.D: tempcenturePoint.x++; break;
case Keypress.J: tempAngle++;tangle = true; break;
default:break;
}
if (tangle && tempcenturePoint.x == 0)
{
if (tempAngle == 1 && gO == GO.I)
tempcenturePoint.x += 2;
else
tempcenturePoint.x++;
}
if (tangle && tempcenturePoint.x == 9)
{
if (tempAngle == 1 && gO == GO.I)
tempcenturePoint.x -= 2;
else
tempcenturePoint.x--;
}
Objectgame tempobjectgame = new Objectgame();
Tpoint[] temppoint4 = tempobjectgame.GetPoint(gO, tempcenturePoint, (byte)(tempAngle % 4 + 3));
if (CrachCheck(temppoint4))
{
centureX = (byte)tempcenturePoint.x;
centureY = (byte)tempcenturePoint.y;
angle = tempAngle;
}
Keypress = Keypress.NULL;
}
time1的代码
(嘿嘿,各位看官能理解吗,是不是很巧妙)
然而,当出现长条对象时(I),在某个角度旋转,移动一格是不行的,这个可以加一个特例,处于这个情况时移动两格
关于下落碰撞检测,和这个差不多,码字累了,就不赘述了,直接上代码吧
tempcenturePoint.y++;
Objectgame tempobjectgame1 = new Objectgame();
Tpoint[] temppoint41 = tempobjectgame1.GetPoint(gO, tempcenturePoint, (byte)(tempAngle % 4 + 3));
if (FallCheck(temppoint41))
centureY = (byte)tempcenturePoint.y;
else
tfall = true;
Tpoint centurePoint = new Tpoint();
centurePoint.x = centureX;
centurePoint.y = centureY;
Objectgame objectgame = new Objectgame();
Tpoint[] point4 = objectgame.GetPoint(gO, centurePoint, (byte)(angle % 4 + 3));
time1的代码
private bool FallCheck(Tpoint[] point4)
{
for (byte i = 0; i < 4; i++)
{
if (point4[i].x < 0 || point4[i].x > 9)
{
break;
}
if(point4[i].y == 24)
{
return false;
}
if (point4[i].y > 4 )
{
if (staticBlock[point4[i].y - 4, point4[i].x])
return false;
}
}
return true;
}
这样的话就解决了碰撞问题,如果你觉得我的方法好的话,就给我点个赞吧!
下一节我会讲定时器的一次执行的整体流程,就是把我们之前写的函数拼接在一起,这样游戏就大功告成啦!