文章目录
前言一、分解一笔画玩法二、代码1.“端口”:Port(每两个点相同端口连接起来就是“线”)2.“点”:Point3.OneStrokeDraw(一笔画:点线管理器)总结前言
策划在游戏里的一个关卡采用一笔画类似的玩法,我在调查发现关于一笔画的玩法在网上很少。
一笔画有很多实现方法,以下这种方法是我自己的一个实现方法。
目前这个交互方式是点击每个点来连线(策划需求),而要想拖动连线的话可以使用IDragHandler的其他接口来实现。
一、分解一笔画玩法
玩法:通过存在的 “线” 通道把所有的 “点” 都连起来。
首先,结构是多个点和线相连的几何图; “线”:只能通过一次的通道。 “点”:是各通道的连接处,也是通关的要素之一。
举例图:
注意点: 1.在连到的最新“点”判断是否存在没连过的 “线”; 2.连过的“点”虽然可以连,但是是只会经过 “线”通道; 3.每次连一个“点”要判断是否所有的“点”和 “线”都被连接; 4.会使用到 LineRenderer 组件。
二、代码
1.“端口”:Port(每两个点相同端口连接起来就是“线”)
每个点都有一或多个端口,这个端口只能跟别的有相同端口号的相连
/// <summary>/// 端口属性/// </summary>[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; //存储两点间的相同端口号/// <summary>/// 端口属性/// </summary>[Serializable]public class Port{public int portNum; //端口号public bool isConnected; //是否被连接}/// <summary> 重置点数据 </summary>public void ResetPort(){DimThePoint();samePort = 0;foreach (var port in ports){port.isConnected = false;}}/// <summary>/// 每个点被点击的时候/// </summary>/// <param name="eventData"></param>public void OnPointerDown(PointerEventData eventData){Debug.Log("OnPointerDown: " + gameObject.name);//先判断是否可以为mainPoint并点亮pointif (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("成功");}}}}/// <summary> 检查相连的两个点是否可以连接 </summary>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;}/// <summary> 使该点变亮点 </summary>public void LightenThePoint(){this.GetComponent<Image>().sprite = openSprite;}/// <summary> 使该点变暗点 </summary>public void DimThePoint(){this.GetComponent<Image>().sprite = closeSprite;}/// <summary>/// 连接点中的端口/// </summary>/// <param name="portNum">端口号</param>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(); //记录端口总数}/// <summary> 计算端口总数 </summary>private int CountIsConnectedInSum(){int isConnectedNum = 0;foreach (var point in points){isConnectedNum += point.ports.Count;}return isConnectedNum;}/// <summary> 检查所有点是否都完成连接 (每次连接的时候都会判断) </summary>public bool CheckAllPointsIsConnected(){return isConnectedInSum == nowNumInIsConnected; //遍历每个点耗性能,这是优化的方案}/// <summary> UI层:重置所有点数据 </summary>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的其他接口来实现。
要善于分解然后考虑每个要素的特点以及实现,这个是要我们的观察力以及想法构造,不能只靠学,得自己多动手。
感谢观看到这里,祝你我在学习路上更上一层楼!!!