Unity home system --- building interaction

During the internship, I was asked to try the front-end development and implementation of the home system. The current progress is as follows:

TMX (XML) parsing, creation of point maps, editing of buildings.

TMXtxt is opened in XML format. Xml is a typical tree structure. To parse xml, you can use the xml class method that comes with C#. The process of parsing is to traverse the depth of the tree and then intercept the key information. There are a lot of articles on class methods, you can take a look, there is even a plug-in like superTiled2unity, but the 2017 version has a problem with parsing it.

The parsed data is generally in the form of a two-dimensional array, and it is sufficient to generate a bitmap with pictures based on the array information.


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;
			    }
		    }
			
		}
	}
	

}

We can generate a point map roughly as follows, each point has a collider, and gridCell class



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;
	}
}

edit method

Then add methods in mouseManager and UImanager, and the UI of the operation panel

Idea MouseManager manages mouse click events and passes parameters to UImanager to open the edit building panel in the ui.

Difficulties, buildings collide with multiple points,

The collider of the building is too large and will touch multiple points at once, which is not the effect we want, so we give the building double collider

One big and one small, when dragging, switch to a small collider to avoid multiple collisions

 

 

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);
	}
}

The adsorption effect is as follows

 

 There are still two BUGs that have not been perfected,

1. The ground method is to control the color conversion through the methods of ontriggerenter and exit. When the OK button in the UI is clicked, it will be terminated directly

After the editing operation, the color of the foothold point under the foot after the operation is completed is still the green color when it was triggered.

Solution idea : Join the editorial manager at that time to do overall management and finishing work.

2. The editing effect of dragging and snapping is not smooth enough. If the point is too small, sometimes the color turns green and the snapping point is not updated. The double collider size is still not the optimal solution.

The solution is to cancel the double collider, cancel the collision method in the cell, analyze the collider in the MouseManager, and change the color of the patch if you click on the patch.

! ! But there is still a problem, the mouse still cannot be restored after leaving. Maybe you can try the double-pointer idea and use a slow pointer to sweep the tail?

Noteworthy points in the system,

1. The current main project tells me that for the production of large-scale systems, the method of passing references and opening by manager is the method. I tried it in the above-mentioned system, and carried out a single principle and decoupling, but I feel that if the system is larger, will the manger be too much? complex. Not sure if this is industry standard practice.

2. Both Ontrriger and OnCollsion methods require the component rigidbady

Guess you like

Origin blog.csdn.net/qq_53211468/article/details/127537133