先说明一下,方法比较蠢,打算后面再试试四叉树那些,先说说我目前的思路。
将一个正方形区域想象成一个九宫格,而人物处在中间区域,中间的区域就是摄像机能看到的范围,
摄像机能看到的范围坐标Unity也有自带的API可以调用,就是
//此坐标为摄像机的右上角
Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
//此坐标为摄像机的左上角
Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
//此坐标为摄像机的左下角
Camera.main.ScreenToWorldPoint(new Vector3(0,0, 0));
//此坐标为摄像机的右角
Camera.main.ScreenToWorldPoint(new Vector3(Screen.width,0, 0));
这样就知道了中间区域的四个角的位置,剩下八个区域(九宫格除掉中间区域)都可以根据这四个角进行计算。
先定义一个枚举,表明这八个区域-分别从左往右数
public enum AreaType
{
One = 0,
Two,
Three,
Four,
Five,
Six,
Seven,
eight,
}
再设定一个八个区域内部,就是小各自的左上角和右下角坐标
public struct EnemyCreateArea
{
public Vector2 leftUpV3;
public Vector2 rightDownV3;
}
设置一个距离摄像机多少生成的距离参数,和左上角最大区域,右下角最大区域,也就是整个框的大小
public float distance = 3;
//这两个决定了这个九宫格最大的面积
public Vector2 create_LeftUpPos;
public Vector2 create_RightDownPos;
怪物的生成信息
[System.Serializable]
public struct EnemyCreateMessage
{
//生成的物体
public GameObject enemyObj;
//生成间隔
public float interval;
}
八个区域计算方法,写的很简陋,可以自己重构一下,参数就是引用上面那八个的枚举。因为需要有一个方法先随机从8个区域抽一个。
然后根据switch来判断只计算那个区域的范围,然后返回。
public EnemyCreateArea CalculationArea(AreaType type)
{
switch (type)
{
case AreaType.One:
areas[0].leftUpV3 = create_LeftUpPos;
areas[0].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
break;
case AreaType.Two:
areas[1].leftUpV3.x = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).x;
areas[1].leftUpV3.y = create_LeftUpPos.y;
areas[1].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
break;
case AreaType.Three:
areas[2].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
areas[2].leftUpV3.y = create_LeftUpPos.y;
areas[2].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
areas[2].rightDownV3.x = create_RightDownPos.x;
break;
case AreaType.Four:
areas[3].leftUpV3.x = create_LeftUpPos.x;
areas[3].leftUpV3.y = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).y;
areas[3].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0));
break;
case AreaType.Five:
areas[4].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
areas[4].rightDownV3.x = create_RightDownPos.x;
areas[4].rightDownV3.y = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)).y;
break;
case AreaType.Six:
areas[5].leftUpV3.x = create_LeftUpPos.x;
areas[5].leftUpV3.y = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)).y;
areas[5].rightDownV3.x = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)).x;
areas[5].rightDownV3.y = create_RightDownPos.y;
break;
case AreaType.Seven:
areas[6].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0));
areas[6].rightDownV3.x = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0)).x;
areas[6].rightDownV3.y = create_RightDownPos.y;
break;
case AreaType.eight:
areas[7].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
areas[7].rightDownV3 = create_RightDownPos;
break;
default:
break;
}
return areas[(int)type];
}
下面是生成的协程方法
public IEnumerator IE_Create(EnemyCreateMessage message, float interval)
{
yield return new WaitForSeconds(interval);
//从八个格子随机抽取一个区域
int range_Area = Random.Range(0, 8);
//九宫格的大小先和摄像机能看见的范围一样大
create_LeftUpPos = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
create_RightDownPos= Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
//然后从中间开始进行扩散,扩散出剩下八个格子的大小
create_LeftUpPos.x -= distance;
create_LeftUpPos.y += distance;
create_RightDownPos.x += distance;
create_RightDownPos.y -= distance;
//当前区域=通过上面CalculationArea计算后,返回的最新区域范围。
currentArea =CalculationArea((AreaType)range_Area);
//从当前区域的左上角坐标和右下角坐标,进行x之间,y之间的随机抽取。
float range_PosX = Random.Range(currentArea.leftUpV3.x, currentArea.rightDownV3.x);
float range_PosY = Random.Range(currentArea.leftUpV3.y, currentArea.rightDownV3.y);
//调用对象池(没写的直接用Instantiate)
GameObject enemy = EnemyPool.Instance.GetPoolEnemy(0);
//生成的NPC位置为上面随机出来的数
enemy.transform.position = new Vector2(range_PosX, range_PosY);
//递归,接着下次生成。
StartCoroutine(IE_Create(message, interval));
}
可以理解成下图,这个正方形目前代表着,除了中间摄像机区域不能生成,其他区域都可以生成。
总代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public struct EnemyCreateMessage
{
public GameObject enemyObj;
public float interval;
}
public enum AreaType
{
One = 0,
Two,
Three,
Four,
Five,
Six,
Seven,
eight,
}
public struct EnemyCreateArea
{
public Vector2 leftUpV3;
public Vector2 rightDownV3;
}
//设计思路
//将主角四周分成8个区域,分别扣除最大区域的X和Y的坐标数,上下左右,左上,左下,右上右下,类似一个九宫格,中间则是主角的位置。
public class CreateEnemy : MonoBehaviour
{
public EnemyCreateMessage[] messages;
public EnemyCreateArea[] areas;
public Vector2 create_LeftUpPos;
public Vector2 create_RightDownPos;
private EnemyCreateArea currentArea;
public float distance = 10;
void Start()
{
areas = new EnemyCreateArea[8];
foreach (var item in messages)
{
StartCoroutine(IE_Create(item, item.interval));
}
}
// Update is called once per frame
void Update()
{
}
public IEnumerator IE_Create(EnemyCreateMessage message, float interval)
{
yield return new WaitForSeconds(interval);
int range_Area = Random.Range(0, 8);
create_LeftUpPos = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
create_RightDownPos= Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
create_LeftUpPos.x -= distance;
create_LeftUpPos.y += distance;
create_RightDownPos.x += distance;
create_RightDownPos.y -= distance;
currentArea =CalculationArea((AreaType)range_Area);
float range_PosX = Random.Range(currentArea.leftUpV3.x, currentArea.rightDownV3.x);
float range_PosY = Random.Range(currentArea.leftUpV3.y, currentArea.rightDownV3.y);
GameObject enemy = EnemyPool.Instance.GetPoolEnemy(0);
enemy.transform.position = new Vector2(range_PosX, range_PosY);
StartCoroutine(IE_Create(message, interval));
}
public EnemyCreateArea CalculationArea(AreaType type)
{
switch (type)
{
case AreaType.One:
areas[0].leftUpV3 = create_LeftUpPos;
areas[0].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0));
break;
case AreaType.Two:
areas[1].leftUpV3.x = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).x;
areas[1].leftUpV3.y = create_LeftUpPos.y;
areas[1].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
break;
case AreaType.Three:
areas[2].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
areas[2].leftUpV3.y = create_LeftUpPos.y;
areas[2].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
areas[2].rightDownV3.x = create_RightDownPos.x;
break;
case AreaType.Four:
areas[3].leftUpV3.x = create_LeftUpPos.x;
areas[3].leftUpV3.y = Camera.main.ScreenToWorldPoint(new Vector3(0, Screen.height, 0)).y;
areas[3].rightDownV3 = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0));
break;
case AreaType.Five:
areas[4].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0));
areas[4].rightDownV3.x = create_RightDownPos.x;
areas[4].rightDownV3.y = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)).y;
break;
case AreaType.Six:
areas[5].leftUpV3.x = create_LeftUpPos.x;
areas[5].leftUpV3.y = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)).y;
areas[5].rightDownV3.x = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0)).x;
areas[5].rightDownV3.y = create_RightDownPos.y;
break;
case AreaType.Seven:
areas[6].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(0, 0, 0));
areas[6].rightDownV3.x = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0)).x;
areas[6].rightDownV3.y = create_RightDownPos.y;
break;
case AreaType.eight:
areas[7].leftUpV3 = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, 0, 0));
areas[7].rightDownV3 = create_RightDownPos;
break;
default:
break;
}
return areas[(int)type];
}
}