移动范围限制

有关正交摄像机的Size和实际渲染尺寸的关系:

https://atao-blast.github.io/2022/02/24/UnityBook/Unity-Book-Chapter6Part1/

在2D游戏中,只要我们设置的pixel per Unit是100,那么摄像机在世界坐标系下渲染的相对大小就能计算出来(Camera也提供了aspect属性)。

然后我们根据相机的RectTransform的位置和上面的相对大小,就能求得当前摄像机所渲染的世界坐标位置边界。然后根据这个边界限制飞机的飞行范围。

飞机本身的大小,可以根据SpriteRenderer提供的bound属性求得,所有继承了Renderer的组件都提供bound属性,可以计算对象的包围盒在世界空间中的位置,如果对象在世界空间中一直在运动,那么这个属性也是一直在变化的。

GameUtil

在里面提供获取当前摄像机视野边界的世界坐标的方法。

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
40
41
42
43
private static Vector2 _cameraSize = Vector2.zero;
public static Vector2 GetCameraSize()
{
if (_cameraSize == Vector2.zero)
{
var camera = GetCamera();
var height = camera.orthographicSize * 2;
var width = height * camera.aspect;
_cameraSize = new Vector2(width, height);
}
return _cameraSize;
}
public static Vector2 GetCameraMin()
{
if (GetCamera() != null)
{
var pos = GetCamera().transform.position;
var size = GetCameraSize();
return new Vector3(pos.x - size.x * 0.5f, pos.y - size.y * 0.5f, pos.z);
}
return Vector2.zero;
}
public static Vector2 GetCameraMax()
{
if (GetCamera() != null)
{
var pos = GetCamera().transform.position;
var size = GetCameraSize();
return new Vector3(pos.x + size.x * 0.5f, pos.y + size.y * 0.5f, pos.z);
}
return Vector2.zero;
}
private static Camera _camera;
public static Camera GetCamera()
{
if ( _camera == null)
{
_camera = GameObject.FindObjectOfType<Camera>();
if (_camera == null)
Debug.LogError("当前场景没有Camera");
}
return _camera;
}

PlayerController

在里面提供判断当前飞机图片是否越过摄像机边界的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void ReceiveW(params object[] args)
{
if(!JudgeUpBorder()) _moveCo.Move(Vector2.up);
}
void ReceiveS(params object[] args)
{
if(!JudgeDownBorder()) _moveCo.Move(Vector2.down);
}
void ReceiveA(params object[] args)
{
if(!JudgeLeftBorder()) _moveCo.Move(Vector2.left);
}
void ReceiveD(params object[] args)
{
if(!JudgeRightBorder()) _moveCo.Move(Vector2.right);
}
bool JudgeUpBorder() => _spriteRenderer.bounds.max.y >= GameUtil.GetCameraMax().y;
bool JudgeDownBorder() => _spriteRenderer.bounds.min.y <= GameUtil.GetCameraMin().y;
bool JudgeLeftBorder() => _spriteRenderer.bounds.min.x <= GameUtil.GetCameraMin().x;
bool JudgeRightBorder() => _spriteRenderer.bounds.max.x >= GameUtil.GetCameraMax().x;

飞机拖动

先给Player的prefab挂载一个Box Collider 2D。注意修改它的大小,这个碰撞体也会作为受击碰撞体,不能太大,覆盖飞机的主体部分即可。

PlayerController

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
using UnityEngine;

public class PlayerController : MonoBehaviour
{
//...
private Vector2 _offset;//飞机中心点到边界的差值
void Start()
{
//...
InitData();
}
private void InitData()
{
_offset = transform.position - _spriteRenderer.bounds.min;
}
//...

private void OnMouseDrag()
{
#if UNITY_EDITOR
Drag(Input.mousePosition);
#else
if (Input.touchCount > 0) Drag(Input.touches[0].position);
#endif
if (JudgeUpBorder())//包括上、左上、右上
{
ResetPosY(GameUtil.GetCameraMax(), Vector2.up);
}
else if (JudgeDownBorder())//包括下、左下、右下
{
ResetPosY(GameUtil.GetCameraMin(), Vector2.down);
}

if (JudgeLeftBorder())//包括左、左上、左下
{
ResetPosX(GameUtil.GetCameraMin(), Vector2.left);
}
else if (JudgeRightBorder())//包括右、右上、右下
{
ResetPosX(GameUtil.GetCameraMax(), Vector2.right);
}
}
private void ResetPosX(Vector2 border, Vector2 direction)
{
var pos = transform.position;
pos.x = border.x - Vector2.Dot(_offset,direction);//向左是负值,正好是加法,向右是正值,正好是减法
transform.position = pos;
}
private void ResetPosY(Vector2 border, Vector2 direction)
{
var pos = transform.position;
pos.y = border.y - Vector2.Dot(_offset, direction);
transform.position = pos;
}
private void Drag(Vector3 screenPos)
{
var pos = Camera.main.ScreenToWorldPoint(screenPos);
pos.z = 0;
transform.localposition = pos;
}
}

修改PlayerController

记录一下另外一个修正Player边界位置的方法

1
2
3
4
5
6
7
8
9
10
private void ResetPos(Vector2 border, Vector2 direction)
{
Vector2 pos = transform.position;
//点乘单位方向向量之后再乘单位方向向量,会得到一个新的向量,这个向量一定是正的,而且另一个维度是0
//减去position需要改变的维度,如果是上下,这里把y减去,保留x;如果是左右,这里把x减去,保留y
pos -= Vector2.Dot(pos, direction) * direction;
//加上修正的值
pos += Vector2.Dot(border, direction) * direction - Vector2.Dot(_offset, direction) * direction;
transform.position = pos;
}