> 文档中心 > Unity 一笔画的玩法实现

Unity 一笔画的玩法实现

文章目录

  • 前言
  • 一、分解一笔画玩法
  • 二、代码
    • 1.“端口”:Port(每两个点相同端口连接起来就是“线”)
    • 2.“点”:Point
    • 3.OneStrokeDraw(一笔画:点线管理器)
  • 总结

前言

策划在游戏里的一个关卡采用一笔画类似的玩法,我在调查发现关于一笔画的玩法在网上很少。
一笔画有很多实现方法,以下这种方法是我自己的一个实现方法。
目前这个交互方式是点击每个点来连线(策划需求),而要想拖动连线的话可以使用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的其他接口来实现。
要善于分解然后考虑每个要素的特点以及实现,这个是要我们的观察力以及想法构造,不能只靠学,得自己多动手。
感谢观看到这里,祝你我在学习路上更上一层楼!!!