实习期间要求让我尝试一下家园系统的前端开发实现。目前做的进度如下:

TMX(XML)解析,创造点图,编辑建筑。

TMXtxt打开就是XML格式,Xml是典型的树形结构,解析xml可以用C#自带的xml类的类方法,解析的过程也就是,树的深度遍历,然后截取关健信息就行了。类方法文章很多,可以瞧瞧,甚至有superTiled2unity这种插件,不过2017版本解析出来有点问题。

解析出的数据一般都是二维数组的形式,根据数组信息生成附带图片的位图就可以了。

using System.Collections.Generic;
using UnityEngine;

[ExecuteInEditMode]
public class CreateMap : MonoBehaviour
{
	private List<List<int>> bitmap;
	public  Texture2D tex;
	private int row = 10;
	private int column = 10;
	private float height = 1 ;//菱形内宽
	private float length = 1 ;//菱形内高
	public Vector3 originalPos;
	

	//public GameObject pos;
	// Use this for initialization
	private void Awake()
	{
		originalPos = this.transform.position;
	}

	void Start () {
		if(this.transform.childCount==0)
		{
			for (int i = 0; i < row; ++i)
			{
				for (int j = 0; j < column; ++j)
			    {
				 GameObject go = new GameObject();
				 go.transform.parent = this.transform;
			    	go.transform.position =
					new Vector3(originalPos.x + j * length - i*length, originalPos.y + j * height+i*height, originalPos.z);
			    	go.name = "mapPos(" +  (i+1)  + ',' + (j +1)+ ')';//生成菱形的地图,每一个生成的地片以菱形两条对角线的长和高在x和y轴上做偏移。如果是生成六边形的地图,要对奇数列和偶数列分开做偏移操作,大致思路相同
			        //gird初始化
			        GridCell gridCell = go.AddComponent<GridCell>();//为地砖加上GridCell类型
			        gridCell.currentState = GridCell.GridType.Empty;//初始化为空
			        SpriteRenderer s = go.AddComponent<SpriteRenderer>();//加上精灵渲染器
			        s.sprite= Sprite.Create(tex,new Rect(0.0f,0.0f,tex.width,tex.height),new Vector2(0.5f,0.5f));
			        BoxCollider2D boxColl =  go.AddComponent<BoxCollider2D>();
			     //   boxColl.isTrigger = true;
			    }
		    }
			
		}
	}
	

}

我们可以生成一个大致如下的点图,每个点有collider,和girdCell类

using UnityEngine;
[ExecuteInEditMode]

public class GridCell : MonoBehaviour
{
	private SpriteRenderer _spriteRenderer;
	private bool change = false;
	public enum GridType//地片的状态 可建筑的(空的),已经建筑的,障碍物(不可交互),杂草(需要清理)
	{
		Empty=0,
		Construction=1,
		Barrier =2,
		Weed=3,
	}

	public GridType currentState;

	public GridType CurrentState
	{
		set
		{
			
		}
		get
		{
			return currentState;
		}
	}

	private void Awake()
	{
		_spriteRenderer = GetComponent<SpriteRenderer>();
	}

	private void Update()
	{
		if(change&&Input.GetMouseButton(0))
			colorchange();
	}

	private void OnTriggerEnter2D(Collider2D a)
	{
		if (a.CompareTag("construction"))
		{
			change = true;
		}
	}

	private void colorchange()//可放置时变颜色,提示
	{
		_spriteRenderer.color = new Color(0f, 1f, 0f, Mathf.Abs(Mathf.Sin(Time.time*3)));
	}

	private void OnTriggerExit2D(Collider2D other)
	{
		_spriteRenderer.color = Color.white;
		change = false;
	}
}

unity中使用xcharts图形插件绑定数据库动态数据 unity xt_unity

编辑方法

然后分别在mouseManager 和 UImanager中添加方法,以及操作面板的UI

思路 MouseManager 管理鼠标点击事件,传参给 UImanager 在打开ui中的编辑建筑面板。

难点,建筑多点碰撞,

建筑的collider太大 会一次性触碰多个点,这样不是我们想要的效果,所以我们给建筑双collider

一大一小,当拖拽时,就切换成小的collider,避免多碰撞

unity中使用xcharts图形插件绑定数据库动态数据 unity xt_c#_02

unity中使用xcharts图形插件绑定数据库动态数据 unity xt_ide_03

 

 

using UnityEngine;

public class UImanager : MonoBehaviour
{

	public static UImanager Instance; 
	public GameObject ConstructOperationPanel;
	
	// Use this for initialization
	private void Awake()
	{

		singletonMode();

		ConstructOperationPanel = this.transform.GetChild(0).gameObject;
	}

	void Start () {
		
		
		
	}
	
	
	// Update is called once per frame
	
	void Update () {
		
	}

	
	public void ConstructOperationOpen(GameObject go)//建筑操作面板打开
	{
		if(!ConstructOperationPanel.activeInHierarchy)
		{  ConstructOperationPanel.SetActive(true);
		   ConstructOperationPanel.GetComponent<ConstructionOperation>().construction = go;
		   ConstructOperationPanel.GetComponent<ConstructionOperation>().oripos = go.transform.position;}
	}

	public void ConstrucOperationClose()//建筑操作面板关闭暂时没用
	{
		ConstructOperationPanel.SetActive(false);
		ConstructOperationPanel.GetComponent<ConstructionOperation>().construction = null;
	}
	
	
	void singletonMode()//单简单例模式
	{
		if (Instance == null)
			Instance = this;
		else
		{
			Destroy(this);
		}
	}
}
using UnityEngine;

public class MouseManager : MonoBehaviour
{

	public static MouseManager Instance;
	public GameObject ConstructionGo;//正在操作的建筑
	private Camera mainCam;
	public Vector2 mousePoint;

	private void Awake()
	{
		if (Instance == null)
			Instance = this;
		else
		{
			Destroy(Instance);
		}
	}

	void Start()
	{

	}


	void Update()
	{
		OnMouseDragConstruction2D();

	}

	public Vector3 magneticPos;

	private void OnMouseDragConstruction2D() //鼠標拖拽建筑物体移动,要求设置tag为“construction”。
	{
		//TODO 拖拽物体移动会有一两帧延后。
		RaycastHit2D hit;
		if (Input.GetMouseButtonDown(0))
		{
			//	Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			if (hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition),
				    Vector2.zero)) //精灵检测方法 和 3D不相同。
			{
				if (hit.collider.CompareTag("construction")) //检测到手误写个分号完全不同,拿到
				{
					ConstructionGo = hit.collider.gameObject;

					UImanager.Instance.ConstructOperationOpen(ConstructionGo);//传值

					magneticPos = ConstructionGo.transform.position;

					BoxCollider2D[]  s2d=ConstructionGo.GetComponents<BoxCollider2D>();//切换物体的collider , 目的是避免碰撞体过大碰撞到多个坐标点,当选中物体时,切换为小一号的碰撞体。
					s2d[0].enabled = false;
					s2d[1].enabled = true;
				}
		
			}
		}
		else if (Input.GetMouseButton(0) && ConstructionGo)
		{
			//TODO 吸附效果
			//TODO 可放置地区绿色高亮。
			
			mousePoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
			ConstructionGo.transform.position =
				new Vector3(mousePoint.x, mousePoint.y-0.5f, ConstructionGo.transform.position.z);
			
			if ( hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero))//抓取到地片就跟新吸附点。
			{

				if ( hit.collider.gameObject.GetComponent<GridCell>().currentState == GridCell.GridType.Empty)
				{
					magneticPos = hit.transform.position;
				}
			}

		}
		
		else if (Input.GetMouseButtonUp(0)) 
		{
			if (ConstructionGo) //有就释放
			{
				ConstructionGo.transform.position = magneticPos;
				BoxCollider2D[]  s2d=ConstructionGo.GetComponents<BoxCollider2D>();
				s2d[0].enabled = true;
				s2d[1].enabled = false;
				ConstructionGo = null;
			}
		}

	}


	
	
	
}
using UnityEngine;
using UnityEngine.UI;

public class ConstructionOperation : MonoBehaviour
{
	public Button conf;
	public Button rev;
	public Button rot;
	public Button del;
	public GameObject construction;
	private Vector2 pos;
	private RectTransform rectTra;
	private Camera cam;

	public Vector3 oripos;

	//public Vector3 magneticPos;
	// Use this for initialization
	
	void Start ()
	{
		rectTra = this.GetComponent<RectTransform>();
		cam = Camera.main;
		conf.onClick.AddListener(Confirm);
		rev.onClick.AddListener(revacation);
		rot.onClick.AddListener(rotation);
		del.onClick.AddListener(delete);
	}



	// Update is called once per frame
	void Update ()
	{
		follow();
	}
  
	void follow()
	{
		if (construction)//如果抓取到了建筑,那么ui跟随建筑移动
		{
			
			pos = cam.WorldToScreenPoint(construction.transform.position);//从时间空间转换到屏幕空间
			rectTra.position = new Vector2(pos.x, pos.y-20f);//更新Rect Transfrom
		//	print(pos);
		//	print(rectTra.position);
		}
		else
		{
			return;
		}
	}

	void Confirm()
	{
		construction = null;
		this.gameObject.SetActive(false);
	}

	void revacation()//返回编辑器最初地点,而不是吸附点
	{
		construction.transform.position = oripos;
		construction = null;
		this.gameObject.SetActive(false);
	}

	void rotation()//2D的旋转可以通过更改UV。offset来实现偏移来实现,或者资源加载新的sprite,这里只做个简单反转示范
	{
		bool x = construction.GetComponent<SpriteRenderer>().flipX;
		if (x)
			construction.GetComponent<SpriteRenderer>().flipX = false;
		else
		{
			construction.GetComponent<SpriteRenderer>().flipX = true;
		}
	}

	void delete()
	{
		Destroy(construction);
		construction = null;
		this.gameObject.SetActive(false);
	}
}

吸附效果如下

unity中使用xcharts图形插件绑定数据库动态数据 unity xt_c#_04

 

unity中使用xcharts图形插件绑定数据库动态数据 unity xt_2d_05

 还有两个BUG没有完善,

1,地片方法是通过ontriggerenter和exit的方法来控制颜色转换,当点击ui中确定按钮是,直接终止

编辑操作,结束操作后脚下的落脚点颜色还是触发时的绿色。

解决思路:到时候加入编辑管理器到时候做统筹管理和扫尾工作。

2,拖拽吸附编辑效果不够丝滑,如果点太小有时候颜色变绿也没有更新吸附点,大小双collider感觉仍然不是最优解。

解决思路,取消双collider,取消cell中碰撞方法,在MouseManager中解析碰撞体,如果点到地片,改变地片颜色。

!!但是仍然有个问题,鼠标离开后仍然不能复原。或许可以尝试双指针思路用一个慢指针来扫尾?

系统中值得注意的点,

1,当前主程告诉我,对于大型系统的制作就是manager传值传引用和打开方法,在上述系统中进行了尝试,进行单一原则和解耦,但是感觉系统再大些,manger会不会过于庞杂。不知道这是否是业界标准做法。

2,Ontrriger, OnCollsion方法均需要组件 rigidbady