整体代码解析:
整体常量存储:
public const int Column=6;
public const int Row=7;
public int ConstraintCount;
public GameObject count_Text;
public GameObject combo_Text;
public GameObject target_Text;
public static int count=0;
public int sum = 0;
public static int combo = 0;
public int origicombo;
public static int step = 15;
public int targetCount=200;
void Awake()
{
count_Text.GetComponent<Text>().text = "当前分数:" + count;
combo_Text.GetComponent<Text>().text = combo+"连击!";
target_Text.GetComponent<Text>().text = "目标分数:" + targetCount;
origicombo = combo;
ConstraintCount = Row + 1;
gameObject.GetComponent<GridLayoutGroup>().constraintCount = ConstraintCount;
}
void Update()
{
if (count >= targetCount)
{
count_Text.GetComponent<Text>().text = "恭喜通关!";
}
else
{
if (step <= 0)
{
count_Text.GetComponent<Text>().text = "Game Over!";
}
else
{
combo_Text.GetComponent<Text>().text = (combo - 1) + "连击!";
//连击奖励
if (origicombo != combo && combo > 1)
{
count += (combo - 1) * 5;
origicombo = combo;
}
count_Text.GetComponent<Text>().text = "当前分数:" + count + "\n" + "步数:" + step;
if (combo >= 2)
{
combo_Text.SetActive(true);
combo_Text.transform.DOScale(new Vector3(2f, 2f, 2f), 0.5f);
}
else
{
combo_Text.SetActive(false);
combo_Text.transform.DOScale(new Vector3(1f, 1f, 1f), 0.5f);
}
}
}
}
这里主要是对一些常量数据进行存储,单独列出一个脚本存储方便后面的修改,比如行和列,还有全局唯一的变量,比如分数和连击数等,同时相关逻辑也在这里进行了修改。
方块内部的数据:
//自身的二维坐标:
public Vector2 localPosition = new Vector2();
//自身的图片:
public Texture localTexture = new Texture();
//自身的真实坐标,方便自身做动画的时候进行移动:
public Vector3 localPrePo = new Vector3();
//是否是炸弹
public bool boomFlag = false;
初始化逻辑:
public void CellInit()
{
int cellTexture = Random.Range(1, 6);
localTexture = Resources.Load("Texture/" + cellTexture.ToString())as Texture;
}
通过随机数来进行随机的材质添加,然后在Awake里面给自身的localTexture赋值就行,还有自身的坐标等。不过这里我遇到的问题就是刚开始初始化的时候坐标都是在一个点,所以用了一个延时初始化坐标,这样就可以保证在整体排列好以后坐标也不会错误,遇到这种问题的可以debug测验一下然后尝试一下这种方法。
void ListInit()
{
for (int i = 0; i <= ConstClass.Row; i++)
{
for (int j = 0; j <= ConstClass.Column; j++)
{
GameObject obj = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/Button"));
obj.name = "item" + count;
obj.transform.SetParent(gameObject.transform);
obj.GetComponent<ZYCell>().localPosition = new Vector2(i, j);
buttonsList.Add(obj);
objStore.Add(new Vector2(i,j),obj);
count++;
}
}
}
这一段逻辑是用来初始化整体列表的,所有的物体都需要存储在一个数据结构上面方便后期存取。这里我使用的是一个Dictionary结构,键是每个点的二维坐标(不是真实坐标),值的话是物体本身。后面每一次对物体的交换或者消除,其实本质是对每个方块内部的数据进行改变和判断,同时也是对整个存储字典的数据维护,这两个搞不对或者忘记了维护的话,会产生各种问题,有问题的时候可以看看有对这两个进行维护没有。
拖拽的判断:
void Start()
{
beginPos = transform.position;
image = transform.GetComponent<RawImage>();
//Invoke("FirstDelet",0.2f);
}
public void OnBeginDrag(PointerEventData eventData)
{
beginPos = transform.position;
beginMouse = eventData.position;
image.raycastTarget = false;
transform.SetAsLastSibling();
}
public void OnDrag(PointerEventData eventData)
{
//进行移动条件判断,通过返回的向量角度来判度
endMouse = eventData.position;
float angle= Diraction(beginMouse, endMouse);
//上移
if (angle<135&&angle>45)
{
moveFlag = 1;
transform.position = new Vector3(transform.position.x, Input.mousePosition.y, transform.position.z);
if (Mathf.Abs(transform.position.y - beginPos.y) > 20f)
{
transform.position = new Vector3(transform.position.x,beginPos.y+20f,transform.position.z);
}
}
//下移
else if (angle>-135&&angle<-45 )
{
moveFlag = 2;
transform.position = new Vector3(transform.position.x, Input.mousePosition.y, transform.position.z);
if (Mathf.Abs(transform.position.y - beginPos.y) > 20f)
{
transform.position = new Vector3(transform.position.x,beginPos.y-20f,transform.position.z);
}
}
//左移
else if (angle < 180&& angle > 135 || angle >-180 && angle <-135 )
{
moveFlag = 3;
transform.position = new Vector3(Input.mousePosition.x, transform.position.y, transform.position.z);
if (Mathf.Abs(transform.position.x - beginPos.x) > 20f)
{
transform.position = new Vector3(beginPos.x - 20f, transform.position.y, transform.position.z);
}
}
//右移
else if (angle <45 && angle > -45 )
{
moveFlag = 4;
transform.position = new Vector3(Input.mousePosition.x, transform.position.y, transform.position.z);
if (Mathf.Abs(transform.position.x - beginPos.x) > 20f)
{
transform.position = new Vector3(beginPos.x + 20f, transform.position.y, transform.position.z);
}
}
transform.DOScale(new Vector3(1.2f,1.2f,1.2f), 0.1f);
}
public void OnEndDrag(PointerEventData eventData)
{
//放下的时候进行条件判断,看是否满足消除条件,满足放下,不满足不放下
Exchange();
transform.DOScale(new Vector3(1f, 1f, 1f), 0.3f);
}
这里比较重要的是对交换的判断,在开始拖拽的时候先获取鼠标的坐标,然后在进行拖拽的时候,进行相应的趋势判断,而不是单纯的拖拽。通过鼠标向量角度的计算,我们可以判断整体我们最后拖拽的趋势,这样当我们拖拽完成后,就可以实现让物体向我们拖拽方向的地方进行移动。同时拖拽的时候记得设置物体的raycastTarget值和 transform.SetAsLastSibling(),这样在拖拽的时候,物体就不会进行射线检测,同时物体会移到最上层,不会出现在移动的过程中去移动其他物体,其他物体会动的情况
相关关键方法
private bool IsFriend(ZYCell cellBegin, ZYCell cellEnd)
{
return (cellBegin.localPosition.x == cellEnd.localPosition.x && Mathf.Abs(cellBegin.localPosition.y -cellEnd.localPosition.y) == 1) || (cellBegin.localPosition.y== cellEnd.localPosition.y && Mathf.Abs(cellBegin.localPosition.x -cellEnd.localPosition.x) == 1);
}
//计算鼠标点和x轴的夹角,(45,135) 上,(-135,-45)下,(135,180)和(-180,-135)左,(-45,45)右
public float Diraction(Vector3 beginMouse,Vector3 endMouse)
{
Vector3 dir = Vector3.Normalize(endMouse - beginMouse);
Vector3 normalDir = new Vector3(1,0,0);
dir = dir - Vector3.Project(dir, Vector3.forward);
normalDir = normalDir - Vector3.Project(normalDir, Vector3.up);
Vector3 cross = Vector3.Cross(dir, normalDir);
float angle = Vector3.Angle(dir,normalDir);
return cross.z > 0 ? -angle : angle;
}
public void Exchange()
{
//根据趋势来判断是否交换,拖到屏幕外的话就不交换
switch (moveFlag)
{
case 1:
if (gameObject.GetComponent<ZYCell>().localPosition.x >0)
{
moveObj = ListCtr.objStore[new Vector2(gameObject.GetComponent<ZYCell>().localPosition.x - 1f, gameObject.GetComponent<ZYCell>().localPosition.y)];
}
else
{
gameObject.GetComponent<ZYCell>().MoveBack();
}
break;
case 2:
if(gameObject.GetComponent<ZYCell>().localPosition.x < ConstClass.Row)
{
moveObj = ListCtr.objStore[new Vector2(gameObject.GetComponent<ZYCell>().localPosition.x+1f, gameObject.GetComponent<ZYCell>().localPosition.y)];
}
else
{
gameObject.GetComponent<ZYCell>().MoveBack();
}
break;
case 3:
if (gameObject.GetComponent<ZYCell>().localPosition.y > 0)
{
moveObj = ListCtr.objStore[new Vector2(gameObject.GetComponent<ZYCell>().localPosition.x, gameObject.GetComponent<ZYCell>().localPosition.y - 1)];
}
else
{
gameObject.GetComponent<ZYCell>().MoveBack();
}
break;
case 4:
if (gameObject.GetComponent<ZYCell>().localPosition.y < ConstClass.Column)
{
moveObj = ListCtr.objStore[new Vector2(gameObject.GetComponent<ZYCell>().localPosition.x, gameObject.GetComponent<ZYCell>().localPosition.y + 1)];
}
else
{
gameObject.GetComponent<ZYCell>().MoveBack();
}
break;
}
if (moveObj != null)
{
DoMove(moveObj);
}
}
//交换数据并消除
public void DoMove(GameObject drag)
{
MatchItem match_1;
MatchItem match_2;
List<GameObject> finishList=new List<GameObject>();
//交换位置
Vector3 pos = drag.transform.position;
drag.GetComponent<RawImage>().raycastTarget = false;
//先交换两者内部数据,不交换位置
LocalDataExchange(gameObject.GetComponent<ZYCell>(),drag.GetComponent<ZYCell>());
//判断是否可以消除
match_1 = ListCtr.Ins.MatchItems(gameObject, gameObject.GetComponent<ZYCell>().localPosition);
if (match_1.finish != null)
{
finishList.AddRange(match_1.finish);
}
match_2 = ListCtr.Ins.MatchItems(drag, drag.GetComponent<ZYCell>().localPosition);
if (match_2.finish!=null)
{
finishList.AddRange(match_2.finish);
}
//如果可以消除交换位置并执行消除逻辑
if (match_1.isDelet || match_2.isDelet)
{
gameObject.GetComponent<ZYCell>().MoveBack();
drag.GetComponent<ZYCell>().MoveBack();
foreach (var item in finishList)
{
//如果里面有炸弹
if (item.GetComponent<ZYCell>().boomFlag == true)
{
for (int i = 0; i <= ConstClass.Row; i++)
{
for (int j = 0; j <= ConstClass.Column; j++)
{
if (ListCtr.objStore[new Vector2(i, j)].GetComponent<ZYCell>().localPosition.x == item.GetComponent<ZYCell>().localPosition.x || ListCtr.objStore[new Vector2(i, j)].GetComponent<ZYCell>().localPosition.y == item.GetComponent<ZYCell>().localPosition.y)
{
ListCtr.objStore[new Vector2(i, j)].transform.DOScale(new Vector3(0f, 0f, 0f), 0.1f);
ListCtr.objStore[new Vector2(i, j)].GetComponent<RawImage>().color = Color.black;
ListCtr.objStore[new Vector2(i, j)].GetComponent<ZYCell>().localTexture = null;
ListCtr.objStore[new Vector2(i, j)].transform.SetAsFirstSibling();
}
}
}
item.GetComponent<ZYCell>().boomFlag = false;
item.transform.DOScale(new Vector3(1, 1, 1), 0.3f);
}
else
{
item.transform.transform.DOScale(new Vector3(0f, 0f, 0f), 0.1f);
item.GetComponent<RawImage>().color = Color.black;
item.GetComponent<ZYCell>().localTexture = null;
item.transform.SetAsFirstSibling();
}
}
ConstClass.count += finishList.Count;
ConstClass.step--;
finishList.Clear();
ListCtr.Ins.Drop();
}
//否则把内部数据交换回来并回到原来的位置
else
{
LocalDataExchange(gameObject.GetComponent<ZYCell>(), drag.GetComponent<ZYCell>());
gameObject.GetComponent<ZYCell>().MoveBack();
drag.GetComponent<ZYCell>().MoveBack();
}
}
public void LocalDataExchange(ZYCell disShow, ZYCell show)
{
//个体维护
Vector2 vector_a = disShow.localPosition;
Vector2 vector_b = show.localPosition;
disShow.localPosition = vector_b;
show.localPosition = vector_a;
Vector3 tra_a = disShow.localPrePo;
Vector3 tra_b = show.localPrePo;
disShow.localPrePo = tra_b;
show.localPrePo = tra_a;
//维护字典:
ListCtr.objStore[disShow.localPosition] = disShow.gameObject;
ListCtr.objStore[show.localPosition] = show.gameObject;
}
代码会有些复杂,其实用字典存储可能不是更好的方法,因为寻找的时候整个代码巨长,根据大佬提示最好使用二维数组来进行整体的存储,会让代码简洁很多。