制作小地图,先添加一个Camera专门用来显示地图,设为正交相机,然后有两种制作方法。

直接使用地图相机

调整小地图Camera的Viewport Rect,比如设x为0.75,y为-0.75,让小地图位于右下角。采用这种方式,通过修改Camera的Depth,小地图相机显示区域会覆盖在最上层,小地图相机可以通过代码直接修改transform.position来跟随人物运动。如果希望点击小地图时,获得对应在场景中点击的位置,可以用小地图Camera来发射屏幕射线。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
void DragCheck()
{
	if (MapCamera.pixelRect.Contains (Input.mousePosition)) {
		Ray ray = MapCamera.ScreenPointToRay (Input.mousePosition);
		RaycastHit hitInfo;
		if (Physics.Raycast (ray, out hitInfo, 100, BattleMain.Instance.PlaneLayerMask)) {
			Vector3 mapPosition = hitInfo.point;
			Ray cameraCenterRay = battleCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
			RaycastHit cameraView;
			Physics.Raycast(cameraCenterRay, out cameraView, Mathf.Infinity, BattleMain.Instance.PlaneLayerMask);
			Vector3 camViewCenter = cameraView.point;
			Vector3 camDestPos = mapPosition - camViewCenter;
			camDestPos.y = 0;
			battleCamera.transform.position += camDestPos;
		}
	}
}

通过上面的代码,点击小地图,可以移动主相机到点击的位置。使用这种方式的缺点很明显,即小地图的形状是方形的,而且不好加其它元素在小地图上。 还有,如果需要一个动态UI跟随场景中物体,比如血条,那么会发现血条始终位于小地图上面。解决的办法是,把显示血条的Canvas的Render Mode改为Screen Space Camera,然后计算UI的位置。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void AddHPBarForTowers()
{
	Transform parentTransform;
	Transform child;

	GameObject HPBarObject = Instantiate (TowerHPBarPrefab) as GameObject;
	HPBarObject.transform.SetParent (HPBarParent, false);
	HPBar hp = HPBarObject.GetComponent<HPBar> ();
	hp.Target = child;
	hp.offset = new Vector3 (0, 3.4f, 0);
}

上面的代码用于动态添加血条Prefab到Canvas中,使用SetParent时需要添加额外第二个参数为false,可以保持原局部坐标和缩放。

1
2
3
4
5
6
void Update () {
	Vector2 pos = battleCamera.WorldToScreenPoint (Target.position + offset);
	pos.x -= battleCamera.pixelWidth* 0.5f;
	pos.y -= battleCamera.pixelHeight * 0.5f;
	GetComponent<RectTransform> ().anchoredPosition = pos;
}

上面的代码可以使Canvas中的血条位于人物顶部。如果主相机是正交相机,那么上面的代码需要改成下面的样子:

1
GetComponent<RectTransform>().anchoredPosition = pos/GetComponentInParent<Canvas>().scaleFactor;

使用 Render Texture

使用Render Texture,可以方便的制作圆形地图,但在小地图上点击后计算实际点击位置比较麻烦。即新建一个Render Texture,然后把小地图的Target Texture指向这张图片,小地图渲染的内容会显示在图片中,此时不需要修改Camera的Viewport Rect。然后,使用那张Render Texture,可以在Canvas中新建一个Raw Image来显示。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public Camera battleCamera; // 主透视相机
public Camera MapCamera; // 小地图正交相机
public GameObject MiniMap; // Canvas下的小地图组件,默认在右下角显示

void Update () {
	if (Input.GetMouseButtonDown(0)) 
	{

        Rect miniMapRect = MiniMap.GetComponent<RectTransform>().rect;
        Rect screenRect = new Rect(
            MiniMap.transform.position.x - miniMapRect.width,
            MiniMap.transform.position.y,
            miniMapRect.width, miniMapRect.height);

        if (screenRect.Contains(Input.mousePosition))
        {
            Vector3 mousePos = Input.mousePosition;
            mousePos.x -= screenRect.x;

            Vector3 mapClickPos = new Vector3(mousePos.x / screenRect.width, mousePos.y / screenRect.height);
            Ray portaledRay = MapCamera.ViewportPointToRay(mapClickPos);
            RaycastHit raycastHit;
			if (Physics.Raycast(portaledRay, out raycastHit, Mathf.Infinity, BattleMain.Instance.PlaneLayerMask))
            {
				Vector3 mapPos = raycastHit.point;

				Ray cameraCenterRay = battleCamera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
				RaycastHit hitInfo;
				Physics.Raycast(cameraCenterRay, out hitInfo, Mathf.Infinity, BattleMain.Instance.PlaneLayerMask);
				Vector3 camCenterPos = hitInfo.point;

				Vector3 camDestPos = mapPos - camCenterPos;
				camDestPos.y = 0;

				battleCamera.transform.position += camDestPos;
            }
        }

上面的代码用于点击小地图后,让主相机移动到点击的位置处。