Unity3d 如何在Unity 3D中创建屏幕敌人指示器?

Unity3d 如何在Unity 3D中创建屏幕敌人指示器?,unity3d,Unity3d,我正在使用下面链接中提到的教程创建一个屏幕敌人指示器。然而,我可以让指示器旋转指向敌人,但指示器不会从屏幕的一端移动到另一端 这是理想的结果: 到目前为止,我已经设法弄明白了下面的问题,请帮助 var screenCenter:Vector3 = new Vector3(0.5, 0.5, 0f); //Note coordinates are translated //Make 00 the centre of the screen instead of bottom l

我正在使用下面链接中提到的教程创建一个屏幕敌人指示器。然而,我可以让指示器旋转指向敌人,但指示器不会从屏幕的一端移动到另一端

这是理想的结果:

到目前为止,我已经设法弄明白了下面的问题,请帮助

var screenCenter:Vector3 = new Vector3(0.5, 0.5, 0f);
    //Note coordinates are translated
    //Make 00 the  centre of the screen instead of bottom left
    screenpos -= screenCenter;

    //find angle from center of screen instead of bototom left
    var angle:float = Mathf.Atan2(screenpos.y, screenpos.x);
    angle -= 90 * Mathf.Deg2Rad;

    var cos:float = Mathf.Cos(angle);
    var sin:float = -Mathf.Cos(angle);

    screenpos = screenCenter + new Vector3(sin*150, cos*150, 0);

    //y=mx + b format
    var m:float = cos/sin;
    var ScreenBounds:Vector3 = screenCenter;// * 0.9f;

    //Check up and down first
    if(cos > 0){
        screenpos = new Vector3(ScreenBounds.y/m, ScreenBounds.y, 0);
    }else{//down
        screenpos = new Vector3(-ScreenBounds.y/m, -ScreenBounds.y, 0);
    }
    //If out of bound then get point on appropriate side
    if(screenpos.x > ScreenBounds.x){//Out of bound must be on right
        screenpos = new Vector3(ScreenBounds.x, ScreenBounds.y*m, 0);
    }else if(screenpos.x < ScreenBounds.x){//Out of bound must be on left
        screenpos = new Vector3(-ScreenBounds.x, -ScreenBounds.y*m, 0);
    }
    //Remove the co ordinate translation
    screenpos += screenCenter;
    var DistanceIndicatorRectT = DistanceIndicator.GetComponent(RectTransform);
    DistanceIndicatorRectT.localPosition = new Vector3(screenpos.x * scrWidth/2, screenpos.y * scrHeight/2, DistanceIndicatorRectT.localPosition.z * screenpos.z);
    DistanceIndicator.transform.rotation = Quaternion.Euler(0, 0, angle*Mathf.Rad2Deg);
var屏幕中心:Vector3=新的Vector3(0.5,0.5,0f);
//注:坐标是平移的
//使00成为屏幕的中心,而不是左下角
screenpos-=屏幕中心;
//从屏幕中心寻找角度,而不是从左侧的肉刀
变量角度:浮动=数学Atan2(屏幕位置y,屏幕位置x);
角度-=90*Mathf.Deg2Rad;
变量cos:float=Mathf.cos(角度);
变量sin:float=-Mathf.Cos(角度);
screenpos=屏幕中心+新矢量3(sin*150,cos*150,0);
//y=mx+b格式
var m:浮动=cos/sin;
变量ScreenBounds:Vector3=屏幕中心;//*0.9f;
//先上下检查
如果(cos>0){
screenpos=新矢量3(ScreenBounds.y/m,ScreenBounds.y,0);
}否则{//down
screenpos=新矢量3(-ScreenBounds.y/m,-ScreenBounds.y,0);
}
//如果超出边界,则在适当的一侧获得点
如果(screenpos.x>ScreenBounds.x){//越界必须在右侧
screenpos=新矢量3(ScreenBounds.x,ScreenBounds.y*m,0);
}else if(screenpos.x
创建一个矩形框碰撞器,划定屏幕边界,并在敌人的方向上使用


碰撞点会告诉你需要在哪里画绿色箭头。

我做了一个与你不同的方法,卡洛斯建议的方法,但没有使用物理

如果“t”是你的目标,这样你就可以得到它在屏幕上的位置,单位是像素(如果它在屏幕外,它只会变成负值或更高的宽度)

这个函数返回一个布尔值,无论矢量3(以像素为单位)是否在屏幕上

bool onScreen(Vector2 input){
    return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}
然后简单计算屏幕中心和目标之间的角度

Vector3 center = new Vector3 (Screen.width / 2f, Screen.height / 2f, 0);
float angle = Mathf.Atan2(targetPosOnScreen.y-center.y, targetPosOnScreen.x-center.x) * Mathf.Rad2Deg;
代码的下一部分根据我们刚刚计算的角度确定将对象与摄影机进行比较的位置

float coef;
if (Screen.width > Screen.height)
    coef = Screen.width / Screen.height;
else
    coef = Screen.height / Screen.width;

float degreeRange = 360f / (coef + 1);

if(angle < 0) angle = angle + 360;
int edgeLine;
if(angle < degreeRange / 4f) edgeLine = 0;
else if (angle < 180 - degreeRange / 4f) edgeLine = 1;
else if (angle < 180 + degreeRange /  4f) edgeLine = 2;
else if (angle < 360 - degreeRange / 4f) edgeLine = 3;
else edgeLine = 0;
下面是函数“intersect”,其代码为:

Vector3 intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2){
    float[] A1 = {-Screen.height, 0, Screen.height, 0};
    float[] B1 = {0, -Screen.width, 0, Screen.width};
    float[] C1 = {-Screen.width * Screen.height,-Screen.width * Screen.height,0, 0};

    float A2 = line2point2.y - line2point1.y;
    float B2 = line2point1.x - line2point2.x;
    float C2 = A2 * line2point1.x + B2 * line2point1.y;

    float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];

    return new Vector3 ((B2 * C1[edgeLine] - B1[edgeLine] * C2) / det, (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det, 0);
}
我们向这个函数发送需要检查与哪个摄像机视图线(矩形)相交的索引,并在屏幕中心和目标位置之间构建一条线

有关此函数的更好解释,请参见此处:

我刚刚修改了A1、B1和C1的值,它们现在都是4的数组,每个值表示一行相机视图(矩形)所需的值

如果要实现边距,只需更改指示器的轴(将实际的精灵渲染器作为子级,并根据需要在局部空间中移动它)


下一件事是对目标数组执行此操作,并将所有这些目标放在给定数组中。希望这有帮助,不要对我太苛刻,这是我第一次在这里发布:)

在上面的示例中,直线矩形的可视角度定义有错误

private void SetIndicatorPosition(Indicator obj)
{

    var target = obj.Target;
    var indicator = obj.PointToTarget;
    if (target == null)
    {

        indicator.SetActive(false);
        return;
    }
    Vector3 targetPosOnScreen = cam.WorldToScreenPoint(target.transform.position);
    if (onScreen(targetPosOnScreen))
    {
        indicator.SetActive(false);
        return;
    }
    indicator.SetActive(true);
    Vector3 center = new Vector3(Screen.width / 2f, Screen.height / 2f, 0);
    float angle = Mathf.Atan2(targetPosOnScreen.y - center.y, targetPosOnScreen.x - center.x) * Mathf.Rad2Deg;
    float scale;
    if (Screen.width > Screen.height)
        scale = Screen.width / Screen.height;
    else
        scale = Screen.height / Screen.width;

    float degreeRange = 360f / (scale + 1);
    float angle2 = Mathf.Atan2(Screen.height - center.y, Screen.width - center.x) * Mathf.Rad2Deg;

    if (angle < 0) angle = angle + 360;
    int edgeLine;
    if (angle < angle2) edgeLine = 0;
    else if (angle < 180 - angle2) edgeLine = 1;
    else if (angle < 180 + angle2) edgeLine = 2;
    else if (angle < 360 - angle2) edgeLine = 3;
    else edgeLine = 0;

    indicator.transform.position = Camera.main.ScreenToWorldPoint(Intersect(edgeLine, center, targetPosOnScreen));
    indicator.transform.eulerAngles = new Vector3(0, 0, angle);
}

Vector3 Intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2)
{
    float[] A1 = { -Screen.height, 0, Screen.height, 0 };
    float[] B1 = { 0, -Screen.width, 0, Screen.width };
    float[] C1 = { -Screen.width * Screen.height, -Screen.width * Screen.height, 0, 0 };

    float A2 = line2point2.y - line2point1.y;
    float B2 = line2point1.x - line2point2.x;

    float C2 = A2 * line2point1.x + B2 * line2point1.y;

    float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];
    var x = (B2 * C1[edgeLine] - B1[edgeLine] * C2) / det;
    var y = (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det;
    return new Vector3(x, y, 0);

}

bool onScreen(Vector2 input)
{
    return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}

public class Indicator
{
    public GameObject Target { get; private set; }
    public GameObject PointToTarget { get; private set; }

    public Indicator(GameObject target, GameObject pointToTarget, ObjectTypeEnum type)
    {
        Target = target;
        PointToTarget = pointToTarget;
        var texture = pointToTarget.GetComponentInChildren<UITexture>();
        if (texture != null)
        {
            texture.color = Helper.GetHintColor(type);
        }

    }
}

你能解释一下你的问题吗?你现在所拥有的只是“我希望这个行为与这个代码”。究竟什么是失败?您期望的输出和获得的输出有什么区别?@DJ IV DJIV:您在哪里添加了上述代码?Update()?谢谢,这是我的工作。但是有一个小错误。当targetPosOnScreen.z<0时,所有内容都会翻转。因此,添加以下内容:
t2.position = Camera.main.ScreenToWorldPoint(intersect(edgeLine, center, targetPosOnScreen)+new Vector3(0,0,10));
t2.eulerAngles = new Vector3 (0, 0, angle);
Vector3 intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2){
    float[] A1 = {-Screen.height, 0, Screen.height, 0};
    float[] B1 = {0, -Screen.width, 0, Screen.width};
    float[] C1 = {-Screen.width * Screen.height,-Screen.width * Screen.height,0, 0};

    float A2 = line2point2.y - line2point1.y;
    float B2 = line2point1.x - line2point2.x;
    float C2 = A2 * line2point1.x + B2 * line2point1.y;

    float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];

    return new Vector3 ((B2 * C1[edgeLine] - B1[edgeLine] * C2) / det, (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det, 0);
}
private void SetIndicatorPosition(Indicator obj)
{

    var target = obj.Target;
    var indicator = obj.PointToTarget;
    if (target == null)
    {

        indicator.SetActive(false);
        return;
    }
    Vector3 targetPosOnScreen = cam.WorldToScreenPoint(target.transform.position);
    if (onScreen(targetPosOnScreen))
    {
        indicator.SetActive(false);
        return;
    }
    indicator.SetActive(true);
    Vector3 center = new Vector3(Screen.width / 2f, Screen.height / 2f, 0);
    float angle = Mathf.Atan2(targetPosOnScreen.y - center.y, targetPosOnScreen.x - center.x) * Mathf.Rad2Deg;
    float scale;
    if (Screen.width > Screen.height)
        scale = Screen.width / Screen.height;
    else
        scale = Screen.height / Screen.width;

    float degreeRange = 360f / (scale + 1);
    float angle2 = Mathf.Atan2(Screen.height - center.y, Screen.width - center.x) * Mathf.Rad2Deg;

    if (angle < 0) angle = angle + 360;
    int edgeLine;
    if (angle < angle2) edgeLine = 0;
    else if (angle < 180 - angle2) edgeLine = 1;
    else if (angle < 180 + angle2) edgeLine = 2;
    else if (angle < 360 - angle2) edgeLine = 3;
    else edgeLine = 0;

    indicator.transform.position = Camera.main.ScreenToWorldPoint(Intersect(edgeLine, center, targetPosOnScreen));
    indicator.transform.eulerAngles = new Vector3(0, 0, angle);
}

Vector3 Intersect(int edgeLine, Vector3 line2point1, Vector3 line2point2)
{
    float[] A1 = { -Screen.height, 0, Screen.height, 0 };
    float[] B1 = { 0, -Screen.width, 0, Screen.width };
    float[] C1 = { -Screen.width * Screen.height, -Screen.width * Screen.height, 0, 0 };

    float A2 = line2point2.y - line2point1.y;
    float B2 = line2point1.x - line2point2.x;

    float C2 = A2 * line2point1.x + B2 * line2point1.y;

    float det = A1[edgeLine] * B2 - A2 * B1[edgeLine];
    var x = (B2 * C1[edgeLine] - B1[edgeLine] * C2) / det;
    var y = (A1[edgeLine] * C2 - A2 * C1[edgeLine]) / det;
    return new Vector3(x, y, 0);

}

bool onScreen(Vector2 input)
{
    return !(input.x > Screen.width || input.x < 0 || input.y > Screen.height || input.y < 0);
}

public class Indicator
{
    public GameObject Target { get; private set; }
    public GameObject PointToTarget { get; private set; }

    public Indicator(GameObject target, GameObject pointToTarget, ObjectTypeEnum type)
    {
        Target = target;
        PointToTarget = pointToTarget;
        var texture = pointToTarget.GetComponentInChildren<UITexture>();
        if (texture != null)
        {
            texture.color = Helper.GetHintColor(type);
        }

    }
}
foreach (var obj in listIndicator)
        {
            SetIndicatorPosition(obj);
        }