转自https://www.imooc.com/learn/636
该教程为视频版,动手实践了一下然后复习一下
一、前期准备
unity3d不用说了 我感觉各个版本差别不是太大
棋盘的图片素材
黑子和白子的图片素材
新建工程(2d)
新建文件夹导入图片素材 多选
在Inspector窗口中取消Generate Physics Shape Filter Mope选择Ponit(点过滤/无过滤器)
Inspector窗口详情可见 https://blog.csdn.net/u012632851/article/details/75063748
二、显示棋盘
创建图片组件 GameObject - UI - Image(或者直接在Hierarchy窗口右键) Image的名字更改为Board
将棋盘的图片拖进Source Image 同时调整图片的尺寸为560*560(实际证明不调整大小 后面会出问题 而且不同的图片 后面的算法要自行调整)
点击Canvas
Canvas-Render Mode 调整摄像机 Screen Space - Camera 并选择Main Camera
Canvas-Render Mode 详见https://blog.csdn.net/fdyshlk/article/details/78509909
Canvas Scale (详见https://www.cnblogs.com/morning-lee/p/7135782.html)
UI Scale Mode 选择 Scale with Screen Size 根据屏幕大小定标(根据载体的分辨率来布局,会随屏幕分辨率的变化而变化。)
Reference Resolution(参考分辨率)调整为常见的1280*720
Screen Match Mode(屏幕匹配模式) 按height匹配 即拉到最右
最后调整board的坐标 PosX PosY 即可在Scene窗口看到棋盘
三、交叉点
让每一个交叉点都被设置好为一个button 点击即放子
实际效果如图所示 棋盘被15*15个button布满 点击交叉点会有反应
具体做法
首先创建一个button GameObject-UI-button
Source Image设置none 颜色设置红色半透明(或者其他你喜欢的 都是为了测试)
button大小设置为40*40 棋盘一个格子的大小
接下来新建一个脚本 Cross 这个脚本用来存放每一个交叉点的坐标(GridX,GridY)
GetCompoment <T>()从当前游戏对象获取组件T,只在当前游戏对象中获取,没得到的就返回null,不会去子物体中去寻找。
给button添加一个点击事件 使用Lambda表达式 (Lambda表达式详解 https://www.jianshu.com/p/e033cb93d99d)
点击事件的后续代码 后面再说
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class Cross : MonoBehaviour { //交叉点的坐标 public int GridX; public int GridY; public MainLoop mainLoop; // Use this for initialization void Start() { GetComponent<Button>().onClick.AddListener(() => { mainLoop.OnClick(this); }); } }
脚本写好拖拽到Hieraichy窗口上的button,把button改名cross制作成一个prefab(拖拽到Project窗口即可),然后delete掉Hieraichy窗口的button
现在一个交叉点制作 然后需要在整个棋盘上铺满所有的交叉点
新建一个脚本 ChessBoard (视频里用的是Board)
这个脚本的关键是 把Cross动态的铺满
关键代码
pos.x = -halfSize + x * crossSize; pos.y = -halfSize + y * crossSize;
完整代码
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 6 //把Cross动态排列到棋盘上 7 public class ChessBoard : MonoBehaviour { 8 9 public GameObject crossPrefab; 10 11 12 const float crossSize = 40;//crossPrefab的大小 13 14 public const int crossCount = 15; //棋盘一行有15个交叉点 15 16 public const int size = 560; //棋盘大小 17 18 public const int halfSize = size / 2; //棋盘大小的一半 19 20 Dictionary<int,Cross> _crossMap = new Dictionary<int, Cross>(); //存储每个交叉点按钮的信息 21 22 static int MakeKey(int x,int y) 23 { 24 return x * 10000 + y; 25 } 26 27 public void Reset() 28 { 29 30 //删掉board下所有子物体 31 foreach (Transform child in gameObject.transform) 32 { 33 GameObject.Destroy(child.gameObject); 34 } 35 36 var mainLoop = GetComponent<MainLoop>(); 37 38 _crossMap.Clear(); 39 40 for(int x = 0; x < crossCount; x++) 41 { 42 for(int y = 0; y < crossCount; y++) 43 { 44 //初始化prefab 45 var crossObject = GameObject.Instantiate<GameObject>(crossPrefab); 46 47 // 归属于本层对象下 48 crossObject.transform.SetParent(gameObject.transform); 49 50 // 复位缩放 51 crossObject.transform.localScale = Vector3.one; 52 53 //设置位置 54 var pos = crossObject.transform.localPosition; 55 pos.x = -halfSize + x * crossSize; 56 pos.y = -halfSize + y * crossSize; 57 pos.z = 1; 58 crossObject.transform.localPosition = pos; 59 60 //记录信息 61 var cross = crossObject.GetComponent<Cross>(); 62 cross.GridX = x; 63 cross.GridY = y; 64 cross.mainLoop = mainLoop; 65 _crossMap.Add(MakeKey(x, y), cross); 66 67 } 68 } 69 } 70 //取出Cross 71 public Cross GetCross(int x,int y) 72 { 73 Cross cross; 74 if (_crossMap.TryGetValue(MakeKey(x, y), out cross)) 75 { 76 return cross; 77 } 78 return null; 79 80 } 81 82 // Use this for initialization 83 void Start () { 84 Reset(); 85 } 86 87 // Update is called once per frame 88 void Update () { 89 90 } 91 }
然后将脚本拖拽到Hieraichy窗口的棋盘下
(Mainloop脚本后面会说)