Unity教程|魔方游戏(附游戏开源代码)
这个魔方游戏的前期的实现参考了许多教程,但全部代码逻辑都是本人写的(借鉴了的都会给出原贴链接),只讲实现的思路。已完成:
魔方的转动和魔方的动画效果,支持魔方的cfop全部公式,按按钮可转动魔方
按键盘上的alt键可用移动鼠标360无死角观察魔方
魔方中心块加了转动提示符,提示魔方是须时针转还是逆时针旋转,双击转动提示符可快速将其设为F面
魔方默认为须时针转动,按键盘上的ctrl键,可切换魔方的转动类型和提示符类型为逆时针旋转
一建打乱,魔方状态保存和复原、可点击魔方块知道魔方的颜色情况,目前也支持了检测魔方的还原情况,魔方还原算法,还在测试中。。。
测试图:
魔方游戏转动思路最初来源于b站的一个视频:萌新学unity可以做一个魔方玩吗?
给我提供了一个很好的思路,我要做的是一个三阶魔方,魔方的转动就是最大的问题,视频中大佬思路是:
1.先摆放27个方块形成一个魔方,然后用6个较薄的正方体作为魔方的控制器,分别置于魔方的六个面,每一个魔方控制器都与9个方块进行触碰。
2.当魔方某个面要进行旋转的时候,相当于选择了某个魔方控制器,然后被选中的魔方控制器去检测与自己产生触碰的物体,将其变成自己的子物体,控制器再去旋转,就完成对魔方某个面的旋转。
3.若选择了某一个魔方控制器,那么剩余的5个魔方控制器都不能有子物体,若有则要将之前的子物体释放,从而避免所形成的魔方控制器得到的方块面不完整。
虽然这种思路可行,但是有个很大缺点,只能对魔方的某个面进行旋转,当我想对魔方的中间进行(E、M、S)旋转时,它做不到,这个就涉及到unity触碰的判断机制:
当A物体与B物体相互触碰,若C物体去触碰A物体,unity会认为C物体触碰到了A物体和B物体。
打一个比较恰当的比喻,就是两个人触电了,你不管摸哪一个都会触电。
如果我用上述的思路,对魔方进行E、M、S的任意一个中间旋转,旋转的都是整个魔方,而不是中间块!
所以想让27个小方块形成的魔方可以随意的转动,第一个要解决的问题是:如何生成控制器?
我想出的方式是用三维坐标来判断,事实证明这种方法很有效果,感觉不但可以用于三阶,还可以用于4阶、5阶等魔方游戏的控制器判断。
首先我让三阶魔方的轴心置于(0,0,0),白色为底面,则会发现一个这样一个规律:
(a,a,-1)F (1,a,a)R (a,1,a)U
(a,a,1)B (-1,a,a)L (a,-1,a)D
若要判断F面的方块,只需让27个方块分别一下判断三维坐标的z轴是否等于-1,得到是9个符合条件的方块。
(a,0,a) E (0,a,a) M (a,0,a) S
若要判断E面的方块,只需让27个方块分别一下判断三维坐标的y轴是否等于0,得到是9个符合条件的中间方块。
f=S(条件)+ F(条件) r=M(条件)+R(条件) u=E(条件)+U(条件)
b=S(条件)+ B(条件) l=M(条件)+L(条件) d=E(条件)+D(条件)
若要判断f面的方块,只需让27个方块分别一下判断三维坐标的y轴是否等于0或z轴是否等于-1,得到是18个符合条件的方块。
实现后发现了一个小问题,就是旋转后魔方的坐标会有一点小误差,不会是刚等于1或0,有可能是1.001或0.0082等,所以判断前要用Mathf.Round()进行误差的去除,才能得到正确的方块数量,不然转着转着,魔方就会出现方块丢失的情况。
魔方转动是整个游戏的最核心部分,实现步骤:
1、27个魔方方块的创建,主要参考的是:Unity教程 | 手把手教你拼一个3D“魔方”,生成的只是一个模型并不能动。
2、12个魔方控制器创建,有6个面控制器和6个中心块控制器,用于控制27个方块。
3、定义了18个按钮,用一个脚本初始化了,主要参考的是:Unity:使用数组管理多个Button
4、魔方旋转动画的实现:
1.用的是四元数插值实现的魔方动画,避免了万向锁问题,但四元数转动只转一次就没了,那就需要保存转动数值且要保持角度的连贯性,完美解决的方法是角度叠加法(我原创的)。
角度叠加法:先定义一个旋转的初始方向,顺时针转则加90,逆时针转减90,角度限制在-360度至360度之间,可以这样理解这旋转原理,记录下了上一次的角度,顺时针转加上90就得到顺时针转的目标值,逆时针转减去90就得到逆时针转的目标值。
2.魔方控制器的值不能相互影响,经过我的探索,12个魔方控制器刚好动画能互相不受影响。
3.魔方旋转动画要按时完成且还要保证转到位,用协程能很好解决这问题。
魔方动画效果代码是:
private IEnumerator RotateOverTime(Transform transformToRotate, Quaternion targetRotation, float duration)
{
var timePassed = 0f;
while (timePassed < duration)
{
var factor = timePassed / duration;
transformToRotate.rotation = Quaternion.Slerp(transformToRotate.rotation, targetRotation, factor);
// 增加自上一帧起经过的时间
timePassed += Time.deltaTime;
// 重要的这告诉Unity在这里中断,渲染这个帧
// 在下一帧中从这里继续
yield return null;
}
// 要确保以精确值结束,请在完成时设置目标旋转修复
transformToRotate.rotation = targetRotation;
}调用动画协程的方法:
StartCoroutine(RotateOverTime(mofanControlList.transform,Quaternion.Euler(mofan_rotate * n1), 0.3f));
自由观察魔方实现:
在主摄像机上绑了一个脚本,让摄像机绕着魔方转,实现一种可随意观察的效果,但这也导致了一个问题,用按钮操控魔方的各个面,但分不清哪面跟哪面,于是我在魔方的中心块上加了魔方转动标示符。
魔方状态保存和复原:
用的是保存27个魔方块的坐标和欧拉角来保存魔方的状态,后面发现用魔方块的坐标和欧拉角可以反推魔方的颜色,具体看:魔方状态检测2_qq_39858654的博客-CSDN博客
这个我列了480记录,用了一个星期左右的时间发现的。
游戏的完整的代码已经在gitee上传,地址为:
https://gitee.com/caoctllo/intelligent-cube
https://gitee.com/caoctllo/intelligent-cube
游戏还有待完善,现处于测试阶段,源码只有75kb多,下载后可在uinty那新建项目导入,导入后会出现少了个tag,需要新建一个tag名为mofan_control就能运行了
贴子没完善,游戏完成后再完善
页:
[1]