需求
以屏幕的宽高为参考,在合适的位置生成上下左右四面墙壁。
实现效果
区域大小为整屏的50%.png区域大小等于屏幕大小.png
核心
获取屏幕对应到场景中的区域:区域用左下角和右上角的坐标表示。
var screenMinPos = Vector3.zero;
var screenMaxPos = new Vector3(Screen.width, Screen.height, 0);
var minPos = Camera.main.ScreenToWorldPoint(screenMinPos);
var maxPos = Camera.main.ScreenToWorldPoint(screenMaxPos);
根据配置的比例(如希望墙围成的区域的Width是屏幕宽度的80%),调整区域(左下和右上坐标位置),得到实际的墙围成的区域:Area
四面墙的位置、宽度、朝向
- 上:(区域中心x,区域右上y),区域宽度+1(为了让边界接触处齐整,因此让上下墙稍宽一些),朝下
- 下:(区域中心x,区域左下y),区域宽度+1,朝上
- 左:(区域左下x,区域中心y),区域高度,朝右
- 右:(区域右上x,区域中心y),区域高度,朝左
流程
1.制作墙预制体:以right(红轴)为墙的朝向。
Wall.prefab.png
代码
Wall.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Wall : MonoBehaviour
{
public Vector3 Dir
{
get { return transform.right; }
private set { transform.right = value; }
}
public void Init(Vector3 pos, Vector3 dir, float width, string name)
{
transform.position = pos;
Dir = dir;
SetWidth(width);
gameObject.name = name;
void SetWidth(float width)
{
transform.localScale = new Vector3(1, width, 1);
}
}
public void MyDestroy()
{
}
// 物体碰到墙时,要反弹。通过这个方法获取反弹后从朝向。
public Vector3 GetReflectVec(Vector3 incidenceVec)
{
return Vector3.Reflect(incidenceVec, Dir);
}
}
WallSys.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallSys
{
private Wall _wallTemplate;
private Wall[] _walls;
private Transform _wallRoot;
public WallSys(Vector2 areaRatio, Wall wallTemplate)
{
var area = InitAreaInfo();
InitWalls(area);
Area InitAreaInfo()
{
var screenMinPos = Vector3.zero;
var screenMaxPos = new Vector3(Screen.width, Screen.height, 0);
var minPos = Camera.main.ScreenToWorldPoint(screenMinPos);
var maxPos = Camera.main.ScreenToWorldPoint(screenMaxPos);
var center = Area.GetCenterPos(minPos, maxPos);
var offset = new Vector2(Area.GetWidth(minPos, maxPos) * areaRatio.x, Area.GetHeight(minPos, maxPos) * areaRatio.y) / 2;
minPos = center - offset;
maxPos = center + offset;
return new Area()
{
MinPos = minPos,
MaxPos = maxPos
};
}
void InitWalls(Area area)
{
_wallTemplate = wallTemplate;
_wallRoot = new GameObject("Walls").transform;
var upWallPos = new Vector3(area.CenterPos.x, area.MaxPos.y, 0);
var upWallDir = Vector3.down;
var downWallPos = new Vector3(area.CenterPos.x, area.MinPos.y, 0);
var downWallDir = Vector3.up;
var leftWallPos = new Vector3(area.MinPos.x, area.CenterPos.y, 0);
var leftWallDir = Vector3.right;
var rightWallPos = new Vector3(area.MaxPos.x, area.CenterPos.y, 0);
var rightWallDir = Vector3.left;
_walls = new Wall[]
{
CreateWall(upWallPos, upWallDir, area.Width+1, $"{nameof(Wall)}_Up"),
CreateWall(downWallPos, downWallDir, area.Width+1, $"{nameof(Wall)}_Down"),
CreateWall(leftWallPos, leftWallDir, area.Height, $"{nameof(Wall)}_Left"),
CreateWall(rightWallPos, rightWallDir, area.Height, $"{nameof(Wall)}_Right"),
};
}
Wall CreateWall(Vector3 pos, Vector3 dir, float width, string name)
{
var wall = GOPool.Instance.GetInstance(_wallTemplate.gameObject).GetComponent<Wall>();
wall.Init(pos, dir, width, name);
wall.transform.SetParent(_wallRoot);
return wall;
}
}
public void MyDestroy()
{
DestroyWalls();
void DestroyWalls()
{
if (_wallRoot != null)
{
for (int i = 0; i < _walls.Length; i++)
{
_walls[i].MyDestroy();
GOPool.Instance.RecycleInstance(_wallTemplate.gameObject, _walls[i].gameObject);
}
_walls = null;
GameObject.Destroy(_wallRoot.gameObject);
_wallRoot = null;
}
_wallTemplate = null;
}
}
}
public class Area
{
public Vector2 MinPos;
public Vector2 MaxPos;
public float Width { get { return GetWidth(MinPos, MaxPos); } }
public float Height { get { return GetHeight(MinPos, MaxPos); } }
public Vector2 CenterPos
{
get { return GetCenterPos(MinPos, MaxPos); }
}
public Vector2 RandomPos
{
get
{
return new Vector2(UnityEngine.Random.Range(MinPos.x, MaxPos.x),
UnityEngine.Random.Range(MinPos.y, MaxPos.y));
}
}
public static Vector2 GetCenterPos(Vector2 min, Vector2 max)
{
return (min + max) / 2;
}
public static float GetWidth(Vector2 min, Vector2 max)
{
return max.x - min.x;
}
public static float GetHeight(Vector2 min, Vector2 max)
{
return max.y - min.y;
}
}
WallTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WallTest : MonoBehaviour
{
[SerializeField]
private Vector2 _wallAreaRatio;
[SerializeField]
private Wall _wallTemplate;
private WallSys _wallSys;
private void Start()
{
Init();
}
private void Update()
{
MyUpdate();
}
private void OnDestroy()
{
MyDestroy();
}
private void Init()
{
_wallSys = new WallSys(_wallAreaRatio, _wallTemplate);
}
private void MyUpdate()
{
}
private void MyDestroy()
{
_wallSys.MyDestroy();
_wallSys = null;
}
}
网友评论