首先看看效果图
拼图完成后,会显示game over
来看看工程结构图
Canvas:画布
kanpask:背包
cell 格子,每个格子上面放一个分割的图片
food就是要拖动的图片
这里cell-food创建一个预设体
准备一个图片。分割成精灵
kanpask:组建
因为这里是5x5的格子,表格布局(Grid Layout Group)x:100 y:100,spacing:x=1 y=1
所以款和高分别是504
food添加组建,来控制是否启用射线
创建createImge.cs脚本挂载在kanpask上
createImge.cs脚本
1 using UnityEngine; 2 using System.Collections; 3 using UnityEngine.UI; 4 5 /// <summary> 6 /// 创建图片,打乱图片排序。然后显示在格子里面 7 /// </summary> 8 public class createImge : MonoBehaviour 9 { 10 11 public Sprite[] sprite; //要显示的图片精灵 12 public GameObject imgPrefab;//生产格子的预设体,这里是父子关系 cell-food 13 14 GameObject[] cells; //保存当前生产的图片精灵,为了拼图后的比较 15 16 public static createImge instance; //单列 17 18 void Awake() 19 { 20 instance = this; //单列脚本 21 } 22 23 // Use this for initialization 24 void Start() 25 { 26 //随机排序图片 , 27 for (int i = 0; i < sprite.Length; i++) 28 { 29 int index = Random.Range(i, sprite.Length); 30 Sprite temp = sprite[i]; 31 sprite[i] = sprite[index]; 32 sprite[index] = temp; 33 } 34 cells = new GameObject[sprite.Length]; 35 //开始生成对象,并显示在场景 36 for (int i = 0; i < sprite.Length; i++) 37 { 38 //GameObject o = Instantiate(imgPrefab) as GameObject; 39 cells[i] = Instantiate(imgPrefab) as GameObject; 40 41 cells[i].name = "exceed_" + i.ToString(); 42 43 cells[i].transform.GetChild(0).GetComponent<Image>().sprite = sprite[i]; 44 cells[i].transform.SetParent(transform); 45 //因为是给子对象赋值,所以先找到第一个子对象GetChild(0),然后找到Image组建赋值精灵 46 cells[i].transform.GetChild(0).GetComponent<Image>().sprite = sprite[i]; 47 //设置当前对象的父对象 48 cells[i].transform.SetParent(transform); 49 //为了保证生成的对象没有缩放模式,写Vector3(1, 1, 1)的简码。 50 cells[i].transform.localScale = Vector3.one; 51 } 52 } 53 54 // Update is called once per frame 55 void Update() 56 { 57 58 } 59 /// <summary> 60 /// 判断是否已经拼图成功 61 /// </summary> 62 /// <returns></returns> 63 public bool IsFinsid() 64 { 65 Sprite food; 66 foreach (GameObject cell in cells) 67 { 68 //笔记父物体和子物体名子是否相等 69 food = cell.transform.GetChild(0).GetComponent<Image>().sprite; 70 if (cell.name != food.name) 71 { 72 return false; 73 } 74 } 75 return true; 76 } 77 }
运行游戏看看层次图
红色标记的一个预设体。没用的
接下来是看拖拽代码了
创建createDrag.cs挂载在food上面
createDrag.脚本
1 using UnityEngine; 2 using System.Collections; 3 using UnityEngine.UI; 4 using UnityEngine.EventSystems; 5 public class createDrag : MonoBehaviour 6 , IBeginDragHandler, IDragHandler, IEndDragHandler 7 { 8 /* 9 拖拽原理:是有很多格子(cell),cell里面有拖动的对象,cell可以做背景图片 10 * 1:程序运行要找到当前物体(即拖动的对象)的位置坐标,也需要临时用了当父物体容器的对象(这样避免遮挡效果),找到被拖动物体的CanvasGroup(CanvasGroup 包含blocksRaycasts属性 如果开启则可以设置是否射线检测到(才能执行相应的事件)) 11 * 2:拖拽开始,记录拖拽前物体的坐标,并设置当前物体为临时容器的子对象,并取消被拖拽物体的射线检测, 12 * 3:获取拖到目标点上的对象。跟当前拖动前的位置交换即可 13 */ 14 15 //自己的RectTransform 16 RectTransform rf; 17 //Vector3 oldPosition;//原来的位置,拖拽前的位置 18 Vector3 newPosition;//拖拽中的位置 19 20 //画布的RectTransform,开始拖拽的时候设它为父物体,避免遮挡效果,如果图片不在Canves中则会被挡住 21 RectTransform knapsackRF; 22 //原来的格子的RectTransform 23 RectTransform cellRF; 24 25 CanvasGroup cg; 26 27 bool isDrag; //是否开始拖拽 28 29 GameObject enterGameObject; 30 31 32 //查找到对象 33 void Awake() 34 { 35 rf = GetComponent<RectTransform>(); 36 knapsackRF = GameObject.FindWithTag("kanpask").GetComponent<RectTransform>(); 37 cg = GetComponent<CanvasGroup>(); //CanvasGroup 包含blocksRaycasts属性 如果开启则可以设置是否射线检测到(才能执行相应的事件) 38 } 39 40 41 /// <summary> 42 /// 开始拖拽 43 /// </summary> 44 /// <param name="eventData"></param> 45 public void OnBeginDrag(PointerEventData eventData) 46 { 47 //oldPosition = rf.position; 48 49 //每次开始拖拽前记录它的原始父物体 50 cellRF = rf.parent.GetComponent<RectTransform>(); 51 //开始拖拽的时候,设置当前的父物体 注意顺序,必须先获取在设置父物体, 52 rf.SetParent(knapsackRF); 53 // 开始拖拽后不能被射线检测到 54 /* 55 因为事件都是靠射线检测的。当拖动图片到另外一张图片上的时候, 56 * 从鼠标发出的射线就会执行当前被拖动的物体。射线就停止了(因为射线碰到物体就会停止),这样射线就不会触碰到下面那个图片 57 * 也就获取不到要放置物体位置的信息了。 58 */ 59 cg.blocksRaycasts = false; 60 isDrag = true; 61 } 62 /// <summary> 63 /// 拖拽中 64 /// </summary> 65 /// <param name="eventData"></param> 66 public void OnDrag(PointerEventData eventData) 67 { 68 if (isDrag) //必须要执行了OnBeginDrag才执行OnDrag 有时候会遇到不执行OnBeginDrag 69 { 70 // 通过屏幕中的鼠标点,获取在父节点中的鼠标点 71 RectTransformUtility.ScreenPointToWorldPointInRectangle(rf, eventData.position, eventData.enterEventCamera, out newPosition); 72 rf.position = newPosition; //设置拖动的图片的位置 73 //print(newPosition); 74 } 75 } 76 77 /// <summary> 78 /// 结束拖拽 79 /// </summary> 80 /// <param name="eventData"></param> 81 public void OnEndDrag(PointerEventData eventData) 82 { 83 if (isDrag) // 84 { 85 enterGameObject = eventData.pointerEnter;//获取当前点上的对象(这样也 是根据射线检测的),也就是拖拽的物体放到了那个物体上面 86 87 //如果拖拽到空的地方 88 if (enterGameObject == null) 89 { 90 MySetParent(rf, cellRF); 91 } 92 else //如果非空 93 { 94 //cell--food是父子关系,坐标相同。所以food会把cell覆盖。UGUI是这样的 95 96 switch (enterGameObject.tag) 97 { 98 case "cell": 99 MySetParent(rf, enterGameObject.transform); //如果是格子,即格子上没有图片 是后面的白板 100 break; 101 case "food": //即格子上有图片 102 MySetParent(rf, enterGameObject.transform.parent); //把当前拖动的图片放到指定位置 103 MySetParent(enterGameObject.transform, cellRF); //把当前的图片放大我拖动图片的位置 ,即我拖动图片要放的位置 。这个位置的图片放到被拖动来之前的位置 ,就是交换位置 104 break; 105 default: 106 MySetParent(rf, cellRF); 107 break; 108 } 109 } 110 //结束拖拽后可以被射线检测到 111 cg.blocksRaycasts = true; 112 isDrag = false; 113 } 114 //每次拖拽结束判断是否拼图完成 115 if (createImge.instance.IsFinsid()) 116 { 117 print("game over"); 118 } 119 } 120 //建立父子关系的方法 121 void MySetParent(Transform son, Transform parent) 122 { 123 son.SetParent(parent); //设置父子关系 124 son.localPosition = Vector3.zero;//设置坐标为0点基于父物体 125 //或者 126 //son.localPosition = Vector3.one; 127 } 128 }
时间: 2024-10-10 17:16:26