Unity 一笔画的玩法实现
文章目录
前言
策划在游戏里的一个关卡采用一笔画类似的玩法,我在调查发现关于一笔画的玩法在网上很少。
一笔画有很多实现方法,以下这种方法是我自己的一个实现方法。
目前这个交互方式是点击每个点来连线(策划需求),而要想拖动连线的话可以使用IDragHandler的其他接口来实现。
一、分解一笔画玩法
玩法:通过存在的 “线” 通道把所有的 “点” 都连起来。
首先,结构是多个点和线相连的几何图;
“线”:只能通过一次的通道。
“点”:是各通道的连接处,也是通关的要素之一。
举例图:
注意点:
1.在连到的最新“点”判断是否存在没连过的 “线”;
2.连过的“点”虽然可以连,但是是只会经过 “线”通道;
3.每次连一个“点”要判断是否所有的“点”和 “线”都被连接;
4.会使用到 LineRenderer 组件。
二、代码
1.“端口”:Port(每两个点相同端口连接起来就是“线”)
每个点都有一或多个端口,这个端口只能跟别的有相同端口号的相连
/// /// 端口属性 /// [Serializable] public class Port { public int portNum; //端口号 public bool isConnected; //是否被连接 }
2.“点”:Point
含有端口类
变量:
1.暗亮点素材是Ui层为了标明显示出点是否被连接过
2.ports管理该点的所有端口
3.samePort 存储两点间的相同端口号
using System;using System.Collections.Generic;using System.Reflection;using UnityEngine;using UnityEngine.EventSystems;using UnityEngine.UI;public class Point : MonoBehaviour, IPointerDownHandler{ [Header("暗点素材")] public Sprite closeSprite; [Header("亮点素材")] public Sprite openSprite; public List<Port> ports; //存储点中所有端口数据 private int samePort; //存储两点间的相同端口号 /// /// 端口属性 /// [Serializable] public class Port { public int portNum; //端口号 public bool isConnected; //是否被连接 } /// 重置点数据 public void ResetPort() { DimThePoint(); samePort = 0; foreach (var port in ports) { port.isConnected = false; } } /// /// 每个点被点击的时候 /// /// public void OnPointerDown(PointerEventData eventData) { Debug.Log("OnPointerDown: " + gameObject.name); //先判断是否可以为mainPoint并点亮point if (transform.parent.gameObject.GetComponent<OneStrokeDraw>().mainPoint == null) { var oneStrokeDraw = transform.parent.gameObject.GetComponent<OneStrokeDraw>(); oneStrokeDraw.mainPoint = this.gameObject; LightenThePoint(); //划线操作 oneStrokeDraw.LengthOfLineRenderer++; oneStrokeDraw.line.SetVertexCount(oneStrokeDraw.LengthOfLineRenderer); oneStrokeDraw.line.SetPosition(0, gameObject.transform.localPosition); } else if (transform.parent.gameObject.GetComponent<OneStrokeDraw>().mainPoint != this.gameObject) { var mainPoint = transform.parent.gameObject.GetComponent<OneStrokeDraw>().mainPoint; Debug.Log(eventData.pointerEnter.gameObject.name); if (CanTwoPointsBeConnected( mainPoint.GetComponent<Point>(), eventData.pointerEnter.gameObject.GetComponent<Point>(), out samePort)) { mainPoint.GetComponent<Point>() .ChangePortIsConnected(samePort); eventData.pointerEnter.gameObject.GetComponent<Point>().ChangePortIsConnected(samePort); Debug.Log(mainPoint.name + " 与 " + eventData.pointerEnter.gameObject.name + " 相连"); var oneStrokeDraw = transform.parent.gameObject.GetComponent<OneStrokeDraw>(); oneStrokeDraw.nowNumInIsConnected += 2;//记录已连接的端口数 //传递主Point换下一个点继续判断 oneStrokeDraw.mainPoint = eventData.pointerEnter.gameObject; eventData.pointerEnter.gameObject.GetComponent<Point>().LightenThePoint(); //划线操作 //绘制两点间划线 //设置线段的端点数 oneStrokeDraw.LengthOfLineRenderer++; oneStrokeDraw.line.SetVertexCount(oneStrokeDraw.LengthOfLineRenderer); int drawPosition = oneStrokeDraw.LengthOfLineRenderer - 1; oneStrokeDraw.line.SetPosition(drawPosition, gameObject.transform.localPosition); //通关的判断 if (oneStrokeDraw.CheckAllPointsIsConnected()) { //TODO 通关处理 Debug.Log("成功"); } } } } /// 检查相连的两个点是否可以连接 public bool CanTwoPointsBeConnected(Point point1, Point point2, out int samePort) { foreach (var port1 in point1.ports) { //若两个点存在相同端口号 if (point2.ports.Exists(port => port.portNum == port1.portNum)) { if (!port1.isConnected) //并且还没被连接(唯一性,一般相同端口号相同状态) { samePort = port1.portNum; return true; //则这个端口可以连接 } } } //不能相连的情况处理 samePort = 0; return false; } /// 使该点变亮点 public void LightenThePoint() { this.GetComponent<Image>().sprite = openSprite; } /// 使该点变暗点 public void DimThePoint() { this.GetComponent<Image>().sprite = closeSprite; } /// /// 连接点中的端口 /// /// 端口号 public void ChangePortIsConnected(int portNum) { var portHash = ports.Find(port => port.portNum == portNum); portHash.isConnected = true; }}
3.OneStrokeDraw(一笔画:点线管理器)
管理点线及总和的变量,组件LineRenderer,并判断通关条件以及重置方法
变量
1.points 存储所有点数据
2.line 挂载LineRenderer组件
3.isConnectedInSum 端口总数
4.LengthOfLineRenderer 端点个数 (LineRenderer划线用)
5.mainPoint 主节点(当前连到的,要判断的点)
6.nowNumInIsConnected 当前已连接端口数
using System;using System.Collections.Generic;using UnityEngine;using UnityEngine.EventSystems;public class OneStrokeDraw : MonoBehaviour{ public List<Point> points; //存储所有点数据 public LineRenderer line; private int isConnectedInSum; //端口总数 private LengthOfLineRenderer = 1; private GameObject mainPoint; private int nowNumInIsConnected; //当前已连接端口数 private void Start() { isConnectedInSum = CountIsConnectedInSum(); //记录端口总数 } /// 计算端口总数 private int CountIsConnectedInSum() { int isConnectedNum = 0; foreach (var point in points) { isConnectedNum += point.ports.Count; } return isConnectedNum; } /// 检查所有点是否都完成连接 (每次连接的时候都会判断) public bool CheckAllPointsIsConnected() { return isConnectedInSum == nowNumInIsConnected; //遍历每个点耗性能,这是优化的方案 } /// UI层:重置所有点数据 public void ResetAllPoint() { foreach (var point in points) { point.ResetPort(); } LengthOfLineRenderer = 0; line.SetVertexCount(LengthOfLineRenderer); //设置线段的端点数 // line.SetPosition(0, new Vector3(0, 0, 0)); mainPoint = null; nowNumInIsConnected = 0; //取消所有划线 }}
总结
以上就是所有要讲的内容,本文仅仅介绍了一笔画的大致实现,目前这个交互方式是点击每个点来连线,而要想拖动连线的话可以使用IDragHandler的其他接口来实现。
要善于分解然后考虑每个要素的特点以及实现,这个是要我们的观察力以及想法构造,不能只靠学,得自己多动手。
感谢观看到这里,祝你我在学习路上更上一层楼!!!