美文网首页
Unity中,生成2D边界(上下左右)

Unity中,生成2D边界(上下左右)

作者: 全新的饭 | 来源:发表于2023-11-13 11:04 被阅读0次

需求

以屏幕的宽高为参考,在合适的位置生成上下左右四面墙壁。

实现效果

区域大小为整屏的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

四面墙的位置、宽度、朝向

  1. 上:(区域中心x,区域右上y),区域宽度+1(为了让边界接触处齐整,因此让上下墙稍宽一些),朝下
  2. 下:(区域中心x,区域左下y),区域宽度+1,朝上
  3. 左:(区域左下x,区域中心y),区域高度,朝右
  4. 右:(区域右上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;
    }
}

相关文章

网友评论

      本文标题:Unity中,生成2D边界(上下左右)

      本文链接:https://www.haomeiwen.com/subject/mgxdwdtx.html