最近看最强大脑第五季,其中是数字华容道和我在高中手机游戏还不多的时候玩的拼图游戏,那时候与同学相互比较,最后都可以在1~2秒内完成游戏,然后就渐渐对这种游戏失去兴趣.现在我对他又突然产生了新的兴趣,就是自己动手把他做出来,前前后后不过两三个小时就完成了.当然时间短促,游戏也不完善,只能算是个Demo,今天拿出来跟大家分享下.
下面正式开始
首先我们需要九张分割好的图片的,我们可以提前准备好九张切好的图,但是这样不但浪费资源,而且不易扩展,所以我的做法是导入一张整图,然后制作九个材质球,利用shader的Tilling和offset实现图片的切分.后面如果提供切换图片的功能,就只用替换材质球里面的图片就好了.
如图中,左上角的图片起始位置就是图中橙色的点,以整张图片为左下角为(0,0)点,所以橙色点的offset为(0,0.66666)。
其余的分别为(0.333,0.666)(0.666,0.666)(0,0.333)(0.333,0.333)(0.666,0.333)
最底下的一排大家很容易就可以推出来了,这里留给大家自己填充
因为每一个小图都占大图1/3,所以tiling都是(0.333,0.333)。
因为游戏并不完善,所有只有游戏逻辑的代码,并没有各种模块管理的脚本。
这里主要就是两个脚本,一个是GameManager,负责游戏的主要逻辑,一个是block,负责各个方块自己的交换。
其实主要的逻辑就只有两个,一个是如何打乱拼图,一个就是方块的移动。
所以GameManager主要是打乱拼图,检测游戏状态,而block脚本则只负责响应自己的点击事件,并进行位置的移动。
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
//单例模式
#region single instance
private static GameManeger instance;
public static GameManeger Instance { get { return instance; } }
void Awake()
{
instance = this;
}
#endregion
public Transform emptyTransform;//记录一开始的空位置的坐标
[HideInInspector]//在面板上隐藏掉这个公共变量
public Vector3 empty;//方块移动时存储的空位置的坐标
public GameObject[] pieces;//存储各个方块
private Vector3[] piecePositions;//存储各个方块的位置,用作判断是否完成游戏
private bool isSwaped = false;//记录是否调用SwapPiece()方法,用作判断是否完成游戏
void Start () {
//初始化empty,piecePositions的值
empty = emptyTransform.position;
piecePositions = new Vector3[pieces.Length];
for (int i = 0; i < pieces.Length; i++)
{
piecePositions[i] = pieces[i].transform.position;
}
SwapPiece();
}
public void SwapPiece()//打乱方块的方法
{
int[] step = { -1, 1, -3, 3 };
int emptyIndex = pieces.Length - 1;//空白方块的索引
int i = 0;
while( i < 1000)//随机点击各个方块,每点击一次就交换了一次方块
{
var index = emptyIndex + step[Random.Range(0, 4)];
if (index < 8 && index >=0)
{
pieces[index].GetComponent().OnMouseDown();
i++;
}
emptyIndex = index;
}
isSwaped = true;
}
public void SwapEmpty(Vector3 targer)//主要是判断游戏结果
{
empty = targer;
if (emptyTransform.position == empty)
{
bool isWin = true;
for (int i = 0; i < pieces.Length; i++)
{
if (pieces[i].transform.position != piecePositions[i])
{
isWin = false;
break;
}
}
if (isWin && isSwaped)
{
print("Win");
isSwaped = false;
}
}
}
}
using UnityEngine;
using System.Collections;
public class Block : MonoBehaviour {
public void OnMouseDown()
{
//判断与空方块的距离,如果不是与空方块相邻的物体这不能交换
if (Vector3.Distance(transform.position,GameManager.Instance.empty) <= 3.8f)
{
var temp = transform.position;
transform.position = GameManager.Instance.empty;//交换位置
GameManager.Instance.SwapEmpty(temp);//每次交换都需要根据空方块的位置,进行判定是否已经完成游戏
}
}
}
代码其实很简单,游戏的主要流程大家看代码和注释应该就能明白了,但是GameManager里面的只有一个个方法需要重点讲一下.
int[] step = { -1, 1, -3, 3 };
这第一句大家可能就看不懂了,不知道是干嘛用的.但是只要把这个搞懂了,这个算法就算是搞懂了.
来,先上图
一图
二图
本来我以为打乱拼图只需要将pieces数组里面的物体随机分布在这9个位置上就可以了,但是这样就会出现拼图不能还原的问题,因为拼图的方块位置是固定的.比如,会出现上面一图中7,8位置互换的情况,这样就光靠移动时还原不了的.
所以的换了一个思路,就是随机点击各个方块,使用移动,因为是靠移动打乱,这样靠移动就一定可以还原拼图,但是移动也不是直接在8张图上随机点,如图1情况,只有6,8是可以移动的,而其他的方块点击是无效的,所以我们需要在有效的方块里面进行随机.
因为每次交换都是与empty进行交换,所以我们可以以empty作为标志.如图1情况,empty是9,有效方块是6,8.,如图2情况,empty5,有效情况是2,4,6,8.所以规律是有效的方块永远只会出现在empty的上下左右,而换成对应的索引就是empty-1.+1.-3.+3.所以我们只需在empty加上{ -1, 1, -3, 3 }这四个数,就可以进行有效随机.但是要注意做一下范围判断,索引要保证在[0,7]
然后就是SwapEmpty()方法,其实很简单.所以也简单说下,
就是每次交换都做一下判断,如果empty在上图9的位置,就比对所有的方块位置与最开始的位置,判断胜利,胜利后,要重新打乱才可再次判定